Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 24 additions & 22 deletions docs/guides/virtualization/cloud-init/01_fundamentals.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,56 @@
---
title: 1. cloud-init Fundamentals
title: 1. cloud-init fundamentals
author: Wale Soyinka
contributors:
contributors: Steven Spencer
tags:
- cloud-init
- cloud
- automation
---


## The Architecture of First Boot
## The architecture of first boot

This guide explores `cloud-init`, the essential tool for automating the initial setup of your Rocky Linux 10 cloud instances. When we talk about deploying servers in the cloud—or even in your local virtualization lab—we often take for granted the almost instantaneous transition from a blank image to a fully functional, network-ready machine. This feat of digital alchemy is performed by a single, tireless utility: cloud-init.

## 1. The Bootstrapping Conundrum
## 1. The bootstrapping conundrum

### The Problem: When a Server Wakes Up Blind
### The problem: When a server wakes up blind

Imagine a generic Rocky Linux 10 QCOW2 image. It’s a perfect, pristine copy, unaware of its final destination. It doesn’t know its hostname, which user account should have SSH access, what timezone it’s in, or if it needs Apache or NGINX.
Imagine a generic Rocky Linux 10 QCOW2 image. It is a perfect, pristine copy, unaware of its final destination. It does not know its hostname, which user account should have SSH access, what timezone it is in, or if it needs Apache or NGINX.

If you were deploying physical hardware, a system administrator would manually configure all these parameters. But in the cloud, servers are ephemeral, scaled up and down by the thousands. We need a standardized, generic, and reliable mechanism to inject the necessary context into that blank image the very first time it boots.

This is the problem **cloud-init** solves.

### What is cloud-init?
### What is cloud-init

Simply put, cloud-init is the industry-standard multi-distribution package that handles early initialization of cloud instances. It is the core service responsible for taking a generic image (like the one we’re using) and performing the required configuration tasks to transform it into a unique, production-ready server.
Simply put, cloud-init is the industry-standard multi-distribution package that handles early initialization of cloud instances. It is the core service responsible for taking a generic image (such as the one we are using) and performing the required configuration tasks to transform it into a unique, production-ready server.

It literally sits at the heart of the provisioning process, interpreting **metadata** and **user-defined instructions** to set up the system. Without it, your cloud instance is just a beautifully compiled Linux kernel with an identity crisis.

### The cloud-init Ecosystem
### The cloud-init ecosystem

cloud-init is a consumer, not a creator. It relies on the underlying cloud platform (AWS, Azure, GCP, OpenStack, or local tools like libvirt) to provide it with configuration information.
cloud-init is a consumer, not a creator. It relies on the underlying cloud platform (AWS, Azure, GCP, OpenStack, or local tools such as libvirt) to provide it with configuration information.

* **Cloud Providers** expose data via a specialized *data source* (often a local HTTP endpoint, a specific disk label, or a kernel parameter).
* **cloud-init** detects this data source, reads the configuration, and executes the appropriate configuration steps.
* **Cloud Providers** expose data via a specialized *data source* (often a local HTTP endpoint, a specific disk label, or a kernel parameter).
* **cloud-init** detects this data source, reads the configuration, and executes the appropriate configuration steps.

This decoupling—where the image is generic and the configuration is provided externally—is the fundamental genius of the entire cloud deployment model.

## 2. Rocky Linux 10 and the Generic Cloud Image
## 2. Rocky Linux 10 and the generic cloud image

For this guide, we'll be using the official [Rocky-10-GenericCloud-Base.latest.x86_64.qcow2](https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2).
For this guide, we will be using the official [Rocky-10-GenericCloud-Base.latest.x86_64.qcow2](https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2).

### The Target Image: A Pre-Wired Workhorse
### The target image: A pre-wired workhorse

This image is special because it comes with the cloud-init package pre-installed and enabled. It has been *generalized*, meaning all machine-specific identifiers, SSH host keys, and log files have been stripped out. It’s ready to receive its new identity on first boot.
This image is special because it includes the cloud-init package pre-installed and enabled. It has been *generalized*, meaning all machine-specific identifiers, SSH host keys, and log files are all stripped out. It is ready to receive its new identity on first boot.

!!! warning "Use the Recommended Image"
If you attempt to use cloud-init on a standard Rocky Linux installation (like a minimal ISO install), you’ll find it’s not present by default. Stick to the **Generic Cloud image** to avoid needless complexity and ensure everything works exactly as the doctor prescribed. Attempting the exercises in this guide with other images will likely fail and is not supported.

### Core Concepts: User-Data vs. Meta-Data
If you attempt to use cloud-init on a standard Rocky Linux installation (like a minimal ISO install), you will find it is not present by default. Stick to the **Generic Cloud image** to avoid needless complexity and ensure everything works exactly as the doctor prescribed. Attempting the exercises in this guide with other images will likely fail and is not supported.

