diff --git a/docs/guides/virtualization/cloud-init/01_fundamentals.md b/docs/guides/virtualization/cloud-init/01_fundamentals.md index 61ea0d1d8e..be0b22ba4d 100644 --- a/docs/guides/virtualization/cloud-init/01_fundamentals.md +++ b/docs/guides/virtualization/cloud-init/01_fundamentals.md @@ -1,7 +1,7 @@ --- -title: 1. cloud-init Fundamentals +title: 1. cloud-init fundamentals author: Wale Soyinka -contributors: +contributors: Steven Spencer tags: - cloud-init - cloud @@ -9,47 +9,48 @@ tags: --- -## 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. @@ -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 | | :---------- | :-------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | @@ -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. diff --git a/docs/guides/virtualization/cloud-init/02_first_contact.md b/docs/guides/virtualization/cloud-init/02_first_contact.md index dcf4a33e32..4d7359fe34 100644 --- a/docs/guides/virtualization/cloud-init/02_first_contact.md +++ b/docs/guides/virtualization/cloud-init/02_first_contact.md @@ -1,5 +1,5 @@ --- -title: 2. First Contact +title: 2. First contact author: Wale Soyinka contributors: tags: @@ -9,15 +9,15 @@ 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`: @@ -25,13 +25,13 @@ Ensure you have the following tools installed on your host machine. On a Rocky L 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 \ @@ -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. @@ -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 < cloud-init-data/user-data #cloud-config @@ -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 < cloud-init-data/meta-data { @@ -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 \ @@ -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@ ``` - !!! 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 < user-data.yml @@ -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 \ @@ -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`. diff --git a/docs/guides/virtualization/cloud-init/03_configuration_engine.md b/docs/guides/virtualization/cloud-init/03_configuration_engine.md index 45ab53add9..19481cfcdf 100644 --- a/docs/guides/virtualization/cloud-init/03_configuration_engine.md +++ b/docs/guides/virtualization/cloud-init/03_configuration_engine.md @@ -1,7 +1,7 @@ --- -title: 3. The Configuration Engine +title: 3. The configuration engine author: Wale Soyinka -contributors: +contributors: Steven Spencer tags: - cloud-init - rocky linux @@ -9,27 +9,27 @@ tags: - automation --- -## Deep Dive into cloud-init Modules +## Deep dive into cloud-init modules -In the last chapter, you successfully booted a cloud image and performed a simple customization. While effective, the true power, portability, and idempotency of `cloud-init` are unlocked through its module system. These modules are the specialized tools in the `cloud-init` toolkit, designed to handle specific configuration tasks in a declarative and predictable way. +In the last chapter, you successfully booted a cloud image and performed a simple customization. While effective, the true power, portability, and you unlock idempotency of `cloud-init` through its module system. These modules are the specialized tools in the `cloud-init` toolkit, designed to handle specific configuration tasks in a declarative and predictable way. This chapter dives deep into the module system, explaining what modules are, how they work, and how to use the most essential ones to build a well-configured server. -## 1. The Anatomy of Configuration +## 1. The anatomy of configuration -### What are cloud-init Modules? +### What are cloud-init modules -A `cloud-init` module is a specialized Python script designed to handle a single, discrete provisioning task. Think of them as plugins for tasks like managing users, installing packages, or writing files. +A `cloud-init` module is a specialized Python script designed to handle a single, discrete provisioning task. Think of them as plugins for tasks such as managing users, installing packages, or writing files. -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 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 does not 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: +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 such as this: ``` System Boot @@ -49,23 +49,24 @@ System Boot The order is critical. For example, the `users-groups` module runs before `runcmd`, ensuring a script can be run by a user who was just created in the same configuration. -!!! tip "Customizing `cloud-init` Behavior" +!!! tip "Customizing `cloud-init` behavior" 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`. +Let us get hands-on with the most common modules by 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. -**Example 1: Creating a New Admin User** +**Example 1: Creating a new admin user** In this example, we will provision a new, dedicated administrative user named `sysadmin`. We will grant this user passwordless `sudo` capabilities by adding them to the `wheel` group and providing a specific `sudo` rule. We will also inject an SSH public key to ensure secure access. -1. **Create `user-data.yml`:** +1. **Create `user-data.yml`:** + ```bash cat < user-data.yml #cloud-config @@ -79,19 +80,21 @@ In this example, we will provision a new, dedicated administrative user named `s EOF ``` -2. **Key Directives Explained:** - * `name`: The username for the new account. - * `groups`: A list of groups to add the user to. On Rocky Linux, membership in the `wheel` group is commonly used to grant administrative rights. - * `sudo`: A list of `sudoers` rules to apply. The rule `ALL=(ALL) NOPASSWD:ALL` grants the user the ability to run any command with `sudo` without being prompted for a password. - * `ssh_authorized_keys`: A list of public SSH keys to add to the user's `~/.ssh/authorized_keys` file. +2. **Key directives explained:** + + * `name`: The username for the new account. + * `groups`: A list of groups to add the user to. On Rocky Linux, membership in the `wheel` group is commonly used to grant administrative rights. + * `sudo`: A list of `sudoers` rules to apply. The rule `ALL=(ALL) NOPASSWD:ALL` grants the user the ability to run any command with `sudo` without a prompt for a password. + * `ssh_authorized_keys`: A list of public SSH keys to add to the user's `~/.ssh/authorized_keys` file. -3. **Boot and Verify:** Boot the VM with this `user-data`. You should be able to SSH as `sysadmin` and run `sudo` commands. +3. **Boot and verify:** Boot the VM with this `user-data`. You should be able to SSH as `sysadmin` and run `sudo` commands. -**Example 2: Modifying the Default User** +**Example 2: Modifying the default user** A more common task is to simply secure the default user provided with the cloud image (`rocky`). Here, we will modify this user to add our SSH key. -1. **Create `user-data.yml`:** +1. **Create `user-data.yml`:** + ```bash cat < user-data.yml #cloud-config @@ -103,19 +106,21 @@ A more common task is to simply secure the default user provided with the cloud EOF ``` -2. **Key Directives Explained:** - * `default`: This special entry tells `cloud-init` to perform its default user setup first. - * `name: rocky`: By specifying the name of an existing user, the module will modify that user instead of creating a new one. Here, it merges the provided SSH key into the `rocky` user's account. +2. **Key directives explained:** + + * `default`: This special entry tells `cloud-init` to perform its default user setup first. + * `name: rocky`: By specifying the name of an existing user, the module will modify that user instead of creating a new one. Here, it merges the provided SSH key into the `rocky` user's account. -3. **Boot and Verify:** Boot the VM. You can now SSH as the `rocky` user without a password. +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. +The `packages` module provides a declarative way to manage the software on your instance, ensuring the installation of specific applications at boot time. -In this example, we will ensure two useful tools, `nginx` (a high-performance web server) and `htop` (an interactive process viewer), are installed. We will also instruct `cloud-init` to update the package repository metadata first to ensure it can find the latest versions. +In this example, we will ensure the installation of two useful tools, `nginx` (a high-performance web server) and `htop` (an interactive process viewer). We will also instruct `cloud-init` to update the package repository metadata first to ensure it can find the latest versions. + +1. **Create `user-data.yml`:** -1. **Create `user-data.yml`:** ```bash cat < user-data.yml #cloud-config @@ -126,23 +131,25 @@ In this example, we will ensure two useful tools, `nginx` (a high-performance we EOF ``` -2. **Key Directives Explained:** - * `package_update: true`: Instructs the package manager to refresh its local metadata. On Rocky Linux, this is equivalent to running `dnf check-update`. - * `packages`: A list of package names to be installed. +2. **Key directives explained:** + + * `package_update: true`: Instructs the package manager to refresh its local metadata. On Rocky Linux, this is equivalent to running `dnf check-update`. + * `packages`: A list of package names to install. -3. **Boot and Verify:** After booting, SSH in and check that `nginx` is installed with `rpm -q nginx`. +3. **Boot and verify:** After booting, SSH in and check the installation of `nginx` with `rpm -q nginx`. -!!! note "Idempotency in Action" +!!! note "Idempotency in action" 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. To demonstrate its power, we will use `write_files` to create a custom homepage for the `nginx` web server that we are also installing in the same run. -1. **Create `user-data.yml`:** +1. **Create `user-data.yml`:** + ```bash cat < user-data.yml #cloud-config @@ -157,18 +164,19 @@ To demonstrate its power, we will use `write_files` to create a custom homepage EOF ``` -2. **Key Directives Explained:** - * `path`: The absolute path on the filesystem where the file will be written. - * `content`: The text content to be written to the file. - * `owner`: Specifies the user and group that should own the file (e.g., `nginx:nginx`). - * `permissions`: The file permissions in octal format (e.g., `0644`). +2. **Key directives explained:** + + * `path`: The absolute path on the filesystem where the file will write to. + * `content`: The text content to write to the file. + * `owner`: Specifies the user and group that should own the file (e.g., `nginx:nginx`). + * `permissions`: The file permissions in octal format (e.g., `0644`). -3. **Boot and Verify:** After booting, SSH in and use `curl localhost` to see the new homepage. +3. **Boot and verify:** After booting, SSH in and use `curl localhost` to see the new homepage. -!!! tip "Writing Binary Files" +!!! tip "Writing binary files" 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. diff --git a/docs/guides/virtualization/cloud-init/04_advanced_provisioning.md b/docs/guides/virtualization/cloud-init/04_advanced_provisioning.md index 2ae6f52cd5..65d31d94c7 100644 --- a/docs/guides/virtualization/cloud-init/04_advanced_provisioning.md +++ b/docs/guides/virtualization/cloud-init/04_advanced_provisioning.md @@ -1,7 +1,7 @@ --- -title: 4. Advanced Provisioning +title: 4. Advanced provisioning author: Wale Soyinka -contributors: +contributors: Steven Spencer tags: - cloud-init - rocky linux @@ -10,29 +10,30 @@ tags: - networking --- -## Networking and Multi-Part Payloads +## Networking and multi-part payloads -In the previous chapter, you mastered the core `cloud-init` modules for managing users, packages, and files. You can now build a well-configured server declaratively. Now, it's time to explore more advanced techniques that give you even greater control over your instance's configuration. +In the previous chapter, you mastered the core `cloud-init` modules for managing users, packages, and files. You can now build a well-configured server declaratively. Now, it is time to explore more advanced techniques that give you even greater control over your instance's configuration. 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, such as shell scripts and `#cloud-config` files, into a single, powerful payload. -## 1. Declarative Network Configuration +## 1. Declarative network configuration -By default, most cloud images are configured to acquire an IP address via DHCP. While convenient, many production environments require servers to have predictable, static IP addresses. The `cloud-init` network configuration system provides a platform-agnostic, declarative way to manage this. +By default, the configuration of most cloud images is to acquire an IP address by DHCP. While convenient, many production environments require servers to have predictable, static IP addresses. The `cloud-init` network configuration system provides a platform-agnostic, declarative way to manage this. -Network configurations are specified in a separate YAML document from your main `#cloud-config`. `cloud-init` processes both from the same file, using the standard YAML document separator (`---`) to distinguish between them. +The specification of the network configurations is in a separate YAML document from your main `#cloud-config`. `cloud-init` processes both from the same file, using the standard YAML document separator (`---`) to distinguish between them. + +!!! note "How `cloud-init` applies network state" -!!! 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. -1. **Create `user-data.yml`:** +1. **Create `user-data.yml`:** This file contains two distinct YAML documents, separated by `---`. The first is our standard `#cloud-config`. The second defines the network state. @@ -60,16 +61,17 @@ In this exercise, we will configure our virtual machine with a static IP address EOF ``` -2. **Key Directives Explained:** - * `network:`: The top-level key for network configuration. - * `version: 2`: Specifies that we are using the modern, Netplan-like syntax. - * `ethernets:`: A dictionary of physical network interfaces to configure, keyed by the interface name (e.g., `eth0`). - * `dhcp4: no`: Disables DHCP for IPv4 on this interface. - * `addresses`: A list of static IP addresses to assign, specified in CIDR notation. - * `gateway4`: The default gateway for IPv4 traffic. - * `nameservers`: A dictionary containing a list of IP addresses for DNS resolution. +2. **Key directives explained:** + + * `network:`: The top-level key for network configuration. + * `version: 2`: Specifies that we are using the modern, Netplan-like syntax. + * `ethernets:`: A dictionary of physical network interfaces to configure, keyed by the interface name (e.g., `eth0`). + * `dhcp4: no`: Disables DHCP for IPv4 on this interface. + * `addresses`: A list of static IP addresses to assign, specified in CIDR notation. + * `gateway4`: The default gateway for IPv4 traffic. + * `nameservers`: A dictionary containing a list of IP addresses for DNS resolution. -3. **Boot and Verify:** +3. **Boot and verify:** Verification is different this time, as the VM will not get a dynamic IP address. You must connect to the VM's console directly. @@ -90,13 +92,15 @@ In this exercise, we will configure our virtual machine with a static IP address # Once logged in, check the IP address [rocky@network-server ~]$ ip a show eth0 ``` + 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. +A common real-world scenario is a server with multiple network interfaces. Here, we will create a VM with two interfaces: `eth0` will use DHCP, and `eth1` will have a static IP. + +1. **Create `user-data.yml` for two interfaces:** -1. **Create `user-data.yml` for two interfaces:** ```bash cat < user-data.yml #cloud-config @@ -115,7 +119,8 @@ A common real-world scenario is a server with multiple network interfaces. Here, EOF ``` -2. **Boot a VM with two NICs:** We add a second `--network` flag to the `virt-install` command. +2. **Boot a VM with two NICs:** We add a second `--network` flag to the `virt-install` command. + ```bash virt-install --name rocky10-multi-nic \ --memory 2048 --vcpus 2 \ @@ -126,13 +131,13 @@ A common real-world scenario is a server with multiple network interfaces. Here, --os-variant rockylinux10 --import --noautoconsole ``` -3. **Verify:** SSH to the DHCP-assigned address on `eth0` and then check the static IP on `eth1` with `ip a show eth1`. +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. -The structure of a MIME file can be visualized as follows: +You can visualize the structure of a MIME file as follows: ``` +-----------------------------------------+ @@ -157,11 +162,11 @@ 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`. -1. **Create the Multi-Part `user-data.mime` file:** +1. **Create the multi-part `user-data.mime` file:** This is a specially formatted text file that uses a "boundary" string to separate the parts. @@ -192,11 +197,11 @@ We will create a multi-part file that first runs a shell script and then proceed EOF ``` - !!! note "About the MIME Boundary" + !!! 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. @@ -223,7 +228,7 @@ We will create a multi-part file that first runs a shell script and then proceed `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. diff --git a/docs/guides/virtualization/cloud-init/05_image_builders_perspective.md b/docs/guides/virtualization/cloud-init/05_image_builders_perspective.md index 9ebb60efc4..6322a0466c 100644 --- a/docs/guides/virtualization/cloud-init/05_image_builders_perspective.md +++ b/docs/guides/virtualization/cloud-init/05_image_builders_perspective.md @@ -1,7 +1,7 @@ --- -title: 5. The Image Builder's Perspective +title: 5. The image builder's perspective author: Wale Soyinka -contributors: +contributors: Steven Spencer tags: - cloud-init - rocky linux @@ -10,16 +10,16 @@ tags: - image-building --- -## Defaults and Generalization +## Defaults and generalization -So far, our journey has focused on configuring individual instances at boot time using `user-data`. In this chapter, we will shift our perspective to that of an **image builder**—someone who creates and maintains the "golden images" that serve as templates for other virtual machines. +So far, our journey has focused on configuring individual instances at boot time using `user-data`. In this chapter, we will shift our perspective to that of an **image builder**. That is, someone who creates and maintains the "golden images" that serve as templates for other virtual machines. Our goal is to create a new, custom image with our own baked-in policies and defaults. This involves two key processes: -1. **Customizing System-Wide Defaults:** Modifying the `cloud-init` configuration *within the image itself*. -2. **Generalizing the Image:** Using tools like `cloud-init clean` and `virt-sysprep` to strip all machine-specific data, preparing the image for cloning. +1. **Customizing system-wide defaults:** Modifying the `cloud-init` configuration *within the image itself*. +2. **Generalizing the image:** Using tools such as `cloud-init clean` and `virt-sysprep` to strip all machine-specific data, preparing the image for cloning. -## 1. The Customization Lab Setup +## 1. The customization lab setup To begin, we need a running instance of the base cloud image that we can modify. We will boot this VM *without* providing any `user-data` to get a clean system. @@ -37,15 +37,15 @@ 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. +Inside our running VM, we can now customize the system-wide `cloud-init` configuration. You should never edit the master file, `/etc/cloud/cloud.cfg`, 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. +Let us 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. -1. **Create a custom configuration file:** From inside the VM, create `/etc/cloud/cloud.cfg.d/99-custom-defaults.cfg`. The `99-` prefix ensures it is read last. +1. **Create a custom configuration file:** From inside the VM, create `/etc/cloud/cloud.cfg.d/99-custom-defaults.cfg`. The `99-` prefix ensures it is read last. ```bash sudo cat < /etc/cloud/cloud.cfg.d/99-custom-defaults.cfg @@ -68,63 +68,74 @@ Let's enforce a policy on our golden image: we will disable password authenticat EOF ``` -!!! tip "Disabling Specific Modules" -A powerful security technique is to completely disable certain `cloud-init` modules. For example, to prevent any user from ever using `runcmd`, you can add the following to your custom `.cfg` file. This tells `cloud-init` to run an empty list of modules during the final stage. +!!! tip "Disabling specific modules" + + A powerful security technique is to completely disable certain `cloud-init` modules. For example, to prevent any user from ever using `runcmd`, you can add the following to your custom `.cfg` file. This tells `cloud-init` to run an empty list of modules during the final stage. + ```yaml 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 (such as `/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. -1. **Run `cloud-init clean`:** From inside the VM, run the following to strip instance-specific data. +1. **Run `cloud-init clean`:** From inside the VM, run the following to strip instance-specific data. + ```bash sudo cloud-init clean --logs --seed ``` + !!! note "On `cloud-init clean --seed`" + This command removes the unique seed `cloud-init` uses to identify the instance, forcing it to run from scratch on the next boot. It does **not** remove your custom configurations in `/etc/cloud/cloud.cfg.d/`. This step is essential for creating a truly generic template. -2. **Immediately Shut Down:** After cleaning, power off the VM immediately. +2. **Immediately shut down:** After cleaning, power off the VM immediately. + ```bash 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. +An even more thorough, industry-standard tool is `virt-sysprep`. You can run this 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. + +1. **Ensure the VM is shut down.** + +2. **Run `virt-sysprep` from your host:** -1. **Ensure the VM is shut down.** -2. **Run `virt-sysprep` from your host:** ```bash sudo virt-sysprep -a golden-image-template.qcow2 ``` Once the generalization process is complete, the disk file (`golden-image-template.qcow2`) is your new golden image. -!!! note "Golden Image Naming Conventions" +!!! 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`. +Let us test our new image by booting a new instance *from* it without any `user-data`. + +1. **Create a new VM disk from our golden image:** -1. **Create a new VM disk from our golden image:** ```bash qemu-img create -f qcow2 -F qcow2 -b golden-image-template.qcow2 test-instance.qcow2 ``` -2. **Boot the test instance:** +2. **Boot the test instance:** + ```bash virt-install --name golden-image-test --cloud-init none ... ``` -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. +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 the installation of `htop` with (`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. diff --git a/docs/guides/virtualization/cloud-init/06_troubleshooting.md b/docs/guides/virtualization/cloud-init/06_troubleshooting.md index 423a091ad3..3d91f34a7e 100644 --- a/docs/guides/virtualization/cloud-init/06_troubleshooting.md +++ b/docs/guides/virtualization/cloud-init/06_troubleshooting.md @@ -1,7 +1,7 @@ --- title: 6. Troubleshooting cloud-init author: Wale Soyinka -contributors: +contributors: Steven Spencer tags: - cloud-init - rocky linux @@ -14,30 +14,32 @@ tags: In any complex, automated system, things will eventually go wrong. When a `cloud-init` configuration fails, knowing how to systematically diagnose the problem is an essential skill. This chapter is your guide to `cloud-init` forensics, covering both in-guest and on-host troubleshooting techniques. -## 1. In-Guest Troubleshooting Toolkit +## 1. In-guest troubleshooting toolkit When you can access a running instance, `cloud-init` provides several commands and logs to show you what happened. -### Pillar 1: The Status Command (`cloud-init status`) +### Pillar 1: The status command (`cloud-init status`) This is your first port of call. It provides a high-level summary of `cloud-init`'s state. -* **Check if `cloud-init` is done:** `cloud-init status` +* **Check for the completion of `cloud-init`:** `cloud-init status` (A successful run will show `status: done`) -* **Wait for `cloud-init` to finish:** `cloud-init status --wait` + +* **Wait for `cloud-init` to finish:** `cloud-init status --wait` (This is useful in scripts to pause execution until `cloud-init` completes) -### Pillar 2: The Main Log (`/var/log/cloud-init.log`) +### Pillar 2: The main log (`/var/log/cloud-init.log`) This file is the golden source of truth: a detailed, chronological record of every stage and module. When you need to know *exactly* what happened, look here. Searching this file for `ERROR` or `WARNING` will often lead you directly to the problem. -### Pillar 3: The Output Log (`/var/log/cloud-init-output.log`) +### Pillar 3: The output log (`/var/log/cloud-init-output.log`) This log captures the full `stdout` and `stderr` of all scripts executed by `cloud-init` (e.g., from `runcmd`). If a module ran but your script within it failed, the error message will be in this file. -**Hands-On: Debugging a Failing `runcmd`** +**Hands-on: Debugging a failing `runcmd`** + +1. Create a `user-data.yml` with a `runcmd` that has a subtle error: -1. Create a `user-data.yml` with a `runcmd` that has a subtle error: ```bash cat < user-data.yml #cloud-config @@ -45,61 +47,69 @@ This log captures the full `stdout` and `stderr` of all scripts executed by `clo - [ ls, /non-existent-dir ] EOF ``` -2. Boot a VM with this data. `cloud-init status` will report `status: done` because the `runcmd` module itself executed successfully. -3. However, `/var/log/cloud-init-output.log` will contain the actual error from the `ls` command, showing you what failed: + +2. Boot a VM with this data. `cloud-init status` will report `status: done` because the `runcmd` module itself executed successfully. + +3. However, `/var/log/cloud-init-output.log` will contain the actual error from the `ls` command, showing you what failed: + ``` ls: cannot access '/non-existent-dir': No such file or directory ``` -## 2. Host-Side Troubleshooting with `libguestfs-tools` +## 2. Host-side troubleshooting with `libguestfs-tools` -Sometimes, a VM will fail to boot entirely, making in-guest tools useless. In these cases, you can diagnose problems by inspecting the VM's disk image directly from the host using the powerful `libguestfs-tools` suite (install with `sudo dnf install libguestfs-tools`). +Sometimes, a VM will fail to boot entirely, making in-guest tools useless. In these cases, you can diagnose problems by inspecting the VM's disk image directly from the host by using the powerful `libguestfs-tools` suite (install with `sudo dnf install libguestfs-tools`). -### `virt-cat`: Reading Files from a Guest Disk +### `virt-cat`: Reading files from a guest disk -`virt-cat` lets you read files from inside a VM's disk image without mounting it. This is perfect for grabbing log files from a non-booting instance. +`virt-cat` allows for the reading of files from inside a VM's disk image without mounting it. This is perfect for grabbing log files from a non-booting instance. ```bash # From the host, read the cloud-init.log from the VM's disk sudo virt-cat -a /path/to/your-vm-disk.qcow2 /var/log/cloud-init.log ``` -### `virt-inspector`: Deep System Inspection +### `virt-inspector`: Deep system inspection -`virt-inspector` generates a detailed XML report of a VM's OS, applications, and configuration. This is incredibly powerful for automated analysis. +`virt-inspector` generates a detailed XML report of a VM's operating system, applications, and configuration. This is incredibly powerful for automated analysis. + +* **Get a full report:** -* **Get a full report:** ```bash sudo virt-inspector -a your-vm-disk.qcow2 > report.xml ``` -* **Perform a targeted query:** You can pipe the XML to `xmllint` to extract specific information. This example checks the installed version of `cloud-init` inside the image: + +* **Perform a targeted query:** You can pipe the XML to `xmllint` to extract specific information. This example checks the installed version of `cloud-init` inside the image: + ```bash sudo virt-inspector -a your-vm-disk.qcow2 | xmllint --xpath "//application[name='cloud-init']/version/text()" - ``` -## 3. Common Pitfalls and How to Avoid Them +## 3. Common pitfalls and how to avoid them -### Pitfall 1: YAML and Schema Errors +### Pitfall 1: YAML and schema errors Invalid YAML is the most common source of failures. A more advanced problem is a syntactically valid YAML file that violates `cloud-init`'s expected structure (e.g., a typo in a module name). -* **Solution:** Use the `cloud-init schema` command to validate your configuration *before* you boot. It will catch both YAML errors and structural errors. +* **Solution:** Use the `cloud-init schema` command to validate your configuration *before* you boot. It will catch both YAML errors and structural errors. + ```bash # Validate your user-data file against the official schema cloud-init schema --config-file user-data.yml ``` + If the file is valid, it will print `Valid cloud-config: user-data.yml`. If not, it will provide detailed errors. -### Pitfall 2: Network-Dependent Modules Failing +### Pitfall 2: Network-dependent modules failing -If networking fails to come up, modules like `packages` will fail. Check your network configuration and the `Network` stage in `/var/log/cloud-init.log`. +If networking fails to come up, modules such as `packages` will fail. Check your network configuration and the `Network` stage in `/var/log/cloud-init.log`. -## 4. Controlling `cloud-init`'s Execution +## 4. Controlling `cloud-init`'s execution -* **Forcing a Re-run:** To test changes on a running VM, run `sudo cloud-init clean --logs` followed by `sudo reboot`. -* **Disabling `cloud-init`:** To prevent `cloud-init` from running on subsequent boots, create a sentinel file: `sudo touch /etc/cloud/cloud-init.disabled`. -* **Running on Every Boot (`bootcmd`):** Use the `bootcmd` module for scripts that must run on every single boot. This is rare but useful for certain diagnostics. +* **Forcing a re-run:** To test changes on a running VM, run `sudo cloud-init clean --logs` followed by `sudo reboot`. +* **Disabling `cloud-init`:** To prevent `cloud-init` from running on subsequent boots, create a sentinel file: `sudo touch /etc/cloud/cloud-init.disabled`. +* **Running on every boot (`bootcmd`):** Use the `bootcmd` module for scripts that must run on every single boot. This is rare but useful for certain diagnostics. -## What's Next? +## What's next -You are now equipped with a powerful set of tools for both in-guest and on-host troubleshooting. In the final chapter, we will look at the `cloud-init` project itself, preparing you to explore its source code and contribute back to the community. +You are now equipped with a powerful set of tools for both in-guest and on-host troubleshooting. In the final chapter, we will examine the `cloud-init` project itself, preparing you to explore its source code and contribute back to the community. diff --git a/docs/guides/virtualization/cloud-init/07_contributing.md b/docs/guides/virtualization/cloud-init/07_contributing.md index b26f5663b7..ab9ad3c7bc 100644 --- a/docs/guides/virtualization/cloud-init/07_contributing.md +++ b/docs/guides/virtualization/cloud-init/07_contributing.md @@ -1,7 +1,7 @@ --- title: 7. Contributing author: Wale Soyinka -contributors: +contributors: Steven Spencer tags: - cloud-init - open source @@ -13,18 +13,19 @@ tags: Congratulations! You have journeyed from the fundamental concepts of `cloud-init` to advanced provisioning and troubleshooting techniques. You are now a `cloud-init` power user. This final chapter opens the door to the next step in your journey: moving from a consumer of `cloud-init` to a potential contributor. -`cloud-init` is a critical open-source project that thrives on community contributions. Whether it's fixing a typo in the documentation, reporting a bug, or writing a brand-new module, every contribution helps. This chapter provides a high-level map for understanding the source code, building a custom module, and engaging with the upstream community. It is not an exhaustive developer guide, but rather a friendly introduction to getting involved. +`cloud-init` is a critical open source project that thrives on community contributions. Whether it is fixing a typo in the documentation, reporting a bug, or writing a brand-new module, every contribution helps. This chapter provides a high-level map for understanding the source code, building a custom module, and engaging with the upstream community. It is not an exhaustive developer guide, but rather a friendly introduction to getting involved. -## 1. The `cloud-init` Source Code Landscape +## 1. The `cloud-init` source code landscape -Before you can contribute, you need to know your way around the project. Let's explore the source code and set up a basic development environment. +Before you can contribute, you need to know your way around the project. Let us explore the source code and set up a basic development environment. -### The Language and Repository +### The language and repository -`cloud-init` is written almost entirely in **Python**. Its canonical source code repository is hosted on **Launchpad**, but for easier collaboration and a more familiar interface, most contributors interact with its official mirror on **GitHub**. +Written almost entirely in **Python**, Canonical hosts the `cloud-init`source code repository on **Launchpad**, but for easier collaboration and a more familiar interface, most contributors interact with its official mirror on **GitHub**. -* **Canonical Repository (Launchpad):** [https://git.launchpad.net/cloud-init](https://git.launchpad.net/cloud-init) -* **GitHub Mirror:** [https://github.com/canonical/cloud-init](https://github.com/canonical/cloud-init) +* **Canonical repository (Launchpad):** [https://git.launchpad.net/cloud-init](https://git.launchpad.net/cloud-init) + +* **GitHub mirror:** [https://github.com/canonical/cloud-init](https://github.com/canonical/cloud-init) To get the source code, you can clone the GitHub repository: @@ -34,7 +35,7 @@ git clone https://github.com/canonical/cloud-init.git cd cloud-init ``` -### Setting up a Development Environment +### Setting up a development environment To work on the code without affecting your system's Python packages, you should always use a virtual environment. @@ -49,23 +50,23 @@ source .venv/bin/activate pip install -r requirements-dev.txt ``` -### A High-Level Tour of the Source Code +### A high-level tour of the source code Navigating a new codebase can be daunting. Here are the most important directories: -* `cloudinit/`: This is the main Python source directory. -* `cloudinit/sources/`: This directory contains the code for **Datasources** (e.g., `DataSourceNoCloud.py`). This is how `cloud-init` detects and reads configuration from different cloud platforms. -* `cloudinit/config/`: This is where the **Modules** live (e.g., `cc_packages.py`, `cc_users_groups.py`). The `cc_` prefix is a convention for modules that are enabled by `#cloud-config`. This is the most common place for new feature contributions. -* `doc/`: The project's official documentation. Documentation improvements are one of the best ways to make your first contribution. -* `tests/`: The comprehensive test suite for the project. +* `cloudinit/`: This is the main Python source directory. +* `cloudinit/sources/`: This directory contains the code for **Datasources** (e.g., `DataSourceNoCloud.py`). This is how `cloud-init` detects and reads configuration from different cloud platforms. +* `cloudinit/config/`: This is where the **Modules** live (e.g., `cc_packages.py`, `cc_users_groups.py`). The `cc_` prefix is a convention for the modules enabled by `#cloud-config`. This is the most common place for new feature contributions. +* `doc/`: The project's official documentation. Documentation improvements are one of the best ways to make your first contribution. +* `tests/`: The comprehensive test suite for the project. -## 2. Writing a Basic Custom Module +## 2. Writing a basic custom module While `runcmd` is useful, writing a proper module is the best way to create reusable, portable, and idempotent configurations. -Let's create the simplest possible module: one that reads a configuration key from `user-data` and writes a message to the `cloud-init` log. +Let us create the simplest possible module: one that reads a configuration key from `user-data` and writes a message to the `cloud-init` log. -1. **Create the Module File:** Create a new file named `cloudinit/config/cc_hello_world.py`. +1. **Create the module file:** Create a new file named `cloudinit/config/cc_hello_world.py`. ```python # Filename: cloudinit/config/cc_hello_world.py @@ -83,7 +84,7 @@ Let's create the simplest possible module: one that reads a configuration key fr log.info(f"Hello World Module says: {message}") ``` -2. **Enable the Module:** Creating the file isn't enough. You must tell `cloud-init` to run it. Create a file at `/etc/cloud/cloud.cfg.d/99-my-modules.cfg` and add your module to one of the module lists: +2. **Enable the module:** Creating the file is not enough. You must tell `cloud-init` to run it. Create a file at `/etc/cloud/cloud.cfg.d/99-my-modules.cfg` and add your module to one of the module lists: ```yaml # Add our custom module to the list of modules that run during the config stage @@ -91,7 +92,7 @@ Let's create the simplest possible module: one that reads a configuration key fr - hello_world ``` -3. **Use the Module:** Now, you can use the module in your `user-data`. The top-level key (`hello_world`) should match the module name without the `cc_` prefix. +3. **Use the module:** Now, you can use the module in your `user-data`. The top-level key (`hello_world`) should match the module name without the `cc_` prefix. ```yaml #cloud-config @@ -101,32 +102,34 @@ Let's create the simplest possible module: one that reads a configuration key fr After booting a VM with this configuration, you can check `/var/log/cloud-init.log` and you will find your custom message, proving your module worked. -## 3. The Contribution Workflow +## 3. The contribution workflow + +Contributing to an open source project follows a standard workflow. Here is a simplified overview: -Contributing to an open-source project follows a standard workflow. Here is a simplified overview: +1. **Find something to work on:** The best place to start is the project's issue tracker on Launchpad. Look for bugs or feature requests. Newcomers are encouraged to start with documentation fixes or issues tagged as "low-hanging-fruit" or "good first issue". -1. **Find Something to Work On:** The best place to start is the project's issue tracker on Launchpad. Look for bugs or feature requests. Newcomers are encouraged to start with documentation fixes or issues tagged as "low-hanging-fruit" or "good first issue". +2. **Fork and branch:** Create your own copy (a "fork") of the `cloud-init` repository on GitHub. Then, create a new branch for your changes. -2. **Fork and Branch:** Create your own copy (a "fork") of the `cloud-init` repository on GitHub. Then, create a new branch for your changes. ```bash git checkout -b my-documentation-fix ``` -3. **Make Your Changes and Commit:** Make your code or documentation changes. When you commit, write a clear message describing what you did. The `-s` flag adds a `Signed-off-by` line, which certifies that you wrote the patch or have the right to contribute it. +3. **Make your changes and commit:** Make your code or documentation changes. When you commit, write a clear message describing what you did. The `-s` flag adds a `Signed-off-by` line, which certifies that you wrote the patch or have the right to contribute it. + ```bash git commit -s -m "Doc: Fix typo in the users module documentation" ``` -4. **Include Tests:** All significant contributions, especially new features, are expected to include tests. Explore the `tests/` directory to see how existing modules are tested. +4. **Include tests:** All significant contributions, especially new features, must include tests. Explore the `tests/` directory to see how existing modules are tested. -5. **Submit a Pull Request (PR):** Push your branch to your fork on GitHub and open a Pull Request to the `main` branch of the `canonical/cloud-init` repository. This is your formal request to have your work included in the project. +5. **Submit a pull request (PR):** Push your branch to your fork on GitHub and open a Pull Request to the `main` branch of the `canonical/cloud-init` repository. This is your formal request to have your work included in the project. -6. **Engage in Code Review:** Project maintainers will review your PR. They may ask questions or request changes. This is a collaborative process. Engaging with feedback is a key part of contributing to open source. +6. **Engage in code review:** Project maintainers will review your PR. They might ask questions or request changes. This is a collaborative process. Engaging with feedback is a key part of contributing to open source. -### Community Engagement +### Community engagement To learn more, ask questions, and interact with the community, you can join the `#cloud-init` channel on the OFTC IRC network or the official mailing list. -## A Final Word +## A final word -Congratulations on completing this guide. You have progressed from a novice user to a `cloud-init` power user, and now you have a map to guide you into the world of open-source contribution. The `cloud-init` community is welcoming, and your contributions, no matter how small, are valued. Happy building! +Congratulations on completing this guide. You have progressed from a novice user to a `cloud-init` power user, and now you have a map to guide you into the world of open source contribution. The `cloud-init` community is welcoming, and they value your contributions, no matter how small. Happy building! diff --git a/docs/guides/virtualization/cloud-init/index.md b/docs/guides/virtualization/cloud-init/index.md index 07d0bd0569..4c3eaffa4a 100644 --- a/docs/guides/virtualization/cloud-init/index.md +++ b/docs/guides/virtualization/cloud-init/index.md @@ -1,38 +1,38 @@ --- title: 0. cloud-init author: Wale Soyinka -contributors: +contributors: Steven Spencer tags: - cloud-init --- ## Guide to cloud-init on Rocky Linux -Welcome to the comprehensive guide to `cloud-init` on Rocky Linux. This series is designed to take you from the fundamental concepts of cloud instance initialization to advanced, real-world provisioning and troubleshooting techniques. Whether you are a new user setting up your first cloud server or an experienced administrator building custom images, this guide has something for you. +Welcome to the comprehensive guide to `cloud-init` on Rocky Linux. This series takes you from the fundamental concepts of cloud instance initialization to advanced, real-world provisioning and troubleshooting techniques. Whether you are a new user setting up your first cloud server or an experienced administrator building custom images, this guide has something for you. -The chapters are designed to be read sequentially, building on the knowledge from the previous sections. +The design of the chapters is for reading sequentially, building on the knowledge from the previous sections. --- -## Chapters in This Guide +## Chapters in this guide **[1. Fundamentals](./01_fundamentals.md)** -> Learn what `cloud-init` is, why it's essential for cloud computing, and the stages of its execution lifecycle. +> Learn what `cloud-init` is, why it is essential for cloud computing, and the stages of its execution life cycle. -**[2. First Contact](./02_first_contact.md)** +**[2. First contact](./02_first_contact.md)** > Your first hands-on exercise. Boot a cloud image and perform a simple customization using a basic `user-data` file. -**[3. The Configuration Engine](./03_configuration_engine.md)** +**[3. The configuration engine](./03_configuration_engine.md)** > Dive deep into the `cloud-init` module system. Learn to use the most important modules for managing users, packages, and files. -**[4. Advanced Provisioning](./04_advanced_provisioning.md)** +**[4. Advanced provisioning](./04_advanced_provisioning.md)** > Tackle complex scenarios, including how to define static network configurations and how to combine scripts and cloud-configs into a single payload. -**[5. The Image Builder's Perspective](./05_image_builders_perspective.md)** +**[5. The image builder's perspective](./05_image_builders_perspective.md)** > Shift your perspective to that of an image builder. Learn how to create "golden images" with baked-in defaults and how to properly generalize them for cloning. **[6. Troubleshooting](./06_troubleshooting.md)** > Learn the essential art of `cloud-init` forensics. Understand the logs, status commands, and common pitfalls to diagnose and solve problems effectively. **[7. Contributing to cloud-init](./07_contributing.md)** -> Go beyond being a user. This chapter provides a map for understanding the `cloud-init` source code and making your first contribution to the open-source project. \ No newline at end of file +> Go beyond being a user. This chapter provides a map for understanding the `cloud-init` source code and making your first contribution to the open source project.