引言

在最近的发行版(在撰写本文时只有 Ubuntu 14.04和 CentOS 7)上可用的 cloud-init 程序能够使用并执行 DigitalOcean 元数据服务的用户数据字段中的数据。 这个过程的行为取决于它找到的信息的格式。 用户数据中最流行的脚本格式之一是 cloud-config 文件格式。

Cloud-config 文件是为 cloud-init 进程运行而设计的特殊脚本。 这些通常用于服务器第一次启动时的初始配置。 在本指南中,我们将讨论 cloud-config 文件的格式和用法。

关于 Cloud-Config 的一般信息

Cloud-config 格式为许多常见的配置项实现了一种声明性语法,使得完成许多任务变得容易。 它还允许您为任何不在预定义声明性能范围内的内容指定任意命令。

这种“两全其美”的方法允许文件充当常见任务的配置文件,同时为更复杂的功能保持脚本的灵活性。

Yaml 格式化

文件是使用 YAML 数据序列化格式编写的。 Yaml 格式的创建是为了便于人类理解和便于程序解析。

在阅读 YAML 文件时,通常能够相当直观地理解它们,但最好了解管理它们的实际规则。

Yaml 文件的一些重要规则如下:

  • 空格缩进表示项之间的结构和关系。 缩进较多的项是第一个项的子项,其上方的缩进级别较低。
  • 列表成员可以用一个前导破折号来标识。
  • 使用冒号(:)、空格和值创建关联数组条目。
  • 文本块缩进。 若要指示块应按原样读取,并维护格式,请在块之前使用管道字符(|)。

让我们用这些规则来分析一个云配置文件的例子,只注意格式:

#cloud-config
users:
  - name: demo
    groups: sudo
    shell: /bin/bash
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf0q4PyG0doiBQYV7OlOxbRjle026hJPBWD+eKHWuVXIpAiQlSElEBqQn0pOqNJZ3IBCvSLnrdZTUph4czNC4885AArS9NkyM7lK27Oo8RV888jWc8hsx4CD2uNfkuHL+NI5xPB/QT3Um2Zi7GRkIwIgNPN5uqUtXvjgA+i1CS0Ku4ld8vndXvr504jV9BMQoZrXEST3YlriOb8Wf7hYqphVMpF3b+8df96Pxsj0+iZqayS9wFcL8ITPApHi0yVwS8TjxEtI3FDpCbf7Y/DmTGOv49+AWBkFhS2ZwwGTX65L61PDlTSAzL+rPFmHaQBHnsli8U9N6E4XHDEOjbSMRX [email protected]
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcthLR0qW6y1eWtlmgUE/DveL4XCaqK6PQlWzi445v6vgh7emU4R5DmAsz+plWooJL40dDLCwBt9kEcO/vYzKY9DdHnX8dveMTJNU/OJAaoB1fV6ePvTOdQ6F3SlF2uq77xYTOqBiWjqF+KMDeB+dQ+eGyhuI/z/aROFP6pdkRyEikO9YkVMPyomHKFob+ZKPI4t7TwUi7x1rZB1GsKgRoFkkYu7gvGak3jEWazsZEeRxCgHgAV7TDm05VAWCrnX/+RzsQ/1DecwSzsP06DGFWZYjxzthhGTvH/W5+KFyMvyA+tZV4i1XM+CIv/Ma/xahwqzQkIaKUwsldPPu00jRN [email protected]
runcmd:
  - touch /test.txt

通过查看这个文件,我们可以学到一些重要的东西。

首先,每个 cloud-config 文件必须在第一行以 # cloud-config 开头。 这向 cloud-init 程序发出信号,表明应该将其解释为一个 cloud-config 文件。 如果这是一个常规脚本文件,第一行将指示应该用于执行该文件的解释器。

上面的文件有两个顶级指令,用户和 runcmd。 这两者都是钥匙。 这些键的值由键后的所有缩进行组成。

在用户键的情况下,值是单个列表项。 我们之所以知道这一点,是因为下一级缩进是一个破折号(-) ,它指定一个列表项,而且在这一级缩进中只有一个破折号。 对于 users 指令,这意味着我们只定义了一个用户。

列表项本身包含一个具有更多键值对的关联数组。 这些是兄弟元素,因为它们都存在于同一级别的缩进中。 每个用户属性都包含在我们上面描述的单个列表项中。

需要注意的是,您看到的字符串不需要引号,并且没有不必要的方括号来定义关联。 解释器可以相当容易地确定数据类型,并且缩进表示项之间的关系,无论是对于人类还是对于程序。

现在,您应该已经掌握了 YAML 格式的工作知识,并且可以使用我们上面讨论的规则来处理信息。

