diff --git a/doc/rtd/development/style_docs.rst b/doc/rtd/development/style_docs.rst index ea73b815559..0d59aa60d75 100644 --- a/doc/rtd/development/style_docs.rst +++ b/doc/rtd/development/style_docs.rst @@ -90,9 +90,9 @@ to text output, you can use code blocks. For diagrams, we recommend the use of Code blocks ----------- -Our documentation uses the Sphinx extension "sphinx-copybutton", which creates -a small button on the right-hand side of code blocks for users to copy the -code snippets we provide. +Our documentation uses the Sphinx extension ``sphinx-copybutton``, which +creates a small button on the right-hand side of code blocks for users to copy +the code snippets we provide. The copied code will strip out the prompt symbol (``$``) so that users can paste commands directly into their terminal. For user convenience, please diff --git a/doc/rtd/howto/index.rst b/doc/rtd/howto/index.rst index b6811fa3133..826f922d989 100644 --- a/doc/rtd/howto/index.rst +++ b/doc/rtd/howto/index.rst @@ -18,7 +18,7 @@ How do I...? .. toctree:: :maxdepth: 1 - Run cloud-init locally before deploying + Launch cloud-init with... Re-run cloud-init Change how often a module runs Validate my user data diff --git a/doc/rtd/howto/launch_libvirt.rst b/doc/rtd/howto/launch_libvirt.rst new file mode 100644 index 00000000000..3b481ed267f --- /dev/null +++ b/doc/rtd/howto/launch_libvirt.rst @@ -0,0 +1,30 @@ +.. _launch_libvirt: + +Run cloud-init locally with libvirt +*********************************** + +`Libvirt`_ is a tool for managing virtual machines and containers. + +Create your configuration +------------------------- + +.. include:: shared/create_config.txt + +Download a cloud image +---------------------- + +.. include:: shared/download_image.txt + +Create an instance +------------------ + +.. code-block:: shell-session + + virt-install --name cloud-init-001 --memory 4000 --noreboot \ + --os-variant detect=on,name=ubuntujammy \ + --disk=size=10,backing_store="$(pwd)/jammy-server-cloudimg-amd64.img" \ + --cloud-init user-data="$(pwd)/user-data,meta-data=$(pwd)/meta-data,network-config=$(pwd)/network-config" + +.. LINKS +.. _Libvirt: https://libvirt.org/ + diff --git a/doc/rtd/howto/launch_lxd.rst b/doc/rtd/howto/launch_lxd.rst new file mode 100644 index 00000000000..c0d50f293c1 --- /dev/null +++ b/doc/rtd/howto/launch_lxd.rst @@ -0,0 +1,75 @@ +.. _launch_lxd: + +Run cloud-init locally with LXD +******************************** + +`LXD`_ offers a streamlined user experience for using Linux system containers. + +Create your configuration +------------------------- + +In this example we will create a file called ``user-data.yaml`` containing +a basic cloud-init configuration: + +.. code-block:: shell-session + + $ cat >user-data.yaml <` about the *user data +cloud-config* format. + +Create your configuration +------------------------- + +.. include:: shared/create_config.txt + +Launch your instance +-------------------- + +You can pass the ``user-data`` file to Multipass and launch a Bionic instance +named ``test-vm`` with the following command: + +.. code-block:: shell-session + + $ multipass launch bionic --name test-vm --cloud-init user-data + +Multipass will validate the ``user-data`` configuration file before starting +the VM. This breaks all cloud-init configuration formats except the *user data +cloud-config*. + +.. LINKS +.. _Multipass: https://multipass.run/ + diff --git a/doc/rtd/howto/launch_qemu.rst b/doc/rtd/howto/launch_qemu.rst new file mode 100644 index 00000000000..80ef283983a --- /dev/null +++ b/doc/rtd/howto/launch_qemu.rst @@ -0,0 +1,66 @@ +.. _launch_qemu: + +Run cloud-init locally with QEMU +******************************** + +`QEMU`_ is a general purpose computer hardware emulator, able to run virtual +machines with hardware acceleration, and to emulate the instruction sets of +different architectures than the host you are running on. + +The ``NoCloud`` datasource allows you to provide your own user data, +metadata, or network configuration directly to an instance without running a +network service. This is helpful for launching local cloud images with QEMU. + +Create your configuration +------------------------- + +.. include:: shared/create_config.txt + +Create an ISO disk +------------------ + +This disk is used to pass the configuration files to cloud-init. Create it with +the ``genisoimage`` command: + +.. code-block:: shell-session + + genisoimage \ + -output seed.img \ + -volid cidata -rational-rock -joliet \ + user-data meta-data network-config + +Download a cloud image +---------------------- + +.. include:: shared/download_image.txt + +.. note:: + This example uses emulated CPU instructions on non-x86 hosts, so it may be + slow. To make it faster on non-x86 architectures, one can change the image + type and ``qemu-system-`` command name to match the + architecture of your host machine. + +Boot the image with the ISO attached +------------------------------------ + +Boot the cloud image with our configuration, ``seed.img``, to QEMU: + +.. code-block:: shell-session + + $ qemu-system-x86_64 -m 1024 -net nic -net user \ + -drive file=jammy-server-cloudimg-amd64.img,index=0,format=qcow2,media=disk \ + -drive file=seed.img,index=1,media=cdrom \ + -machine accel=kvm:tcg + +The now-booted image will allow for login using the password provided above. + +For additional configuration, you can provide much more detailed +configuration in the empty :file:`network-config` and :file:`meta-data` files. + +.. note:: + See the :ref:`network_config_v2` page for details on the format and config + of network configuration. To learn more about the possible values for + metadata, check out the :ref:`datasource_nocloud` page. + +.. LINKS +.. _QEMU: https://www.qemu.org/ diff --git a/doc/rtd/tutorial/wsl.rst b/doc/rtd/howto/launch_wsl.rst similarity index 88% rename from doc/rtd/tutorial/wsl.rst rename to doc/rtd/howto/launch_wsl.rst index d1bb218010b..1d7ef07df93 100644 --- a/doc/rtd/tutorial/wsl.rst +++ b/doc/rtd/howto/launch_wsl.rst @@ -1,26 +1,18 @@ -.. _tutorial_wsl: +.. _launch_wsl: -WSL Tutorial -************ +Using WSL with cloud-init +************************* -In this tutorial, we will customize a Windows Subsystem for Linux (WSL) +In this guide, we will customize a `Windows Subsystem for Linux`_ (WSL) instance using cloud-init on Ubuntu. -How to use this tutorial -======================== - -In this tutorial, the commands in each code block can be copied and pasted -directly into a ``PowerShell`` Window . 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. - Prerequisites ============= -This tutorial assumes you are running within a ``Windows 11`` or ``Windows +This guide assumes you are running within a ``Windows 11`` or ``Windows Server 2022`` environment. If ``wsl`` is already installed, you must be running version 2. You can check your version of ``wsl`` by running the -following command: +following command in your terminal: .. code-block:: doscon @@ -38,9 +30,8 @@ Example output: DXCore version: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp Windows version: 10.0.20348.2402 -If running this tutorial within a virtualized -environment (`including in the cloud`_), ensure that -`nested virtualization`_ is enabled. +If you follow this guide while using a virtualized environment +(`including in the cloud`_), ensure that `nested virtualization`_ is enabled. Install WSL =========== @@ -66,8 +57,8 @@ Example output: Reboot the system when prompted. -Create our user data -==================== +Create some user data +===================== User data is the primary way for a user to customize a cloud-init instance. Open Notepad and paste the following: @@ -91,7 +82,7 @@ not as a ``.txt`` file. .. note:: We are creating user data that is tied to the instance we just created, but by changing the filename, we can create user data that applies to - multiple or all WSL instances. See + multiple (or all) WSL instances. See :ref:`WSL Datasource reference page` for more information. @@ -167,7 +158,7 @@ Download the Ubuntu 24.04 WSL image. PS> Invoke-WebRequest -Uri https://cloud-images.ubuntu.com/wsl/noble/current/ubuntu-noble-wsl-amd64-wsl.rootfs.tar.gz -OutFile wsl-images\ubuntu-noble-wsl-amd64-wsl.rootfs.tar.gz -Import the image into WSL storing it in the ``wsl-images`` directory. +Import the image into WSL, storing it in the ``wsl-images`` directory. .. code-block:: doscon @@ -186,8 +177,8 @@ Start the Ubuntu WSL instance PS> wsl --distribution Ubuntu-24.04 -Setup the Ubuntu WSL instance -============================= +Set up the Ubuntu WSL instance +============================== The Ubuntu WSL instance will start, and you may be prompted for a username and password. @@ -224,7 +215,7 @@ screen similar to the following: /root/.hushlogin file. root@machine:/mnt/c/Users/me# -You should now be in a shell inside the WSL instance. +This indicates you are now in a shell inside the WSL instance. Verify that ``cloud-init`` ran successfully ------------------------------------------- @@ -305,7 +296,7 @@ successfully! What's next? ============ -In this tutorial, we used the :ref:`Write Files module ` to +In this guide, we used the :ref:`Write Files module ` to write a file to our WSL instance. The full list of modules available can be found in our :ref:`modules documentation`. Each module contains examples of how to use it. @@ -316,7 +307,7 @@ examples of more common use cases. Cloud-init's WSL reference documentation can be found on the :ref:`WSL Datasource reference page`. - +.. _Windows Subsystem for Linux: https://learn.microsoft.com/en-us/windows/wsl/ .. _including in the cloud: https://techcommunity.microsoft.com/t5/itops-talk-blog/how-to-setup-nested-virtualization-for-azure-vm-vhd/ba-p/1115338 .. _nested virtualization: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/nested-virtualization .. _Ubuntu 24.04: https://apps.microsoft.com/detail/9nz3klhxdjp5 diff --git a/doc/rtd/howto/launching.rst b/doc/rtd/howto/launching.rst new file mode 100644 index 00000000000..bb339321546 --- /dev/null +++ b/doc/rtd/howto/launching.rst @@ -0,0 +1,34 @@ +.. _launching: + +Launch a local instance with cloud-init +*************************************** + +It’s very likely that you will want to test your cloud-init configuration +locally before deploying it to the cloud. + +Fortunately, there are several different virtual machine (VM) and container +tools ideal for this sort of local testing. + +Due to differences across platforms, initializing and launching instances with +cloud-init can vary. Here we present instructions for various platforms, or +links to instructions where platforms have provided their preferred methods for +using cloud-init. + +* :ref:`Launch with QEMU ` +* :ref:`Launch with LXD ` +* :ref:`Launch with Multipass ` +* :ref:`Launch with libvirt ` +* :ref:`Launch with WSL ` + + In this guide you will use a cloud-init user data script to customize a WSL + instance. + +.. toctree:: + :maxdepth: 2 + :hidden: + + QEMU + LXD + Multipass + Libvirt + WSL diff --git a/doc/rtd/howto/run_cloud_init_locally.rst b/doc/rtd/howto/run_cloud_init_locally.rst deleted file mode 100644 index 2510eadd067..00000000000 --- a/doc/rtd/howto/run_cloud_init_locally.rst +++ /dev/null @@ -1,224 +0,0 @@ -.. _run_cloud_init_locally: - -How to run ``cloud-init`` locally -********************************* - -It's very likely that you will want to test ``cloud-init`` locally before -deploying it to the cloud. Fortunately, there are several different virtual -machine (VM) and container tools that are ideal for this sort of local -testing. - -* :ref:`boot cloud-init with QEMU ` -* :ref:`boot cloud-init with LXD ` -* :ref:`boot cloud-init with Libvirt ` -* :ref:`boot cloud-init with Multipass ` - -.. _run_with_qemu: - -QEMU -==== - -`QEMU`_ is a general purpose computer hardware emulator that is capable of -running virtual machines with hardware acceleration as well as emulating the -instruction sets of different architectures than the host that you are -running on. - -The ``NoCloud`` datasource allows users to provide their own user data, -metadata, or network configuration directly to an instance without running a -network service. This is helpful for launching local cloud images with QEMU. - -Create your configuration -------------------------- - -We will leave the :file:`network-config` and :file:`meta-data` files empty, but -populate :file:`user-data` with a cloud-init configuration. You may edit the -:file:`network-config` and :file:`meta-data` files if you have a config to -provide. - -.. code-block:: shell-session - - $ touch network-config - $ touch meta-data - $ cat >user-data <` command name to match the - architecture of your host machine. - -Boot the image with the ISO attached ------------------------------------- - -Boot the cloud image with our configuration, :file:`seed.img`, to QEMU: - -.. code-block:: shell-session - - $ qemu-system-x86_64 -m 1024 -net nic -net user \ - -drive file=jammy-server-cloudimg-amd64.img,index=0,format=qcow2,media=disk \ - -drive file=seed.img,index=1,media=cdrom \ - -machine accel=kvm:tcg - -The now-booted image will allow for login using the password provided above. - -For additional configuration, users can provide much more detailed -configuration in the empty :file:`network-config` and :file:`meta-data` files. - -.. note:: - - See the :ref:`network_config_v2` page for details on the format and config - of network configuration. To learn more about the possible values for - metadata, check out the :ref:`datasource_nocloud` page. - -.. _run_with_lxd: - -LXD -=== - -`LXD`_ offers a streamlined user experience for using Linux system containers. -With LXD, the following command initialises a container with user data: - -.. code-block:: shell-session - - $ lxc init ubuntu-daily:jammy test-container - $ lxc config set test-container user.user-data - < userdata.yaml - $ lxc start test-container - -To avoid the extra commands this can also be done at launch: - -.. code-block:: shell-session - - $ lxc launch ubuntu-daily:jammy test-container --config=user.user-data="$(cat userdata.yaml)" - -Finally, a profile can be set up with the specific data if you need to -launch this multiple times: - -.. code-block:: shell-session - - $ lxc profile create dev-user-data - $ lxc profile set dev-user-data user.user-data - < cloud-init-config.yaml - $ lxc launch ubuntu-daily:jammy test-container -p default -p dev-user-data - -LXD configuration types ------------------------ - -The above examples all show how to pass user data. To pass other types of -configuration data use the configuration options specified below: - -+----------------+---------------------------+ -| Data | Configuration option | -+================+===========================+ -| user data | cloud-init.user-data | -+----------------+---------------------------+ -| vendor data | cloud-init.vendor-data | -+----------------+---------------------------+ -| network config | cloud-init.network-config | -+----------------+---------------------------+ - -See the LXD `Instance Configuration`_ docs for more info about configuration -values or the LXD `Custom Network Configuration`_ document for more about -custom network config. - -.. _run_with_libvirt: - -Libvirt -======= - -`Libvirt`_ is a tool for managing virtual machines and containers. - -Create your configuration -------------------------- - -We will leave the :file:`network-config` and :file:`meta-data` files empty, but -populate user-data with a cloud-init configuration. You may edit the -:file:`network-config` and :file:`meta-data` files if you have a config to -provide. - -.. code-block:: shell-session - - $ touch network-config - $ touch meta-data - $ cat >user-data <user-data <`. -This tutorial, which we recommend if you are completely new to ``cloud-init``, -uses the QEMU emulator to introduce you to all of the key concepts, tools, -processes and operations that you will need to get started. +This tutorial uses the QEMU emulator to introduce you to all of the key +concepts, tools, processes and operations that you will need to use cloud-init +successfully. -.. toctree:: - :maxdepth: 1 +Further tutorials +================= - qemu.rst +This tutorial is recommended if you have some familiarity with cloud-init's key +concepts already. It uses LXD containers to show more of cloud-init's +capabilities. -Quick-start tutorial -==================== +* :ref:`Part 1: quick deployment ` -This tutorial is recommended if you have some familiarity with ``cloud-init`` -or the concepts around it, and are looking to get started as quickly as -possible. Here, you will use an LXD container to deploy a ``cloud-init`` -user data script. + Here we deploy a cloud-init user data script into a LXD container. It + can also be used as a quick-start guide. .. toctree:: :maxdepth: 1 + :hidden: + qemu.rst lxd.rst - -WSL tutorial -============ - -This tutorial is for learning to use ``cloud-init`` within a ``WSL`` -environment. You will use a ``cloud-init`` user data script to customize a -``WSL`` instance. - -.. toctree:: - :maxdepth: 1 - - wsl.rst diff --git a/doc/rtd/tutorial/lxd.rst b/doc/rtd/tutorial/lxd.rst index 8bde79c852e..85c28f185bf 100644 --- a/doc/rtd/tutorial/lxd.rst +++ b/doc/rtd/tutorial/lxd.rst @@ -3,29 +3,18 @@ Quick-start tutorial with LXD ***************************** -In this tutorial, we will create our first ``cloud-init`` user data script -and deploy it into an `LXD`_ container. +In this tutorial, we will create our first cloud-init user data script and +deploy it into a `LXD`_ container. Why LXD? ======== We'll be using LXD for this tutorial because it provides first class support -for ``cloud-init`` user data, as well as ``systemd`` support. Because it is +for cloud-init user data, as well as ``systemd`` support. Because it is container based, it allows us to quickly test and iterate upon our user data definition. -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 and initialise LXD +Install and initialize LXD ========================== If you already have LXD set up, you can skip this section. Otherwise, let's @@ -38,7 +27,7 @@ install LXD: If you don't have snap, you can install LXD using one of the `other installation options`_. -Now we need to initialise LXD. The minimal configuration will be enough for +Now we need to initialize LXD. The minimal configuration will be enough for the purposes of this tutorial. If you need to, you can always change the configuration at a later time. @@ -49,8 +38,9 @@ configuration at a later time. Define our user data ==================== -Now that LXD is set up, we can define our user data. Create the -following file on your local filesystem at :file:`/tmp/my-user-data`: +Now that LXD is set up, we can define our user data. Create a file on your +local filesystem at :file:`/tmp/my-user-data` and populate it with this +content: .. code-block:: yaml @@ -58,8 +48,8 @@ following file on your local filesystem at :file:`/tmp/my-user-data`: runcmd: - echo 'Hello, World!' > /var/tmp/hello-world.txt -Here, we are defining our ``cloud-init`` user data in the -:ref:`#cloud-config` format, using the +Here, we are defining our cloud-init user data in the +:ref:`#cloud-config ` format, using the :ref:`runcmd module ` to define a command to run. When applied, it will write ``Hello, World!`` to :file:`/var/tmp/hello-world.txt` (as we shall see later!). @@ -74,7 +64,7 @@ instance with our user data: $ lxc launch ubuntu:focal my-test --config=user.user-data="$(cat /tmp/my-user-data)" -Verify that ``cloud-init`` ran successfully +Verify that cloud-init ran successfully ------------------------------------------- After launching the container, we should be able to connect to our instance @@ -86,7 +76,7 @@ using: You should now be in a shell inside the LXD instance. -Before validating the user data, let's wait for ``cloud-init`` to complete +Before validating the user data, let's wait for cloud-init to complete successfully: .. code-block:: shell-session @@ -102,8 +92,8 @@ Which provides the following output: Verify our user data -------------------- -Now we know that ``cloud-init`` has been successfully run, we can verify that -it received the expected user data we provided earlier: +Now we know that cloud-init ran successfully, we can verify that it +received the expected user data we provided earlier: .. code-block:: shell-session @@ -141,13 +131,13 @@ Which should then print: Hello, World! -We can see that ``cloud-init`` has received and consumed our user data +We can see that cloud-init has received and consumed our user data successfully! -Tear down -========= +Completion and next steps +========================= -Exit the container shell (by typing :command:`exit` or pressing :kbd:`ctrl-d`). +Exit the container shell (by typing :command:`exit` or pressing :kbd:`Ctrl-D`). Once we have exited the container, we can stop the container using: .. code-block:: shell-session @@ -160,9 +150,6 @@ We can then remove the container completely using: $ lxc rm my-test -What's next? -============ - In this tutorial, we used the :ref:`runcmd module ` to execute a shell command. The full list of modules available can be found in our :ref:`modules documentation`. diff --git a/doc/rtd/tutorial/qemu.rst b/doc/rtd/tutorial/qemu.rst index caa79cd39dd..e7417fdd027 100644 --- a/doc/rtd/tutorial/qemu.rst +++ b/doc/rtd/tutorial/qemu.rst @@ -1,7 +1,7 @@ .. _tutorial_qemu: -Core tutorial with QEMU -*********************** +New user tutorial with QEMU +*************************** .. toctree:: :titlesonly: @@ -10,73 +10,55 @@ Core tutorial with QEMU 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. +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. +cloud-init, which you can then use as a development environment to test +your cloud-init configuration locally before launching it 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. +machines. QEMU is used at the core of a range of production operating system +deployments and open source software projects (including libvirt, LXD, +and vagrant). It is capable of running Windows, Linux, and Unix guest operating +systems. While QEMU is flexibile and feature-rich, we are using it because it +is widely supported and able to run on \*nix-derived operating systems. -How to use this tutorial -======================== +If you do not already have QEMU installed, you can install it by running the +following command in Ubuntu: -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 +.. code-block:: bash $ 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 -============================ +If you are not using Ubuntu, you can visit QEMU's `install instructions`_ to +see details for your system. -This directory will store our cloud image and configuration files for -:ref:`user data`, :ref:`metadata`, and -:ref:`vendor data`. - -You should run all commands from this temporary directory. If you run the -commands from anywhere else, your virtual machine will not be configured. +Download a cloud image +====================== -Let's create a temporary directory and make it our current working directory -with :command:`cd`: +First, we'll set up a temporary directory that will store both our cloud image +and the configuration files we'll create in the next section. Let's also make +it our current working directory: -.. code-block:: sh +.. code-block:: bash $ mkdir temp $ cd temp -Download a cloud image -====================== +We will run all the commands from this temporary directory. If we run the +commands from anywhere else, our virtual machine will not be configured. -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`` +Cloud images typically come with cloud-init pre-installed and configured to +run on first boot. We don't 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 +In our case, we want to select the latest `Ubuntu LTS`_. Let's download the server image using :command:`wget`: -.. code-block:: sh +.. code-block:: bash $ wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img @@ -86,18 +68,32 @@ server image using :command:`wget`: type and :spelling:ignore:`qemu-system-` command name to match the architecture of your host machine. -Define our user data -==================== +Define the configuration data files +=================================== + +When we launch an instance using cloud-init, we pass different types of +configuration data files to it. Cloud-init uses these as a blueprint for how to +configure the virtual machine instance. There are three major types: + +* :ref:`User data ` is provided by the user, and cloud-init + recognises many different formats. +* :ref:`vendor data ` is provided by the cloud provider. +* :ref:`Metadata ` contains the metadata about the instance + itself, including things like machine ID, hostname, etc. + +There is a specific user data format called "*cloud-config*" that is probably +the most commonly used, so we will create an example of this (and examples of +both vendor data and metadata files), then pass them all to cloud-init. -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`. +Let's create our :file:`user-data` file first. The user data *cloud-config* +is a YAML-formatted file, and in this example it 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`. -Run the following command, which creates a file named :file:`user-data` -containing our configuration data. +Run the following command to create the user data file (named +:file:`user-data`) containing our configuration data. -.. code-block:: sh +.. code-block:: bash $ cat << EOF > user-data #cloud-config @@ -107,14 +103,11 @@ containing our configuration data. EOF -What is user data? -================== +Before moving forward, let's first inspect our :file:`user-data` file. -Before moving forward, let's inspect our :file:`user-data` file. +.. code-block:: bash -.. code-block:: sh - - $ cat user-data + cat user-data You should see the following contents: @@ -125,40 +118,31 @@ You should see the following contents: 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`. - -The second line, ``password: password``, as per -:ref:`the Users and Groups module docs`, sets the default -user's password to ``password``. +* The first line starts with ``#cloud-config``, which tells cloud-init what + type of user data is in the config file. -The third and fourth lines direct ``cloud-init`` to not require a password -reset on first login. +* The second line, ``password: password`` sets the default user's password to + ``password``, as per the :ref:`Users and Groups ` + module documentation. -Define our metadata -=================== +* The third and fourth lines tell cloud-init not to require a password reset + on first login. Now let's run the following command, which creates a file named -:file:`meta-data` containing configuration data. +:file:`meta-data` containing the instance ID we want to associate to the +virtual machine instance. -.. code-block:: sh +.. code-block:: bash $ cat << EOF > meta-data instance-id: someid/somehostname EOF -Define our vendor data -====================== - -Now we will create the empty file :file:`vendor-data` in our temporary +Next, let's create an empty file called :file:`vendor-data` in our temporary directory. This will speed up the retry wait time. -.. code-block:: sh +.. code-block:: bash $ touch vendor-data @@ -166,44 +150,38 @@ directory. This will speed up the retry wait time. 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 +Instance Metadata Service (IMDS) is a service used by most cloud providers +as a way to expose information to virtual machine instances. This service is +the primary mechanism for some clouds to expose cloud-init configuration data +to the instance. - $ cd temp - $ python3 -m http.server --directory . +The IMDS uses a private http webserver to provide metadata to each running +instance. During early boot, cloud-init sets up network access and queries this +webserver to gather configuration data. This allows cloud-init to configure +the operating system while it boots. -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. +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 before deploying to a cloud. -How does ``cloud-init`` use the IMDS? -------------------------------------- +Open up a second terminal window, and in that window, run the following +commands to change to the temporary directory and then start the built-in +Python webserver: -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. +.. code-block:: bash -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. + $ cd temp + $ python3 -m http.server --directory . -Launch a virtual machine with our user data -=========================================== +Launch a VM 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 +Switch back to your original terminal, and run the following command to 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 +.. code-block:: bash $ qemu-system-x86_64 \ -net nic \ @@ -218,9 +196,6 @@ take a few moments to complete. 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. @@ -228,19 +203,19 @@ 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. +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`. During boot, ``cloud-init`` +The second line tells cloud-init where it can find user data, using the +:ref:`NoCloud datasource`. During boot, cloud-init checks the ``SMBIOS`` serial number for ``ds=nocloud``. If found, -``cloud-init`` will use the specified URL to source its user data config files. +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 +cloud-init will, inside the virtual machine, query the server running on host. -Verify that ``cloud-init`` ran successfully +Verify that cloud-init ran successfully =========================================== After launching the virtual machine, we should be able to connect to our @@ -254,13 +229,10 @@ If you can log in using the configured password, it worked! If you couldn't log in, see :ref:`this page for debug information`. -Check ``cloud-init`` status -=========================== +Let's now check cloud-init's status. Run the following command, which will +allow us to check if cloud-init has finished running: -Run the following command, which will allow us to check if ``cloud-init`` has -finished running: - -.. code-block:: sh +.. code-block:: bash $ cloud-init status --wait @@ -269,20 +241,17 @@ 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 -========= +Completion and next steps +========================= -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 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? -============ +server using (:kbd:`Ctrl-C`). In this tutorial, we configured the default user's password and ran -``cloud-init`` inside our QEMU virtual machine. +cloud-init inside our QEMU virtual machine. The full list of modules available can be found in :ref:`our modules documentation`. @@ -293,4 +262,4 @@ 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 +.. _Ubuntu LTS: https://wiki.ubuntu.com/Releases