diff options
Diffstat (limited to 'doc/rtd/tutorial/qemu.rst')
-rw-r--r-- | doc/rtd/tutorial/qemu.rst | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/doc/rtd/tutorial/qemu.rst b/doc/rtd/tutorial/qemu.rst new file mode 100644 index 00000000..4370051a --- /dev/null +++ b/doc/rtd/tutorial/qemu.rst @@ -0,0 +1,292 @@ +.. _tutorial_qemu: + +Core tutorial with QEMU +*********************** + +.. toctree:: + :titlesonly: + :hidden: + + qemu-debugging.rst + +In this tutorial, we will launch an Ubuntu cloud image in a virtual machine +that uses ``cloud-init`` to pre-configure the system during boot. + +The goal of this tutorial is to provide a minimal demonstration of +``cloud-init``, which you can then use as a development environment to test +your ``cloud-init`` configurations locally before launching to the cloud. + +Why QEMU? +========= + +`QEMU`_ is a cross-platform emulator capable of running performant virtual +machines. QEMU is used at the core of a broad range of production operating +system deployments and open source software projects (including libvirt, LXD, +and vagrant) and is capable of running Windows, Linux, and Unix guest operating +systems. While QEMU is flexibile and feature-rich, we are using it because of +the broad support it has due to its broad adoption and ability to run on +\*nix-derived operating systems. + +How to use this tutorial +======================== + +In this tutorial, the commands in each code block can be copied and pasted +directly into the terminal. Omit the prompt (``$``) before each command, or +use the "copy code" button on the right-hand side of the block, which will copy +the command for you without the prompt. + +Each code block is preceded by a description of what the command does, and +followed by an example of the type of output you should expect to see. + +Install QEMU +============ + +.. code-block:: sh + + $ sudo apt install qemu-system-x86 + +If you are not using Ubuntu, you can visit QEMU's `install instructions`_ for +additional information. + +Create a temporary directory +============================ + +This directory will store our cloud image and configuration files for +:ref:`user data<user_data_formats>`, :ref:`metadata<instance_metadata>`, and +:ref:`vendor data<vendordata>`. + +You should run all commands from this temporary directory. If you run the +commands from anywhere else, your virtual machine will not be configured. + +Let's create a temporary directory and make it our current working directory +with :command:`cd`: + +.. code-block:: sh + + $ mkdir temp + $ cd temp + +Download a cloud image +====================== + +Cloud images typically come with ``cloud-init`` pre-installed and configured to +run on first boot. You will not need to worry about installing ``cloud-init`` +for now, since we are not manually creating our own image in this tutorial. + +In our case, we want to select the latest Ubuntu LTS_. Let's download the +server image using :command:`wget`: + +.. code-block:: sh + + $ wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img + +Define our user data +==================== + +Now we need to create our :file:`user-data` file. This user data cloud-config +sets the password of the default user, and sets that password to never expire. +For more details you can refer to the +:ref:`Set Passwords module page<mod-set_passwords>`. + +Run the following command, which creates a file named :file:`user-data` +containing our configuration data. + +.. code-block:: sh + + $ cat << EOF > user-data + #cloud-config + password: password + chpasswd: + expire: False + + EOF + +What is user data? +================== + +Before moving forward, let's inspect our :file:`user-data` file. + +.. code-block:: sh + + $ cat user-data + +You should see the following contents: + +.. code-block:: yaml + + #cloud-config + password: password + chpasswd: + expire: False + +The first line starts with ``#cloud-config``, which tells ``cloud-init`` +what type of user data is in the config. Cloud-config is a YAML-based +configuration type that tells ``cloud-init`` how to configure the virtual +machine instance. Multiple different format types are supported by +``cloud-init``. For more information, see the +:ref:`documentation describing different formats<user_data_formats>`. + +The second line, ``password: password``, as per +:ref:`the Users and Groups module docs<mod-users_groups>`, sets the default +user's password to ``password``. + +The third and fourth lines direct ``cloud-init`` to not require a password +reset on first login. + +Define our metadata +=================== + +Now let's run the following command, which creates a file named +:file:`meta-data` containing configuration data. + +.. code-block:: sh + + $ cat << EOF > meta-data + instance-id: someid/somehostname + local-hostname: jammy + + EOF + +Define our vendor data +====================== + +Now we will create the empty file :file:`vendor-data` in our temporary +directory. This will speed up the retry wait time. + +.. code-block:: sh + + $ touch vendor-data + + +Start an ad hoc IMDS webserver +============================== + +Open up a second terminal window, change to your temporary directory and then +start the built-in Python webserver: + +.. code-block:: sh + + $ cd temp + $ python3 -m http.server --directory . + +What is an IMDS? +---------------- + +Instance Metadata Service (IMDS) is a service provided by most cloud providers +as a means of providing information to virtual machine instances. This service +is used by cloud providers to expose information to a virtual machine. This +service is used for many different things, and is the primary mechanism for +some clouds to expose ``cloud-init`` configuration data to the instance. + +How does ``cloud-init`` use the IMDS? +------------------------------------- + +The IMDS uses a private http webserver to provide metadata to each operating +system instance. During early boot, ``cloud-init`` sets up network access and +queries this webserver to gather configuration data. This allows ``cloud-init`` +to configure your operating system while it boots. + +In this tutorial we are emulating this workflow using QEMU and a simple Python +webserver. This workflow is suitable for developing and testing +``cloud-init`` configurations prior to cloud deployments. + +Launch a virtual machine with our user data +=========================================== + +Switch back to your original terminal, and run the following command so we can +launch our virtual machine. By default, QEMU will print the kernel logs and +``systemd`` logs to the terminal while the operating system boots. This may +take a few moments to complete. + +.. code-block:: sh + + $ qemu-system-x86_64 \ + -net nic \ + -net user \ + -machine accel=kvm:tcg \ + -cpu host \ + -m 512 \ + -nographic \ + -hda jammy-server-cloudimg-amd64.img \ + -smbios type=1,serial=ds='nocloud-net;s=http://10.0.2.2:8000/' + +.. note:: + If the output stopped scrolling but you don't see a prompt yet, press + :kbd:`Enter` to get to the login prompt. + +How is QEMU configured for ``cloud-init``? +------------------------------------------ + +When launching QEMU, our machine configuration is specified on the command +line. Many things may be configured: memory size, graphical output, networking +information, hard drives and more. + +Let us examine the final two lines of our previous command. The first of them, +:command:`-hda jammy-server-cloudimg-amd64.img`, tells QEMU to use the cloud +image as a virtual hard drive. This will cause the virtual machine to +boot Ubuntu, which already has ``cloud-init`` installed. + +The second line tells ``cloud-init`` where it can find user data, using the +:ref:`NoCloud datasource<datasource_nocloud>`. During boot, ``cloud-init`` +checks the ``SMBIOS`` serial number for ``ds=nocloud-net``. If found, +``cloud-init`` will use the specified URL to source its user data config files. + +In this case, we use the default gateway of the virtual machine (``10.0.2.2``) +and default port number of the Python webserver (``8000``), so that +``cloud-init`` will, inside the virtual machine, query the server running on +host. + +Verify that ``cloud-init`` ran successfully +=========================================== + +After launching the virtual machine, we should be able to connect to our +instance using the default distro username. + +In this case the default username is ``ubuntu`` and the password we configured +is ``password``. + +If you can log in using the configured password, it worked! + +If you couldn't log in, see +:ref:`this page for debug information<qemu_debug_info>`. + +Check ``cloud-init`` status +=========================== + +Run the following command, which will allow us to check if ``cloud-init`` has +finished running: + +.. code-block:: sh + + $ cloud-init status --wait + +If you see ``status: done`` in the output, it succeeded! + +If you see a failed status, you'll want to check +:file:`/var/log/cloud-init.log` for warning/error messages. + +Tear down +========= + +In our main terminal, let's exit the QEMU shell using :kbd:`ctrl-a x` (that's +:kbd:`ctrl` and :kbd:`a` simultaneously, followed by :kbd:`x`). + +In the second terminal, where the Python webserver is running, we can stop the +server using (:kbd:`ctrl-c`). + +What's next? +============ + +In this tutorial, we configured the default user's password and ran +``cloud-init`` inside our QEMU virtual machine. + +The full list of modules available can be found in +:ref:`our modules documentation<modules>`. +The documentation for each module contains examples of how to use it. + +You can also head over to the :ref:`examples page<yaml_examples>` for +examples of more common use cases. + +.. _QEMU: https://www.qemu.org +.. _install instructions: https://www.qemu.org/download/#linux +.. _LTS: https://wiki.ubuntu.com/Releases |