现在,我们可以开始探索一些最常用的云配置指令。

用户和组管理

要在系统上定义新用户,可以使用我们在上面的示例文件中看到的 users 指令。

用户定义的一般格式如下:

#cloud-config
users:
  - first_user_parameter
    first_user_parameter

  - second_user_parameter
    second_user_parameter
    second_user_parameter
    second_user_parameter

每个新用户都应以破折号开头。 每个用户在键值对中定义参数。 下列键可用于定义:

  • 名称: 帐户用户名。
  • Primary-group: 用户的主要组。 默认情况下,这将是创建的与用户名匹配的组。 这里指定的任何组都必须已经存在或者必须显式创建(我们将在本节后面讨论)。
  • 组: 任何补充组都可以在这里列出,用逗号分隔。
  • Gecos: 关于用户的补充信息的字段。
  • Shell: 应该为用户设置的 shell。 如果不设置这个属性,将使用非常基本的 sh shell。
  • Expiredate: 帐户应该到期的日期,采用 YYYY-MM-DD 格式。
  • Sudo: 如果希望定义 sudo 特权,则使用不带用户名字段的 sudo 字符串。
  • Lock-passwd: 默认设置为“ True”。 将此设置为“ False” ,以允许用户使用密码登录。
  • Passwd: 帐户的散列密码。
  • Ssh-authorized-keys: 应该添加到用户授权密钥文件中的完整 SSH 公钥列表。 Ssh 目录。
  • Inactive: 一个布尔值,它将帐户设置为 inactive。
  • 系统: 如果“真” ,此帐户将是一个没有主目录的系统帐户。
  • Homedir: 用于覆盖默认的 / home / username,否则将创建和设置它。
  • Ssh-import-ID: 从 LaunchPad 导入的 SSH ID。
  • Selinux-user: 这可用于设置应该用于此帐户登录的 SELinux 用户。
  • No-create-home: 设置为“ True”以避免为用户创建 / home / username 目录。
  • No-user-group: 设置为“ True”以避免创建与用户名相同的组。
  • No-log-init: 设置为“ True”以不初始化用户登录数据库。

除了一些基本信息(如 name key)之外,您只需定义偏离默认值或提供所需数据的区域。

对于用户来说,有一点很重要,那就是不应该在生产系统中使用 passwd 字段,除非您具有立即修改给定值的机制。 与所有作为用户数据提交的信息一样,在服务器的整个生命周期中,散列将始终保持系统上的任何用户都可以访问。 在现代硬件上,这些散列很容易在很短的时间内被破解。 即使暴露哈希也是一个巨大的安全风险,不应该在任何非一次性计算机上使用。

对于一个用户定义的例子,我们可以使用我们上面看到的部分 cloud-config 例子:

#cloud-config
users:
  - name: demo
    groups: sudo
    shell: /bin/bash
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf0q4PyG0doiBQYV7OlOxbRjle026hJPBWD+eKHWuVXIpAiQlSElEBqQn0pOqNJZ3IBCvSLnrdZTUph4czNC4885AArS9NkyM7lK27Oo8RV888jWc8hsx4CD2uNfkuHL+NI5xPB/QT3Um2Zi7GRkIwIgNPN5uqUtXvjgA+i1CS0Ku4ld8vndXvr504jV9BMQoZrXEST3YlriOb8Wf7hYqphVMpF3b+8df96Pxsj0+iZqayS9wFcL8ITPApHi0yVwS8TjxEtI3FDpCbf7Y/DmTGOv49+AWBkFhS2ZwwGTX65L61PDlTSAzL+rPFmHaQBHnsli8U9N6E4XHDEOjbSMRX [email protected]
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcthLR0qW6y1eWtlmgUE/DveL4XCaqK6PQlWzi445v6vgh7emU4R5DmAsz+plWooJL40dDLCwBt9kEcO/vYzKY9DdHnX8dveMTJNU/OJAaoB1fV6ePvTOdQ6F3SlF2uq77xYTOqBiWjqF+KMDeB+dQ+eGyhuI/z/aROFP6pdkRyEikO9YkVMPyomHKFob+ZKPI4t7TwUi7x1rZB1GsKgRoFkkYu7gvGak3jEWazsZEeRxCgHgAV7TDm05VAWCrnX/+RzsQ/1DecwSzsP06DGFWZYjxzthhGTvH/W5+KFyMvyA+tZV4i1XM+CIv/Ma/xahwqzQkIaKUwsldPPu00jRN [email protected]

要定义组,您应该使用 groups 指令。 这个指令相对简单,因为它只需要您想要创建的组的列表。

