Cloud-Config脚本简介
介绍
在最近的发行版上可用的 cloud-init
程序(在撰写本文时只有 Ubuntu 14.04 和 CentOS 7)能够使用和执行来自 DigitalOcean 的 user-data
字段的数据元数据服务。 这个过程的行为会有所不同,具体取决于它找到的信息格式。 user-data
中最流行的脚本格式之一是 cloud-config 文件格式。
Cloud-config 文件是旨在由 cloud-init 进程运行的特殊脚本。 这些通常用于服务器首次启动时的初始配置。 在本指南中,我们将讨论 cloud-config 文件的格式和用法。
关于 Cloud-Config 的一般信息
cloud-config
格式为许多常见的配置项实现了声明式语法,可以轻松完成许多任务。 它还允许您为超出预定义声明功能的任何内容指定任意命令。
这种“两全其美”的方法让该文件充当常见任务的配置文件,同时保持脚本的灵活性以实现更复杂的功能。
YAML 格式
该文件使用 YAML 数据序列化格式编写。 YAML 格式的创建是为了便于人类理解和易于程序解析。
YAML 文件在阅读时通常很容易理解,但最好了解管理它们的实际规则。
YAML 文件的一些重要规则是:
- 带有空格的缩进表示项目之间的结构和关系。 更多缩进的项目是第一个项目的子项目,它们上方的缩进级别较低。
- 列表成员可以通过前导破折号来标识。
- 通过使用冒号 (:) 后跟空格和值来创建关联数组条目。
- 文本块是缩进的。 要指示应按原样读取块,并保持格式不变,请在块前使用竖线字符 (|)。
让我们以这些规则来分析一个示例 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 user@example.com - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcthLR0qW6y1eWtlmgUE/DveL4XCaqK6PQlWzi445v6vgh7emU4R5DmAsz+plWooJL40dDLCwBt9kEcO/vYzKY9DdHnX8dveMTJNU/OJAaoB1fV6ePvTOdQ6F3SlF2uq77xYTOqBiWjqF+KMDeB+dQ+eGyhuI/z/aROFP6pdkRyEikO9YkVMPyomHKFob+ZKPI4t7TwUi7x1rZB1GsKgRoFkkYu7gvGak3jEWazsZEeRxCgHgAV7TDm05VAWCrnX/+RzsQ/1DecwSzsP06DGFWZYjxzthhGTvH/W5+KFyMvyA+tZV4i1XM+CIv/Ma/xahwqzQkIaKUwsldPPu00jRN user@desktop runcmd: - touch /test.txt
通过查看这个文件,我们可以了解到许多重要的事情。
首先,每个 cloud-config
文件必须在第一行单独以 #cloud-config
开头。 这向 cloud-init 程序发出信号,表明它应该被解释为 cloud-config
文件。 如果这是一个常规脚本文件,第一行将指示应该用于执行该文件的解释器。
上面的文件有两个顶级指令,users
和 runcmd
。 这些都用作键。 这些键的值由键后的所有缩进行组成。
在 users
键的情况下,该值是单个列表项。 我们知道这一点是因为下一级缩进是一个破折号 (-),它指定了一个列表项,并且因为在这个缩进级别只有一个破折号。 在 users
指令的情况下,这顺便表明我们只定义了一个用户。
列表项本身包含一个具有更多键值对的关联数组。 这些是兄弟元素,因为它们都存在于相同的缩进级别。 每个用户属性都包含在我们上面描述的单个列表项中。
需要注意的是,您看到的字符串不需要引用,并且没有不必要的括号来定义关联。 解释器可以相当容易地确定数据类型,并且缩进指示项目之间的关系,无论是对于人类还是程序。
到目前为止,您应该已经掌握了 YAML 格式的工作知识,并且可以轻松地使用我们上面讨论的规则来处理信息。
我们现在可以开始探索 cloud-config
的一些最常见的指令。
用户和组管理
要在系统上定义新用户,您可以使用我们在上面的示例文件中看到的 users
指令。
用户定义的一般格式是:
#cloud-config users: - first_user_parameter first_user_parameter - second_user_parameter second_user_parameter second_user_parameter second_user_parameter
每个新用户都应该以破折号开头。 每个用户在键值对中定义参数。 以下键可用于定义:
- name:账号用户名。
- primary-group:用户的主组。 默认情况下,这将是一个与用户名匹配的组。 此处指定的任何组必须已经存在或必须显式创建(我们将在本节后面讨论)。
- groups:此处可以列出任何补充组,以逗号分隔。
- gecos:关于用户的补充信息字段。
- shell:应该为用户设置的shell。 如果不设置,将使用非常基本的
sh
shell。 - expiredate:账户到期的日期,格式为YYYY-MM-DD。
- sudo:如果您想定义 sudo 权限,则使用 sudo 字符串,不带用户名字段。
- lock-passwd:默认设置为“True”。 将此设置为“False”以允许用户使用密码登录。
- passwd:帐户的哈希密码。
- ssh-authorized-keys:完整的 SSH 公钥列表,应添加到该用户的
authorized_keys
文件中,位于其.ssh
目录中。 - inactive:一个布尔值,将帐户设置为非活动状态。
- system:如果为“True”,则此帐户将是没有主目录的系统帐户。
- 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
键,您只需要定义偏离默认值或提供所需数据的区域。
对用户来说重要的一件事是 passwd
字段应该 not 用于生产系统,除非您有立即修改给定值的机制。 与作为用户数据提交的所有信息一样,在服务器的整个生命周期内,系统上的 any 用户都可以访问散列。 在现代硬件上,这些哈希值很容易在很短的时间内被破解。 甚至暴露哈希也是一个巨大的安全风险,不应该在任何非一次性机器上承担。
对于示例用户定义,我们可以使用上面看到的示例 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 user@example.com - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcthLR0qW6y1eWtlmgUE/DveL4XCaqK6PQlWzi445v6vgh7emU4R5DmAsz+plWooJL40dDLCwBt9kEcO/vYzKY9DdHnX8dveMTJNU/OJAaoB1fV6ePvTOdQ6F3SlF2uq77xYTOqBiWjqF+KMDeB+dQ+eGyhuI/z/aROFP6pdkRyEikO9YkVMPyomHKFob+ZKPI4t7TwUi7x1rZB1GsKgRoFkkYu7gvGak3jEWazsZEeRxCgHgAV7TDm05VAWCrnX/+RzsQ/1DecwSzsP06DGFWZYjxzthhGTvH/W5+KFyMvyA+tZV4i1XM+CIv/Ma/xahwqzQkIaKUwsldPPu00jRN user@desktop
要定义组,您应该使用 groups
指令。 该指令相对简单,因为它只需要您要创建的组列表。
对此的可选扩展是为您正在创建的任何组创建一个子列表。 这个新列表将定义应该放在这个组中的用户:
#cloud-config groups: - group1 - group2: [user1, user2]
更改现有用户的密码
对于已经存在的用户帐户(root
帐户是最相关的),可以使用 chpasswd
指令来提供密码。
注意:在调试情况下应该only使用该指令,因为再一次,在服务器的生命周期内,系统上的每个用户都可以使用该值。 这在本节中更加相关,因为使用此指令提交的密码必须以 纯文本 给出。
基本语法如下所示:
#cloud-config chpasswd: list: | user1:password1 user2:password2 user3:password3 expire: False
该指令包含两个关联数组键。 list
键将包含一个块,其中列出了您要分配的帐户名称和相关密码。 expire
键是一个布尔值,用于确定是否必须在首次启动时更改密码。 这默认为“真”。
需要注意的一点是,您可以将密码设置为“RANDOM”或“R”,这将生成一个随机密码并将其写入 /var/log/cloud-init-output.log
。 请记住,系统上的任何用户都可以访问此文件,因此它不再安全。
将文件写入磁盘
为了将文件写入磁盘,您应该使用 write_files
指令。
应该写入的每个文件都由指令下的列表项表示。 这些列表项将是定义每个文件属性的关联数组。
此数组中唯一需要的键是 path
,它定义了写入文件的位置,以及 content
,它包含您希望文件包含的数据。
用于配置 write_files
项目的可用键是:
- path:文件系统上应写入文件的位置的绝对路径。
- content:应该放在文件中的内容。 对于多行输入,您应该通过在“内容”行上使用竖线字符 (|) 开始一个块,然后是包含内容的缩进块。 二进制文件应包含“!!binary”和管道字符前的空格。
- owner:应该被赋予文件所有权的用户帐户和组。 这些应该以“用户名:组”格式给出。
- permissions:应该为此文件提供的八进制权限集。
- encoding:文件的可选编码规范。 这可以是 Base64 文件的“b64”、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 数据库,您应该将 package_update
指令设置为“true”。 这与从命令行调用 apt-get update
同义。
默认值实际上是“true”,所以如果你想禁用它,你只需要担心这个指令:
#cloud-config package_update: false
如果您希望在服务器首次启动后升级所有软件包,您可以设置 package_upgrade
指令。 这类似于手动执行的 apt-get upgrade
。
默认情况下设置为“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_authorized_keys
部分中指定它们。 这些将被添加到第一个定义的用户的 authorized_keys 文件中。
这采用与 users
指令中的密钥规范相同的一般格式:
#cloud-config ssh_authorized_keys: - ssh_key_1 - ssh_key_2
您还可以提前生成 SSH 服务器的私钥并将它们放在文件系统上。 如果您想事先向您的客户提供有关此服务器的信息,这将很有用,允许它在服务器上线后立即信任该服务器。
为此,我们可以使用 ssh_keys
指令。 这可以使用 rsa_private
、rsa_public
、dsa_private
、dsa_public
、ecdsa_private
获取 RSA、DSA 或 ECDSA 密钥的密钥对, 和 ecdsa_public
子项。
由于格式和换行对私钥很重要,因此在指定这些时请确保使用带有管道键的块。 此外,您 必须 包括开始键和结束键行,您的键才有效。
#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 时,将删除默认包含的所有正常证书信任信息。 这通常不是必需的,如果您不知道自己在做什么,可能会导致一些问题,因此请谨慎使用。
第二项是trusted
,它是一个列表,每个都包含一个受信任的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
指令下,您可以使用 nameservers
、searchdomains
、domain
和 options
项目管理您的设置。
nameservers
指令应该包含您的名称服务器的 IP 地址列表。 当用户指定主机但未指定域时,searchdomains
指令获取要搜索的域和子域列表。
domain
设置应该用于任何无法解析的请求的域,并且 options
包含一组可以在 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.log
文件:
#cloud-config runcmd: - [ sed, -i, -e, 's/here/there/g', some_file] - echo "modified some_file" - [cat, some_file]
关闭或重新启动服务器
在某些情况下,您需要在执行其他项目后关闭或重新启动服务器。 您可以通过设置 power_state
指令来做到这一点。
该指令有四个可以设置的子项。 它们是 delay
、timeout
、message
和 mode
。
delay
指定在未来多长时间内应该重新启动或关闭。 默认情况下,这将是“现在”,这意味着程序将立即开始。 要添加延迟,用户应使用 +<num_of_mins>
格式指定应经过的时间量(以分钟为单位)。
timeout
参数采用无单位值,表示在启动 delay
倒计时之前等待 cloud-init 完成的秒数。
message
字段允许您指定将发送给系统所有用户的消息。 mode
指定要启动的电源事件的类型。 这可以是“poweroff”来关闭服务器,“reboot”来重新启动服务器,或者“halt”来让系统决定哪个是最佳操作(通常是关闭):
#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 完成基本服务器配置 的教程进行操作。