### Core concepts: User-Data vs. Meta-Data

The configuration information that cloud-init processes is categorized into two key types. Understanding this distinction is critical to knowing what you can control and what the cloud provider controls.

Expand All @@ -68,11 +69,11 @@ We will focus primarily on crafting effective **User-Data** files, which typical
#cloud-config
```

## 3. The Lifecycle: cloud-init's Four Stages of Initialization
## 3. The life cycle: cloud-init's four stages of initialization

cloud-init doesn't just run a script and exit; it executes a series of highly structured stages that align with the server's boot process. This methodical approach ensures that dependencies are met (e.g., networking is configured before packages are downloaded).

Understanding this lifecycle is crucial for debugging and knowing precisely when your custom instructions are executed.
Understanding this life cycle is crucial for debugging and knowing precisely when your custom instructions are executed.

| Stage | Timing & Description | Key Actions/Modules |
| :---------- | :-------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- |
Expand All @@ -81,9 +82,10 @@ Understanding this lifecycle is crucial for debugging and knowing precisely when
| **Network** | Runs once networking is fully configured and operational. It queries network-based data sources (like the cloud provider's API). | Configure network interfaces, fetch keys from network metadata. |
| **Final** | Runs last. This is where the majority of user-defined configuration takes place, as all prerequisites (users, network, disks) are now ready. | Installing packages, running custom scripts (runcmd), writing files (write_files), system clean-up. |

!!! tip "Check the Logs"
!!! tip "Check the logs"

When troubleshooting, always check `/var/log/cloud-init.log`. This file is the forensic report of the `cloud-init` process, showing exactly when each stage began and finished, and what modules were executed along the way. If your script didn't run, the log will tell you exactly why, and which stage failed.

## What's Next?
## What's next

Now that you understand the fundamental architecture of `cloud-init`—the "what" and "why," the different data types, and the boot stages—you are ready to move from theory to practice. The next chapter will guide you through your first hands-on exercise: booting the Rocky Linux 10 cloud image and performing a simple, real-world customization.
68 changes: 39 additions & 29 deletions docs/guides/virtualization/cloud-init/02_first_contact.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: 2. First Contact
title: 2. First contact
author: Wale Soyinka
contributors:
tags:
Expand All @@ -9,29 +9,29 @@ tags:
---


## Simple Bootstrapping with the Rocky Linux 10 QCOW2 Image
## Simple bootstrapping with the Rocky Linux 10 QCOW2 image

In the previous chapter, we covered the fundamental concepts of `cloud-init`. Now, it’s time to move from theory to practice. This chapter is your first hands-on mission: you will take the official Rocky Linux 10 Generic Cloud image, provide it with a simple set of instructions, and watch it configure itself on first boot.
In the previous chapter, we covered the fundamental concepts of `cloud-init`. Now, it is time to move from theory to practice. This chapter is your first hands-on mission: you will take the official Rocky Linux 10 Generic Cloud image, provide it with a simple set of instructions, and watch it configure itself on first boot.

## 1. Prepping the Lab Environment
## 1. Prepping the lab environment

Before we can boot our first instance, we need to prepare our local lab environment. For these exercises, we will simulate a cloud environment using standard Linux virtualization tools.

### Prerequisites: Host Tools
### Prerequisites: host tools

Ensure you have the following tools installed on your host machine. On a Rocky Linux host, you can install them with `dnf`:

```bash
sudo dnf install -y libvirt qemu-kvm virt-install genisoimage
```

* **Virtualization Hypervisor:** A tool like KVM/QEMU or VirtualBox.
* `virt-install`: A command-line utility for provisioning new virtual machines.
* `genisoimage` (or `mkisofs`): A tool to create an ISO9660 filesystem.
* **Virtualization Hypervisor:** A tool like KVM/QEMU or VirtualBox.
* `virt-install`: A command-line utility for provisioning new virtual machines.
* `genisoimage` (or `mkisofs`): A tool to create an ISO9660 filesystem.

### The QCOW2 Image
### The QCOW2 image

If you haven't already, download the official Rocky Linux 10 Generic Cloud image.
If you have not already, download the official Rocky Linux 10 Generic Cloud image.

```bash
curl -L -o Rocky-10-GenericCloud.qcow2 \
Expand All @@ -44,7 +44,7 @@ To preserve the original, create a working copy of the image for your VM.
cp Rocky-10-GenericCloud.qcow2 first-boot-vm.qcow2
```

!!! tip "Save Disk Space with Backing Files"
!!! tip "Save disk space with backing files"

A full copy of the image can be large. To save disk space, you can create a *linked clone* that uses the original image as a backing file. This creates a much smaller `qcow2` file that only stores the differences from the original.

Expand All @@ -53,18 +53,20 @@ cp Rocky-10-GenericCloud.qcow2 first-boot-vm.qcow2
-b Rocky-10-GenericCloud.qcow2 first-boot-vm.qcow2
```

