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
12 changes: 6 additions & 6 deletions docs/guides/virtualization/cloud-init/01_fundamentals.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
Title: I. cloud-init Fundamentals: The Architecture of First Boot
title: 1. cloud-init Fundamentals
author: Wale Soyinka
contributors:
tags:
Expand All @@ -9,7 +9,7 @@ tags:
---


## Introduction
## 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.

Expand Down Expand Up @@ -38,18 +38,18 @@ cloud-init is a consumer, not a creator. It relies on the underlying cloud platf

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).

### **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.

!!! 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**
### 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,7 +68,7 @@ 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 Lifecycle: 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).

Expand Down
14 changes: 7 additions & 7 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: II. First Contact: Simple Bootstrapping
title: 2. First Contact
author: Wale Soyinka
contributors:
tags:
Expand Down Expand Up @@ -29,7 +29,7 @@ sudo dnf install -y libvirt qemu-kvm virt-install genisoimage
* `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.

Expand All @@ -53,11 +53,11 @@ 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.

### **Creating the Configuration Files**
### Creating the Configuration Files

1. **Create a directory for your configuration files:**
```bash
Expand Down Expand Up @@ -89,7 +89,7 @@ One of the most common ways to provide data to `cloud-init` in a local environme
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`.
```bash
Expand Down Expand Up @@ -119,7 +119,7 @@ One of the most common ways to provide data to `cloud-init` in a local environme

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`**
### Simplified `user-data`

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

Expand All @@ -133,7 +133,7 @@ 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.
```bash
Expand Down
16 changes: 8 additions & 8 deletions docs/guides/virtualization/cloud-init/03_configuration_engine.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: III. The Configuration Engine: Deep Dive into cloud-init Modules
title: 3. The Configuration Engine
author: Wale Soyinka
contributors:
tags:
Expand All @@ -23,11 +23,11 @@ A `cloud-init` module is a specialized Python script designed to handle a single

The key advantage of using modules over simple scripts (like `runcmd`) is **idempotency**. An idempotent operation produces the same result whether you run it once or ten times. When you declare that a user should exist, the module ensures that state is met—it will create the user if it doesn't exist, but do nothing if it already does. This makes your configurations reliable and repeatable.

### **The `#cloud-config` Format Revisited**
### The `#cloud-config` Format Revisited

When `cloud-init` sees the `#cloud-config` header, it interprets the file as a YAML-formatted instruction set. The top-level keys in this YAML file map directly to `cloud-init` modules.

### **Module Execution and Order**
### Module Execution and Order

Modules run at specific stages of the boot process in a sequence defined in `/etc/cloud/cloud.cfg`. A simplified view of this flow looks like this:

Expand All @@ -53,11 +53,11 @@ The order is critical. For example, the `users-groups` module runs before `runcm

While `/etc/cloud/cloud.cfg` defines the default behavior, you should never edit it directly. For persistent, system-wide customizations, place your own `.cfg` files in the `/etc/cloud/cloud.cfg.d/` directory. This is the standard practice for building custom images, which we will explore in a later chapter.

## **2. High-Utility Modules: The Daily Drivers**
## 2. High-Utility Modules: The Daily Drivers

Let's get hands-on with the most common modules using the direct injection method with `virt-install`.

### **Module Deep Dive: `users` and `groups`**
### Module Deep Dive: `users` and `groups`

Properly managing user accounts is the cornerstone of securing a new server instance. The `users` module is your primary tool for this, allowing you to create new users, modify existing ones, manage group memberships, and, most importantly, inject SSH keys to facilitate secure, passwordless logins from the very first boot.

Expand Down Expand Up @@ -109,7 +109,7 @@ A more common task is to simply secure the default user provided with the cloud

3. **Boot and Verify:** Boot the VM. You can now SSH as the `rocky` user without a password.

### **Module Deep Dive: `packages`**
### Module Deep Dive: `packages`

The `packages` module provides a declarative way to manage the software on your instance, ensuring that specific applications are installed at boot time.

Expand All @@ -136,7 +136,7 @@ In this example, we will ensure two useful tools, `nginx` (a high-performance we

If you were to reboot this VM with the same `user-data`, the `packages` module would see that `nginx` and `htop` are already installed and do nothing further. It ensures the desired state (packages are present) without taking unnecessary action. That is idempotency.

### **Module Deep Dive: `write_files`**
### Module Deep Dive: `write_files`

This module is incredibly versatile, allowing you to write any text content to any file on the system. It is the perfect tool for deploying application configuration files, populating web content, or creating helper scripts.

Expand Down Expand Up @@ -169,6 +169,6 @@ To demonstrate its power, we will use `write_files` to create a custom homepage

The `write_files` module is not limited to text. By specifying an `encoding`, you can deploy binary files. For example, you can use `encoding: b64` to write base64-encoded data. For advanced use cases, refer to the [official `write_files` documentation](https://cloudinit.readthedocs.io/en/latest/topics/modules.html#write-files).

## **What's Next?**
## What's Next?

You have now mastered the three most fundamental `cloud-init` modules. By combining them, you can perform a significant amount of automated server configuration. In the next chapter, we will tackle more advanced scenarios, including network configuration and combining different `user-data` formats in a single run.
53 changes: 28 additions & 25 deletions docs/guides/virtualization/cloud-init/04_advanced_provisioning.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: IV. Advanced Provisioning - Networking and Multi-Part Payloads
title: 4. Advanced Provisioning
author: Wale Soyinka
contributors:
tags:
Expand All @@ -16,8 +16,8 @@ In the previous chapter, you mastered the core `cloud-init` modules for managing

This chapter covers two powerful, advanced topics:

1. **Declarative Network Configuration:** How to move beyond DHCP and define static network configurations for your instances.
2. **Multi-Part MIME Payloads:** How to combine different types of user-data, like shell scripts and `#cloud-config` files, into a single, powerful payload.
1. Declarative Network Configuration: How to move beyond DHCP and define static network configurations for your instances.
2. Multi-Part MIME Payloads: How to combine different types of user-data, like shell scripts and `#cloud-config` files, into a single, powerful payload.