对此的一个可选扩展是为您正在创建的任何组创建一个子列表。 这个新列表将定义应该放置在这个组中的用户:

#cloud-config
groups:
  - group1
  - group2: [user1, user2]

更改现有用户的密码

对于已经存在的用户帐户(根帐户是最相关的) ,可以通过使用 chpasswd 指令来设置密码。

注意: 这个指令只应该在调试情况下使用,因为在服务器的生命周期中,该值对系统上的每个用户都是可用的。 这在本节中更为相关,因为随此指令提交的密码必须以纯文本形式给出。

基本语法如下:

#cloud-config
chpasswd:
  list: |
    user1:password1
    user2:password2
    user3:password3
  expire: False

该指令包含2个关联数组 / 密钥。 列表键将包含一个列出要分配的帐户名和相关密码的块。 过期键是一个布尔值,它决定密码是否必须在第一次启动时更改。 默认值为“ True”。

需要注意的一点是,您可以将密码设置为“ RANDOM”或“ r” ,这将生成一个随机密码并将其写入 / var / log / cloud-init-output。 原木。 请记住,系统上的任何用户都可以访问这个文件,因此它不再安全。

将文件写入磁盘

为了将文件写入磁盘,您应该使用 write files 指令。

应该写入的每个文件都由指令下的列表项表示。 这些列表项将是定义每个文件属性的关联数组。

这个数组中唯一需要的键是路径(定义文件的写入位置)和内容(包含希望文件包含的数据)。

配置写文件项的可用键是:

  • Path: 文件应该被写入的文件系统位置的绝对路径。
  • Content: 应该放在文件中的内容。 对于多行输入,您应该在“ content”行上使用一个管道字符(|)开始一个块,后面跟一个包含内容的缩进块。 二进制文件应该包含“ ! ! “二进制”和管道字符之前的空格。
  • Owner: 应该给予文件所有权的用户帐户和组。 这些应该以“用户名: 组”格式提供。
  • 权限: 应该为此文件提供的八进制权限集。
  • 编码: 文件的可选编码规范。 这可以是“ b64”表示 Base64文件,“ Gzip”表示 Gzip 压缩文件,或者“ gz + b64”表示组合。 省略这一项将使用默认的常规文件类型。

例如,我们可以将一个文件写到 / test.txt,其内容如下:

Here is a line.
Another line is here.

可以实现这一点的 cloud-config 部分如下所示:

#cloud-config
write_files:
  - path: /test.txt
    content: |
      Here is a line.
      Another line is here.

在服务器上更新或安装软件包

要管理包,需要记住一些相关的设置和指令。

要更新基于 debian 的发行版上的 apt 数据库,应该将包 update 指令设置为“ true”。 这与从命令行调用 apt-get update 是同义词。

默认值实际上是“ true” ,因此如果您希望禁用该指令,则只需担心该指令:

#cloud-config
package_update: false

如果您希望在服务器首次启动后升级服务器上的所有包,可以设置包升级指令。 这类似于手动执行 apt-get 升级。

默认设置为“ false” ,所以如果你想要这个功能,确保你设置为“ true” :

#cloud-config
package_upgrade: true

要安装其他软件包,只需使用“ packages”指令列出软件包名称即可。 每个列表项应表示一个包。 与上面的两个命令不同,这个指令将使用 yum 或 apt 托管发行版本来工作。

这些项目可以采取两种形式之一。 第一个是包含包名称的字符串。 第二种形式是包含两个项的列表。 这个新列表的第一项是包名,第二项是版本号:

#cloud-config
packages:
  - package_1
  - package_2
  - [package_3, version_num]

“ packages”指令将 apt update 设置为 true,覆盖以前的任何设置。

为用户帐户和 SSH 守护进程配置 SSH 密钥

您可以在 users 指令中管理 SSH 密钥,但也可以在专门的 SSH 授权密钥部分中指定它们。 这些将被添加到第一个定义的用户的授权密钥文件中。

这与用户指令中的关键规范采用相同的通用格式:

#cloud-config
ssh_authorized_keys:
  - ssh_key_1
  - ssh_key_2

您还可以提前生成 SSH 服务器的私钥并将它们放在文件系统上。 如果您希望事先向客户端提供有关此服务器的信息,从而允许它在服务器上线后立即信任该服务器,那么这将非常有用。

为此,我们可以使用 ssh keys 指令。 这可以使用 RSA private、 RSA public、 DSA private、 DSA public、 ECDSA private 和 ECDSA public 子项获取 RSA、 DSA 或 ECDSA 密钥对。

由于格式化和换行符对于私钥非常重要,因此在指定这些私钥时一定要使用带管道键的块。 此外,必须包括开始键和结束键行,才能使键有效。