## 2. Method 1: The `NoCloud` Datasource (ISO)
## 2. Method 1: The `NoCloud` datasource (ISO)

One of the most common ways to provide data to `cloud-init` in a local environment is the `NoCloud` datasource. This method requires packaging our configuration files into a virtual CD-ROM (an ISO file) that `cloud-init` will automatically detect and read on boot.
One of the most common ways to provide data to `cloud-init` in a local environment is the `NoCloud` datasource. This method requires packaging your configuration files into a virtual CD-ROM (an ISO file) that `cloud-init` will automatically detect and read on boot.

### Creating the Configuration Files
### Creating the configuration files

1. **Create a directory for your configuration files:**

1. **Create a directory for your configuration files:**
```bash
mkdir cloud-init-data
```

2. **Create the `user-data` file:** This file is your primary instruction set. We will use a `cat` heredoc to create it.
2. **Create the `user-data` file:** This file is your primary instruction set. We will use a `cat` heredoc to create it.

```bash
cat <<EOF > cloud-init-data/user-data
#cloud-config
Expand All @@ -74,7 +76,8 @@ One of the most common ways to provide data to `cloud-init` in a local environme
EOF
```

3. **Create the `meta-data` file:** This file provides context *about* the instance. The `instance-id` is particularly important, as `cloud-init` uses it to determine if it has run on this instance before. Changing the ID will cause `cloud-init` to run again.
3. **Create the `meta-data` file:** This file provides context *about* the instance. The `instance-id` is particularly important, as `cloud-init` uses it to determine if it has run on this instance before. Changing the ID will cause `cloud-init` to run again.

```bash
cat <<EOF > cloud-init-data/meta-data
{
Expand All @@ -84,14 +87,16 @@ One of the most common ways to provide data to `cloud-init` in a local environme
EOF
```

4. **Generate the ISO:** Use `genisoimage` to package the files into `config.iso`. The volume label `-V cidata` is the magic key that `cloud-init` looks for.
4. **Generate the ISO:** Use `genisoimage` to package the files into `config.iso`. The volume label `-V cidata` is the magic key that `cloud-init` looks for.

```bash
genisoimage -o config.iso -V cidata -r -J cloud-init-data
```

### Booting and Verification
### Booting and verification

1. **Launch the VM** with `virt-install`, attaching both the VM image and the `config.iso`.

1. **Launch the VM** with `virt-install`, attaching both the VM image and the `config.iso`.
```bash
virt-install --name rocky10-iso-boot \
--memory 2048 --vcpus 2 \
Expand All @@ -101,27 +106,31 @@ One of the most common ways to provide data to `cloud-init` in a local environme
--import --noautoconsole
```

2. **Find the IP and connect via SSH.** The default user is `rocky`.
2. **Find the IP and connect via SSH.** The default user is `rocky`.

```bash
virsh domifaddr rocky10-iso-boot
ssh rocky@<IP_ADDRESS>
```
!!! tip "Secure Logins with SSH Keys"

!!! tip "Secure logins with SSH keys"

Connecting with a default user is convenient for a quick lab test, but it is not a secure practice. In the next chapter, we will explore how to use `cloud-init` to automatically inject your SSH public key, allowing for secure, passwordless logins.

3. **Verify the changes:** Check the hostname and the file created by `runcmd`.
3. **Verify the changes:** Check the hostname and the file created by `runcmd`.

```bash
hostname
sudo cat /root/boot_done.txt
```

## **3. Method 2: Direct Injection with `virt-install`**
## 3. Method 2: Direct injection with `virt-install`

Creating an ISO is a reliable method, but for users of `libvirt` and `virt-install`, there is a much simpler way. The `--cloud-init` flag allows you to pass `user-data` directly, letting `virt-install` handle the creation of the datasource automatically.

### Simplified `user-data`

Create a simple `user-data.yml` file. You can even add the SSH key pre-emptively.
Create a simple `user-data.yml` file. You can even add the SSH key preemptively.

```bash
cat <<EOF > user-data.yml
Expand All @@ -133,9 +142,10 @@ users:
EOF
```

### Booting and Verification
### Booting and verification

1. **Launch the VM** using the `--cloud-init` flag. Notice we can set the hostname here directly.

1. **Launch the VM** using the `--cloud-init` flag. Notice we can set the hostname here directly.
```bash
virt-install --name rocky10-direct-boot \
--memory 2048 --vcpus 2 \
Expand All @@ -145,8 +155,8 @@ EOF
--import --noautoconsole
```

2. **Find the IP and connect.** If you added your SSH key, you should be able to connect without a password.
2. **Find the IP and connect.** If you added your SSH key, you should be able to connect without a password.

3. **Verify the hostname.** It should be `cloud-rockstar-02`.
3. **Verify the hostname.** It should be `cloud-rockstar-02`.

This direct method is often faster and more convenient for local development and testing with `libvirt`.
Loading