Skip to content

Commit

Permalink
doc: Update local testing docs (canonical#4578)
Browse files Browse the repository at this point in the history
Remove duplicate content that is better described in tutorials.
Add content describing how to re-run cloud-init.
  • Loading branch information
holmanb committed Nov 5, 2023
1 parent 74e3e76 commit 6299a5c
Showing 1 changed file with 41 additions and 112 deletions.
153 changes: 41 additions & 112 deletions doc/rtd/howto/predeploy_testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,139 +3,68 @@
How to test ``cloud-init`` locally before deploying
***************************************************

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
machines (VMs) and container tools that are ideal for this sort of local
machine (VM) and container tools that are ideal for this sort of local
testing.

In this guide, we will show how to use three of the most popular tools:
`Multipass`_, `LXD`_ and `QEMU`_.
To run cloud-init locally, head over to the :ref:`tutorials page<tutorial_index>`
page, which will show you how to run cloud-init locally. Once you know
how to run cloud-init locally, you may wish to "rerun" cloud-init while
developing your cloud config for faster development.

Multipass
=========
.. _how_to_rerun_cloud-init:

Multipass is a cross-platform tool for launching Ubuntu VMs across Linux,
Windows, and macOS.
How to re-run cloud-init
========================

When a user launches a Multipass VM, user data can be passed by adding the
``--cloud-init`` flag and the appropriate YAML file containing the user data:
Cloud-init runs on "first boot", so simply rebooting the system will
not run cloud-init again[1]. Cloud-init provides two different options for
rerunning cloud-init for debugging purposes.

.. code-block:: shell-session
$ multipass launch bionic --name test-vm --cloud-init userdata.yaml
Multipass will validate the YAML syntax of the cloud-config file before
attempting to start the VM! A nice addition which saves time when you're
experimenting and launching instances with various cloud-configs.

Multipass *only* supports passing user data, and *only* as YAML cloud-config
files. Passing a script, a MIME archive, or any of the other user data formats
``cloud-init`` supports will result in an error from the YAML syntax validator.

LXD
===

LXD offers a streamlined user experience for using Linux system containers.
With LXD, a user can pass:
.. warning::

* user data,
* vendor data,
* metadata, and
* network configuration.
Making cloud-init run again may be destructive and must never be done on a production system. Artifacts such as ssh keys or passwords may be overwritten.

The following command initialises a container with user data:
Option #1: Remove the logs and cache then reboot
************************************************
This method will reboot the system as if cloud-init never ran. This
command does not remove all cloud-init artifacts from previous runs of
cloud-init, but it will clean enough artifacts to allow cloud-init to
think that it hasn't ran yet and re-run after a reboot.

.. code-block:: shell-session
$ lxc init ubuntu-daily:bionic test-container
$ lxc config set test-container user.user-data - < userdata.yaml
$ lxc start test-container
cloud-init clean --logs --reboot
To avoid the extra commands this can also be done at launch:
Option #2: Run a single cloud-init module
*****************************************
If you are using :ref:`user data cloud-config<user_data_formats-cloud_config>`
format, you might wish to rerun just a single configuration module.
Cloud-init provides the ability to run a single module in isolation and
separate from boot. This command is:

.. code-block:: shell-session
$ lxc launch ubuntu-daily:bionic 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:
This subcommand is not called by the init system. It can be called manually to
load the configured datasource and run a single cloud-config module once, using
the cached user data and metadata after the instance has booted.

.. 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:bionic test-container -p default -p dev-user-data
The above examples all show how to pass user data. To pass other types of
configuration data use the config option specified below:

+----------------+---------------------------+
| Data | Config 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.
$ sudo cloud-init single --name cc_ssh --frequency always
QEMU
====
Example output:

The :command:`cloud-localds` command from the `cloud-utils`_ package generates
a disk with user-supplied data. The ``NoCloud`` datasouce 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, for example.

The following is an example of creating the local disk using the
:command:`cloud-localds` command:

.. code-block:: shell-session
$ cat >user-data <<EOF
#cloud-config
password: password
chpasswd:
expire: False
ssh_pwauth: True
ssh_authorized_keys:
- ssh-rsa AAAA...UlIsqdaO+w==
EOF
$ cloud-localds seed.img user-data
The resulting :file:`seed.img` can then be passed along to a cloud image
containing ``cloud-init``. Below is an example of passing the :file:`seed.img`
with QEMU:

.. code-block:: shell-session
$ qemu-system-x86_64 -m 1024 -net nic -net user \
-hda ubuntu-20.04-server-cloudimg-amd64.img \
-hdb seed.img
The now-booted image will allow for login using the password provided above.

For additional configuration, users can provide much more detailed
configuration, including network configuration and metadata:

.. code-block:: shell-session
.. code-block::
$ cloud-localds --network-config=network-config-v2.yaml \
seed.img userdata.yaml metadata.yaml
...
Generating public/private ed25519 key pair
...
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.
.. note::
Each cloud-config module has a module ``FREQUENCY`` configured: ``PER_INSTANCE``, ``PER_BOOT``, ``PER_ONCE`` or ``PER_ALWAYS``. When a module is run by cloud-init, it stores a semaphore file in :file:`/var/lib/cloud/instance/sem/config_<module_name>.<frequency>` which marks when the module last successfully ran. Presence of this semaphore file prevents a module from running again if it has already been run. To ensure that a module is run again, the desired frequency can be overridden via the command line:

.. _Multipass: https://multipass.run/
.. _LXD: https://ubuntu.com/lxd
.. _QEMU: https://www.qemu.org/
.. _Instance Configuration: https://documentation.ubuntu.com/lxd/en/latest/instances/
.. _Custom Network Configuration: https://documentation.ubuntu.com/lxd/en/latest/cloud-init/
.. _cloud-utils: https://github.com/canonical/cloud-utils/
Inspect :file:`cloud-init.log` for output of what operations were performed as
a result.

0 comments on commit 6299a5c

Please sign in to comment.