跳至内容

4. 高级配置

网络和多部分载荷

在上一个章节中,您已掌握了用于管理用户、软件包和文件的核心 cloud-init 模块。现在,您可以声明式地构建一个配置完善的服务器。现在,是时候探索更高级的技术,让您能够更精确地控制实例的配置了。

本章涵盖两个强大、高级的主题:

  1. 声明式网络配置:如何超越 DHCP,为您的实例定义静态网络配置。
  2. 多部分 MIME 载荷:如何将不同类型的用户数据(例如 Shell 脚本和 #cloud-config 文件)合并成一个强大的单一载荷。

1. 声明式网络配置

默认情况下,大多数云镜像的配置是通过 DHCP 获取 IP 地址。虽然方便,但许多生产环境需要服务器拥有可预测的静态 IP 地址。cloud-init 网络配置系统提供了一种独立于平台的声明式方法来管理此问题。

网络配置的规范与您的主 #cloud-config 分开,是一个单独的 YAML 文档。cloud-init 从同一文件中处理两者,使用标准的 YAML 文档分隔符 (---) 来区分它们。

cloud-init 如何应用网络状态

在 Rocky Linux 上,cloud-init 不直接配置网络接口。相反,它充当一个翻译器,将其网络配置转换为 **NetworkManager**(默认网络服务)可以理解的文件。然后,它将控制权交给 NetworkManager 来应用配置。您可以在 /etc/NetworkManager/system-connections/ 中检查生成的连接配置文件。

示例 1:配置单个静态 IP

在本练习中,我们将为虚拟机配置一个静态 IP 地址、默认网关和自定义 DNS 服务器。

  1. 创建 user-data.yml

    此文件包含两个不同的 YAML 文档,由 --- 分隔。第一个是我们标准的 #cloud-config。第二个定义了网络状态。

    cat <<EOF > user-data.yml
    #cloud-config
    # We can still include standard modules.
    # Let's install a network troubleshooting tool.
    packages:
      - traceroute
    
    ---
    
    # This second document defines the network configuration.
    network:
      version: 2
      ethernets:
        eth0:
          dhcp4: no
          addresses:
            - 192.168.122.100/24
          gateway4: 192.168.122.1
          nameservers:
            addresses: [8.8.8.8, 8.8.4.4]
    EOF
    
  2. 关键指令说明

    • network::网络配置的顶级键。
    • version: 2:指定我们正在使用现代的、类似 Netplan 的语法。
    • ethernets::要配置的物理网络接口的字典,以接口名称(例如 eth0)为键。
    • dhcp4: no:在此接口上禁用 IPv4 的 DHCP。
    • addresses:要分配的静态 IP 地址列表,以 CIDR 格式指定。
    • gateway4:IPv4 流量的默认网关。
    • nameservers:包含 DNS 解析 IP 地址列表的字典。
  3. 启动和验证

    这次的验证方式不同,因为虚拟机不会获得动态 IP 地址。您必须直接连接到虚拟机的控制台。

    # Use a new disk image for this exercise
    qemu-img create -f qcow2 -F qcow2 -b Rocky-10-GenericCloud.qcow2 static-ip-vm.qcow2
    
    virt-install --name rocky10-static-ip \
    --memory 2048 --vcpus 2 \
    --disk path=static-ip-vm.qcow2,format=qcow2 \
    --cloud-init user-data=user-data.yml,hostname=network-server \
    --os-variant rockylinux10 \
    --import --noautoconsole
    
    # Connect to the virtual console
    virsh console rocky10-static-ip
    
    # Once logged in, check the IP address
    [rocky@network-server ~]$ ip a show eth0
    

    输出应显示 eth0 具有静态 IP 地址 192.168.122.100/24

示例 2:多接口配置

一个常见的实际场景是具有多个网络接口的服务器。在这里,我们将创建一个具有两个接口的虚拟机:eth0 将使用 DHCP,eth1 将具有静态 IP。

  1. 为两个接口创建 user-data.yml

    cat <<EOF > user-data.yml
    #cloud-config
    packages: [iperf3]
    
    ---
    
    network:
      version: 2
      ethernets:
        eth0:
          dhcp4: yes
        eth1:
          dhcp4: no
          addresses: [192.168.200.10/24]
    EOF
    
  2. 启动具有两个 NIC 的虚拟机: 我们在 virt-install 命令中添加了第二个 --network 标志。

    virt-install --name rocky10-multi-nic \
    --memory 2048 --vcpus 2 \
    --disk path=... \
    --network network=default,model=virtio \
    --network network=default,model=virtio \
    --cloud-init user-data=user-data.yml,hostname=multi-nic-server \
    --os-variant rockylinux10 --import --noautoconsole
    
  3. 验证: 通过 SSH 连接到 eth0 上的 DHCP 分配地址,然后使用 ip a show eth1 检查 eth1 上的静态 IP。

2. 使用多部分 MIME 统一载荷

有时,您需要在主要的 #cloud-config 模块执行之前运行一个设置脚本。MIME 多部分文件是解决方案,它允许您将不同类型的内容打包到一个有序的载荷中。

您可以将 MIME 文件的结构可视化如下:

+-----------------------------------------+
| Main Header (multipart/mixed; boundary) |
+-----------------------------------------+
|
| --boundary                              |
| +-------------------------------------+
| | Part 1 Header (e.g., text/x-shellscript)  |
| +-------------------------------------+
| | Part 1 Content (#/bin/sh...)        |
| +-------------------------------------+
|
| --boundary                              |
| +-------------------------------------+
| | Part 2 Header (e.g., text/cloud-config)   |
| +-------------------------------------+
| | Part 2 Content (#cloud-config...)   |
| +-------------------------------------+
|
| --boundary-- (closing)                  |
+-----------------------------------------+

实践:预检脚本

我们将创建一个多部分文件,该文件首先运行一个 Shell 脚本,然后继续执行主 #cloud-config

  1. 创建多部分 user-data.mime 文件

    这是一个特殊格式的文本文件,它使用“边界”字符串来分隔各个部分。

    cat <<EOF > user-data.mime
    Content-Type: multipart/mixed; boundary="//"
    MIME-Version: 1.0
    
    --//
    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
    
    --//
    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" ]
    
    --//--
    EOF
    

    关于 MIME 边界

    边界字符串(此例中为 //)是一个任意字符串,它不得出现在任何部分的內容中。它用于分隔文件的不同部分。

  2. 启动和验证

    您以与标准 user-data.yml 文件相同的方式将此文件传递给 virt-install

    # Use a new disk image
    qemu-img create -f qcow2 -F qcow2 -b Rocky-10-GenericCloud.qcow2 mime-vm.qcow2
    
    virt-install --name rocky10-mime-test \
    --memory 2048 --vcpus 2 \
    --disk path=mime-vm.qcow2,format=qcow2 \
    --cloud-init user-data=user-data.mime,hostname=mime-server \
    --os-variant rockylinux10 \
    --import --noautoconsole
    

    启动后,SSH 进入虚拟机,并通过查找它们创建的文件来检查两个部分是否都已运行。

    cat /tmp/pre-flight-status.txt
    cat /tmp/main-config-status.txt
    

其他多部分内容类型

cloud-init 支持其他内容类型以应对高级用例,例如用于早期启动脚本的 text/cloud-boothook 或用于运行自定义 Python 代码的 text/part-handler。有关更多详细信息,请参阅官方文档。

下一步

您现在已经学习了两个强大的、高级的 cloud-init 技术。现在,您可以定义静态网络,并通过多部分用户数据来协调复杂的配置工作流程。

在下一章中,我们将视角从按实例“使用” cloud-init 转移到“定制其默认行为”,以创建您自己的预配置“黄金镜像”。

作者:Wale Soyinka

贡献者:Steven Spencer