## 1. Declarative Network Configuration

Expand All @@ -28,7 +28,7 @@ Network configurations are specified in a separate YAML document from your main
!!! note "How `cloud-init` Applies Network State"
On Rocky Linux, `cloud-init` does not directly configure the network interfaces. Instead, it acts as a translator, converting its network configuration into files that **NetworkManager** (the default network service) can understand. It then hands off control to NetworkManager to apply the configuration. You can inspect the resulting connection profiles in `/etc/NetworkManager/system-connections/`.

### **Example 1: Configuring a Single Static IP**
### Example 1: Configuring a Single Static IP

In this exercise, we will configure our virtual machine with a static IP address, a default gateway, and custom DNS servers.

Expand Down Expand Up @@ -92,7 +92,7 @@ In this exercise, we will configure our virtual machine with a static IP address
```
The output should show that `eth0` has the static IP address `192.168.122.100/24`.

### **Example 2: Multi-Interface Configuration**
### Example 2: Multi-Interface Configuration

A common real-world scenario is a server with multiple network interfaces. Here, we'll create a VM with two interfaces: `eth0` will use DHCP, and `eth1` will have a static IP.

Expand Down Expand Up @@ -128,7 +128,7 @@ A common real-world scenario is a server with multiple network interfaces. Here,

3. **Verify:** SSH to the DHCP-assigned address on `eth0` and then check the static IP on `eth1` with `ip a show eth1`.

## **2. Unifying Payloads with Multi-Part MIME**
## 2. Unifying Payloads with Multi-Part MIME

Sometimes, you need to run a setup script *before* the main `#cloud-config` modules execute. MIME multi-part files are the solution, allowing you to bundle different content types into one ordered payload.

Expand Down Expand Up @@ -157,7 +157,7 @@ The structure of a MIME file can be visualized as follows:
+-----------------------------------------+
```

### **Hands-On: A Pre-flight Check Script**
### Hands-On: A Pre-flight Check Script

We will create a multi-part file that first runs a shell script and then proceeds to the main `#cloud-config`.

Expand All @@ -168,33 +168,35 @@ We will create a multi-part file that first runs a shell script and then proceed
```bash
cat <<EOF > user-data.mime
Content-Type: multipart/mixed; boundary="//"
MIME-Version: 1.0
MIME-Version: 1.0

--//
Content-Type: text/x-shellscript; charset="us-ascii"
--//
Content-Type: text/x-shellscript; charset="us-ascii"

#!/bin/sh
echo "Running pre-flight checks..."
# In a real script, you might check disk space or memory.
# If checks failed, you could 'exit 1' to halt cloud-init.
echo "Pre-flight checks passed." > /tmp/pre-flight-status.txt
#!/bin/sh
echo "Running pre-flight checks..."
# In a real script, you might check disk space or memory.
# If checks failed, you could 'exit 1' to halt cloud-init.
echo "Pre-flight checks passed." > /tmp/pre-flight-status.txt

--//
Content-Type: text/cloud-config; charset="us-ascii"
--//
Content-Type: text/cloud-config; charset="us-ascii"

#cloud-config
packages:
- htop
runcmd:
- [ sh, -c, "echo 'Main cloud-config ran successfully' > /tmp/main-config-status.txt" ]
#cloud-config
packages:
- htop
runcmd:
- [ sh, -c, "echo 'Main cloud-config ran successfully' > /tmp/main-config-status.txt" ]

--//--
--//--
EOF
```

