跳至内容

3. 配置引擎

深入了解 cloud-init 模块

在上一章中,您成功启动了一个云镜像并执行了简单的自定义。虽然有效,但通过其模块系统,您可以真正释放 cloud-init 的强大功能、可移植性和幂等性。这些模块是 cloud-init 工具包中的专用工具,旨在以声明式和可预测的方式处理特定的配置任务。

本章将深入探讨模块系统,解释什么是模块、它们如何工作以及如何使用最核心的模块来构建一个配置良好的服务器。

1. 配置的解剖

什么是 cloud-init 模块

cloud-init 模块是一个专门的 Python 脚本,用于处理单个、离散的配置任务。将它们看作是管理用户、安装软件包或写入文件等任务的插件。

与简单脚本(如 runcmd)相比,使用模块的关键优势在于**幂等性**。幂等操作无论执行一次还是十次,都会产生相同的结果。当您声明一个用户应该存在时,模块会确保满足该状态——如果用户不存在,它会创建用户;如果用户已存在,则不做任何操作。这使得您的配置可靠且可重复。

重新审视 #cloud-config 格式

cloud-init 看到 #cloud-config 头部时,它会将该文件解释为一系列 YAML 格式的指令。此 YAML 文件中的顶级键直接映射到 cloud-init 模块。

模块执行和顺序

模块在引导过程的特定阶段按 /etc/cloud/cloud.cfg 中定义的顺序运行。此流程的简化视图如下所示:

System Boot
    |
    +--- Stage: Generator (Very early boot)
    |    `--- cloud_init_modules (e.g., migrator)
    |
    +--- Stage: Local (Pre-network)
    |    `--- (Modules for local device setup)
    |
    +--- Stage: Network (Network is up)
    |    `--- cloud_config_modules (e.g., users-groups, packages, write_files)
    |
    `--- Stage: Final (Late boot)
         `--- cloud_final_modules (e.g., runcmd, scripts-user)

顺序至关重要。例如,users-groups 模块在 runcmd 之前运行,确保脚本可以由在同一配置中刚创建的用户运行。

自定义 cloud-init 行为

虽然 /etc/cloud/cloud.cfg 定义了默认行为,但您永远不应该直接编辑它。对于持久的、系统范围的自定义,请将您自己的 .cfg 文件放在 /etc/cloud/cloud.cfg.d/ 目录中。这是构建自定义镜像的标准做法,我们将在后面的章节中探讨。

2. 高效模块:日常驱动程序

让我们通过使用 virt-install 的直接注入方法来实际操作最常见的模块。

模块深入:usersgroups

妥善管理用户帐户是保护新服务器实例的基石。users 模块是您进行此操作的主要工具,它允许您创建新用户、修改现有用户、管理组成员身份,最重要的是,注入 SSH 密钥以在首次引导时实现安全、无密码登录。

示例 1:创建一个新的管理员用户

在此示例中,我们将配置一个名为 sysadmin 的新专用管理用户。我们将通过将该用户添加到 wheel 组并提供特定的 sudo 规则来授予该用户无密码 sudo 能力。我们还将注入一个 SSH 公钥以确保安全访问。

  1. 创建 user-data.yml

    cat <<EOF > user-data.yml
    #cloud-config
    users:
      - name: sysadmin
        groups: [ wheel ]
        sudo: [ "ALL=(ALL) NOPASSWD:ALL" ]
        shell: /bin/bash
        ssh_authorized_keys:
          - <YOUR_SSH_PUBLIC_KEY_HERE>
    EOF
    
  2. 关键指令说明

    • name:新帐户的用户名。
    • groups:将用户添加到的组列表。在 Rocky Linux 上,通常使用 wheel 组成员身份来授予管理权限。
    • sudo:要应用的 sudoers 规则列表。规则 ALL=(ALL) NOPASSWD:ALL 允许用户在提示输入密码的情况下运行任何 sudo 命令。
    • ssh_authorized_keys:添加到用户 ~/.ssh/authorized_keys 文件的 SSH 公钥列表。
  3. 引导和验证:使用此 user-data 引导 VM。您应该能够以 sysadmin 身份 SSH 登录并运行 sudo 命令。

示例 2:修改默认用户

更常见的任务是简单地保护云镜像(rocky)提供的默认用户。在这里,我们将修改该用户以添加我们的 SSH 密钥。

  1. 创建 user-data.yml

    cat <<EOF > user-data.yml
    #cloud-config
    users:
      - default
      - name: rocky
        ssh_authorized_keys:
          - <YOUR_SSH_PUBLIC_KEY_HERE>
    EOF
    
  2. 关键指令说明

    • default:此特殊条目告诉 cloud-init 首先执行其默认用户设置。
    • name: rocky:通过指定现有用户的名称,模块将修改该用户而不是创建新用户。在这里,它将提供的 SSH 密钥合并到 rocky 用户的帐户中。
  3. 引导和验证:引导 VM。您现在可以以 rocky 用户身份无密码 SSH 登录。

模块深入:packages

packages 模块提供了一种声明式的方法来管理实例上的软件,确保在引导时安装特定的应用程序。

在此示例中,我们将确保安装两个有用的工具 nginx(高性能 Web 服务器)和 htop(交互式进程查看器)。我们还将指示 cloud-init 首先更新软件包存储库元数据,以确保它可以找到最新版本。

  1. 创建 user-data.yml

    cat <<EOF > user-data.yml
    #cloud-config
    package_update: true
    packages:
      - nginx
      - htop
    EOF
    
  2. 关键指令说明

    • package_update: true:指示软件包管理器刷新其本地元数据。在 Rocky Linux 上,这等同于运行 dnf check-update
    • packages:要安装的软件包名称列表。
  3. 引导和验证:引导后,SSH 登录并使用 rpm -q nginx 检查 nginx 的安装情况。

幂等性在行动

如果您使用相同的 user-data 重新引导此 VM,packages 模块将看到 nginxhtop 已安装,不会采取进一步行动。它确保所需状态(软件包存在)而无需不必要的操作。这就是幂等性。

模块深入:write_files

此模块功能非常强大,允许您将任何文本内容写入系统上的任何文件。它是部署应用程序配置文件、填充 Web 内容或创建辅助脚本的理想工具。

为了展示其强大功能,我们将使用 write_files 来创建 nginx Web 服务器的自定义主页,该 Web 服务器也在同一次运行中进行安装。

  1. 创建 user-data.yml

    cat <<EOF > user-data.yml
    #cloud-config
    packages: [nginx]
    write_files:
      - path: /usr/share/nginx/html/index.html
        content: '<h1>Hello from cloud-init!</h1>'
        owner: nginx:nginx
        permissions: '0644'
    runcmd:
      - [ systemctl, enable, --now, nginx ]
    EOF
    
  2. 关键指令说明

    • path:文件将在文件系统上写入的绝对路径。
    • content:要写入文件的文本内容。
    • owner:指定文件的所有者用户和组(例如 nginx:nginx)。
    • permissions:文件权限(以八进制格式表示,例如 0644)。
  3. 引导和验证:引导后,SSH 登录并使用 curl localhost 查看新主页。

写入二进制文件

write_files 模块不仅限于文本。通过指定 encoding,您可以部署二进制文件。例如,您可以使用 encoding: b64 来写入 base64 编码的数据。有关高级用例,请参阅官方 write_files 文档

下一步

您现在已经掌握了三个最基本的 cloud-init 模块。通过组合它们,您可以执行大量的自动化服务器配置。在下一章中,我们将处理更高级的场景,包括网络配置以及在同一次运行中组合不同的 user-data 格式。

作者:Wale Soyinka

贡献者:Steven Spencer