Cloud-Init - Getting Started
If you read my blog carefully, you may know that I really like Ansible. You can manage and configure machines and APIs very easily with Ansible automation. But what if the machine is offline or needs a configuration to boot up? This is where Cloud-Init can help.
If you read my blog carefully, you may know that I really like Ansible. You can manage and configure machines and APIs very easily with Ansible automation. But what if the machine is offline or needs a configuration to boot up? This is where Cloud-Init can help. Configurations are written in YAML, which fits well in my tool chain.
Cloud-Init
Cloud-Init is a quite simple, but powerful way to configure machines. Let's assume, you want to set up a machine, that requires some settings pre-configured or packages installed. You can think of "create a user" or "install updates", but also "configure network" or "put a file there".
Other than Kickstart, Cloud-Init works for almost all major GNU/Linux distributions, as long as you are using a special cloud-image. But what is special about these images? And how does this work?
How does Cloud-Init work?
Under the hood, the whole Cloud-Init magic seems trivial.
- a new cloud-image machine starts and therefore the cloud-init.service is started, too
- cloud-init checks, validates and parses an existing cloud-init configuration
- cloud-init applies (via API, Commands and config changes) the cloud-init configuration
That's already it. If there is no Cloud-Init configuration, nothing will be done. Optionally, a reboot is triggered.
The above-mentioned "apply" stage works in modules, which are somewhat nicely documented in the official documentation.
Where to use Cloud-Init?
Ok, so where can one use Cloud-Init? Looking at the name, it should work in the cloud. Chances are high, that your hosting/cloud provider already supports it. You can expect very sane support in at least:
- OpenStack
- Apache CloudStack
- Amazone Web Services (AWS)
- Microsoft Azure
- Exoscale
- KVM/libvirt
- and many more
Most of them can also be consumed as a data source for additional features.
Using Cloud-Init with Fedora
Enough of the theory, let's make something work. I suggest starting with Fedora VM on a KVM/libvirt hypervisor/host. Anyway, the example can also be used with Ubuntu, CentOS or AlmaLinux as long as the libvirt/virt-install version is recent enough.
Requirements
To follow the guide, you need to have a Fedora 36 KVM host, similar to the home server setup as described in "Fedora - Home Server (Virtualization)" article. In addition, you will need "virt-install" in Version 3.0.0 or newer.
If you have a plain Fedora Server or Workstation, you can install all necessary tooling with a single command:
# Install needed tooling
$ sudo dnf install \
libvirt-daemon-config-network \
libvirt-daemon-kvm \
qemu-kvm \
virt-install
# Reboot afterwards
$ reboot
Now, we can already check if everything works.
# Check user VMs
$ virsh list
Id Name State
--------------------
# Check root VMs
$ sudo virsh list
Id Name State
--------------------
The next thing we need is a Cloud Image. I am using the Fedora 36 Cloud Base Image for now. But, please feel free to test your configuration with another Cloud Image like Ubuntu.
# Download image
$ wget https://download.fedoraproject.org/pub/fedora/linux/releases/36/Cloud/x86_64/images/Fedora-Cloud-Base-36-1.5.x86_64.qcow2
Now, we can start to play with Cloud-Init deployments.
SImple Cloud-Init Configuration
Writing a Cloud-Init configuration can be done with basically every editor. Let's start with something really simple. Just create a new file, named "user-data" and fill in the below.
This will configure the VM with a user and the given password.
Starting a VM
Now, that we are having the image and the configuration, we can use the virt-install
command to create a machine and apply the Cloud-Init configuration.
# Copy the image / Create the disk
$ cp Fedora-Cloud-Base-36-1.5.x86_64.qcow2 vm01.qcow2
# Create the VM
$ virt-install \
--name vm01 \
--memory 1024 \
--vcpus 2 \
--graphics none \
--os-variant detect=on \
--import \
--disk vm01.qcow2,size=20 \
--graphics none \
--console pty,target_type=virtio \
--serial pty \
--cloud-init user-data=user-data
After firing the above command, you will find yourself in a new console (inside the VM). Waiting for some seconds and you can monitor the initial bootup. At the end, you can log in to your VM with the above provided user and password.
Starting install...
Creating domain... | 0 B 00:00:00
Running text console command: virsh --connect qemu:///session console vm01
Connected to domain 'vm01'
Escape character is ^] (Ctrl + ])
...SNIP...
[ OK ] Finished cloud-final.servi… Execute cloud user/final scripts.
[ OK ] Reached target cloud-init.target - Cloud-init target.
Fedora Linux 36 (Cloud Edition)
Kernel 5.17.5-300.fc36.x86_64 on an x86_64 (ttyS0)
fedora login:
Feel free to play in the VM as you like. If you are done, you can quit the console with the mentioned Escape sequence ( CTRL + ALT Gr + 9
on a German keyboard).
After quitting the VM, it will be running in the background. If you like, you can stop/start or remove the machine with the below commands.
# List VMs
$ virsh list
Id Name State
----------------------
1 vm01 running
# Stop VM
$ virsh destroy vm01
Domain 'vm01' destroyed
# Start VM
$ virsh start vm01
Domain 'vm01' started
# Remove VM (after stopping)
$ virsh undefine vm01
Domain 'vm01' has been undefined
# Connect to the console of a VM
$ virsh console vm01
The virsh
command is very powerful, and we may revisit at some point. For now, this should be sufficient.
Another Cloud-Init Configuration
For a more advanced example, we can also install a couple of packages, and apply updates.
Inside the VM:
# Connect to the VM
$ virsh console VMNAME
Connected to domain 'vm01'
Escape character is ^] (Ctrl + ])
vm01 login: admin
Password:
[admin@vm01 ~]$ sudo cat /root/hello.txt
Hello World!
Feel free to enhance your configuration even more with the available Cloud-Init modules.
Alternatives
There are a couple of alternatives for different purposes, which I want to link here.
Kickstart was already addressed in another article and is mostly for RHEL family systems and bare metal or "from scratch" installations.
Preseed and Autoyast are similar to Kickstart, but meant for Debian/Ubuntu and SUSE Linux.
There is also Ignition, which is intended for cloud deployments and origins in CoreOS. It is used for Fedora CoreOS.
Docs & Links
If you want to dig deeper, you can have a look at the official documentation and some nice articles about the same topic.
Conclusion
That's it for today. Feel free to play with Cloud-Init and reach out to me, if I forgot something. I would also love to get your feedback if you use Cloud-Init and if there are any other mechanisms, that should be added to the article.