!!! note "About the MIME Boundary"

The boundary string (`//` in this case) is an arbitrary string that must not appear in the content of any part. It is used to separate the different sections of the file.

2. **Boot and Verify:**
2. Boot and Verify:

You pass this file to `virt-install` in the same way as a standard `user-data.yml` file.

Expand All @@ -218,9 +220,10 @@ runcmd:
```

!!! tip "Other Multi-Part Content Types"

`cloud-init` supports other content types for advanced use cases, such as `text/cloud-boothook` for very early boot scripts or `text/part-handler` for running custom Python code. Refer to the official documentation for more details.

## **What's Next?**
## What's Next?

You have now learned two powerful, advanced `cloud-init` techniques. You can now define static networks and orchestrate complex provisioning workflows with multi-part user-data.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: V. The Image Builder's Perspective
title: 5. The Image Builder's Perspective
author: Wale Soyinka
contributors:
tags:
Expand Down Expand Up @@ -37,11 +37,11 @@ virt-install --name golden-image-builder \
virsh console golden-image-builder
```

## **2. System-Wide Configuration with `cloud.cfg.d`**
## 2. System-Wide Configuration with `cloud.cfg.d`

Inside our running VM, we can now customize the system-wide `cloud-init` configuration. The master file, `/etc/cloud/cloud.cfg`, should never be edited directly. The correct, upgrade-safe location for customizations is the `/etc/cloud/cloud.cfg.d/` directory. `cloud-init` reads all `.cfg` files here in alphabetical order after the main `cloud.cfg`, allowing you to override defaults.

### **Hands-On: Setting Golden Image Defaults**
### Hands-On: Setting Golden Image Defaults

Let's enforce a policy on our golden image: we will disable password authentication, set a new default user, and ensure a baseline set of packages is always installed.

Expand Down Expand Up @@ -74,11 +74,11 @@ A powerful security technique is to completely disable certain `cloud-init` modu
cloud_final_modules: []
```

## **3. Generalizing the Image**
## 3. Generalizing the Image

Our VM now contains our custom configuration, but it also holds unique machine identifiers (like `/etc/machine-id`) and SSH host keys. Before we can clone it, we **must** remove this data in a process called **generalization**.
Our VM now contains our custom configuration, but it also holds unique machine identifiers (like `/etc/machine-id`) and SSH host keys. Before we can clone it, we must remove this data in a process called **generalization**.

### **Method 1: `cloud-init clean` (Inside the VM)**
### Method 1: `cloud-init clean` (Inside the VM)

`cloud-init` provides a built-in command for this purpose.

Expand All @@ -94,7 +94,7 @@ Our VM now contains our custom configuration, but it also holds unique machine i
sudo poweroff
```

### **Method 2: `virt-sysprep` (From the Host)**
### Method 2: `virt-sysprep` (From the Host)

An even more thorough, industry-standard tool is `virt-sysprep`. It can be run from your host machine on the shutdown VM disk. It performs all the actions of `cloud-init clean` and much more, such as clearing command history, removing temporary files, and resetting log files.

Expand All @@ -109,7 +109,7 @@ Once the generalization process is complete, the disk file (`golden-image-templa
!!! note "Golden Image Naming Conventions"
It is a good practice to give your golden images descriptive names that include the OS and a version number, such as `rocky10-base-v1.0.qcow2`. This helps with version control and infrastructure management.

## **4. Verifying the Golden Image**
## 4. Verifying the Golden Image

Let's test our new image by booting a new instance *from* it without any `user-data`.

Expand All @@ -125,6 +125,6 @@ Let's test our new image by booting a new instance *from* it without any `user-d

3. **Verify:** Connect to the console (`virsh console golden-image-test`). The login prompt should be for the user `admin`, not `rocky`. Once logged in, you can also verify that `htop` is installed (`rpm -q htop`). This confirms your baked-in defaults are working.

## **What's Next?**
## What's Next?

You have now learned how to create standardized templates by baking in defaults with `cloud-init`'s system-wide configuration and properly generalizing them for cloning. In the next chapter, we will cover the essential skill of troubleshooting when `cloud-init` doesn't behave as expected.
Loading