#cloud-config
ssh_keys:
  rsa_private: |
    -----BEGIN RSA PRIVATE KEY-----
    your_rsa_private_key
    -----END RSA PRIVATE KEY-----

  rsa_public: your_rsa_public_key

设置受信任的 CA 证书

如果您的基础结构依赖于由内部证书颁发机构签名的密钥,则可以通过注入证书信息来设置新机器以信任 CA 证书。 为此,我们使用 ca-certs 指令。

此指令有两个子项。 第一个是 remove-defaults,当设置为 true 时,它将删除默认包含的所有普通证书信任信息。 这通常是不需要的,并可能导致一些问题,如果你不知道你在做什么,所以使用时要谨慎。

第二个项目是受信任的,它是一个列表,每个列表包含一个受信任的 CA 证书:

#cloud-config
ca-certs:
  remove-defaults: true
  trusted:
    - |
      -----BEGIN CERTIFICATE-----
      your_CA_cert
      -----END CERTIFICATE-----

配置 resolv.conf 以使用特定的 DNS 服务器

如果您已经配置了自己希望使用的 DNS 服务器,则可以使用 resolv conf 指令管理服务器的 resolv.conf 文件。 这目前只适用于基于 rhel- 的发行版。

在 resolv conf 指令下,可以使用名称服务器、搜索域、域和选项项管理设置。

命名服务器指令应该获取名称服务器的 IP 地址列表。 当用户指定主机而不是域时,searchdomains 指令获取要搜索的域和子域的列表。

域设置应该用于任何无法解析的请求的域,选项包含一组可以在 resolv.conf 文件中定义的选项。

如果使用 resolv conf 指令,则必须确保 manage-resolv-conf 指令也设置为 true。 不这样做将导致您的设置被忽略:

#cloud-config
manage-resolv-conf: true
resolv_conf:
  nameservers:
    - 'first_nameserver'
    - 'second_nameserver'
  searchdomains:
    - first.domain.com
    - second.domain.com
  domain: domain.com
  options:
    option1: value1
    option2: value2
    option3: value3

运行任意命令以获得更多控制

如果 cloud-config 提供的托管操作都不能满足您的需要,那么还可以运行任意命令。 可以使用 runcmd 指令完成此操作。

此指令接受要执行的项目列表。 可以用两种不同的方式指定这些项,这将影响它们的处理方式。

如果列表项是一个简单的字符串,那么整个列表项将被传递给 sh shell 进程以便运行。

另一个选项是传递一个列表,其中的每个项目将以类似于 execve 处理命令的方式执行。 第一项将被解释为要运行的命令或脚本,下列项将作为该命令的参数传递。

大多数用户可以使用这两种格式中的任何一种,但是如果您有特殊需求,灵活性使您能够选择最佳的选项。 任何输出都将写入标准输出和 / var / log / cloud-init-output。 日志文件:

#cloud-config
runcmd:
  - [ sed, -i, -e, 's/here/there/g', some_file]
  - echo "modified some_file"
  - [cat, some_file]

关闭或重新启动服务器

在某些情况下,您希望在执行其他项目后关闭或重新启动服务器。 您可以通过设置电源状态指令来实现这一点。

该指令有四个子项可以设置。 这些是延迟、超时、消息和模式。

延迟指定重新启动或关机应该持续多长时间。 默认情况下,这将是“现在” ,这意味着程序将立即开始。 要添加延迟,用户应该使用 + num 的 mins 格式指定应该通过的时间量(以分钟为单位)。

Timeout 参数采用一个无单位的值,该值表示在启动延迟倒计时之前等待 cloud-init 完成的秒数。

Message 字段允许您指定将发送给系统的所有用户的消息。 该模式指定要启动的电源事件的类型。 这可以是“断电”关闭服务器,“重新启动”重新启动服务器,或“暂停”让系统决定哪个是最好的行动(通常是关机) :

#cloud-config
power_state:
  timeout: 120
  delay: "+5"
  message: Rebooting in five minutes. Please save your work.
  mode: reboot

总结

上面的示例代表了在运行 cloud-config 文件时可用的一些更常见的配置项。 还有一些额外的功能我们在本指南中没有涉及。 这些方法包括组态管理 / 服务器设置,配置附加存储库,甚至在服务器初始化时注册一个外部 URL。

您可以通过检查 / usr / share / doc / cloud-init / examples 目录了解其中一些选项的更多信息。 要获得帮助您熟悉 cloud-config 文件的实用指南,您可以按照我们的教程学习如何使用 cloud-config 来完成基本的服务器配置。