OpenStack系列(二十一) 编写Heat模板
1 | 作者:李晓辉 |
你知道 Heat Orchestration Template Syntax(HOT 模板语法)那事儿不?这可是云运维人员和开发人员打交道时用到的“秘密武器”。云运维人员要搞定云开发者的应用,有时候得去调试或者修改那些编排配置,说不定还得解决错误,或者提升应用性能、让应用能更好地扩展。OpenStack 的编排服务(Heat)就是用 YAML 结构来写 HOT 文件的。
YAML 现在超流行,网上能找到超多参考资料。它用空格缩进,绝对不能用制表符,用来表示实体、组件、参数和属性之间的层级关系。它把括号和标签都去掉了,看起来很“人类友好”。
大多数文本编辑器都支持 YAML,还能设置自动用空格。比如 Red Hat Enterprise Linux 自带的 gedit 编辑器,你可以把“用空格代替制表符”这个选项勾上。要是用 vim 编辑器,就得在隐藏的配置文件里设置。要是想让 YAML 文件编辑自动缩进、设置制表符宽度、缩进宽度,还有把制表符展开成空格,就在 ~/.vimrc 文件里加上这行:
1 | autocmd FileType yaml setlocal ai ts=2 sw=2 et |
HOT 模板在声明版本和描述之后,结构大概就是这样的:一个有效的模板至少得定义一个要创建的资源,其他部分都是可选的。
parameter_groups:就是把输入参数分组、排序。
parameters:声明创建堆栈时需要提供的输入参数。
resources:声明堆栈里要创建的独一无二的资源。
outputs:声明创建堆栈后要提供给用户的输出参数。
conditions:用来限制在什么情况下创建资源。
模板的版本
对了,还得说说模板版本。每次 OpenStack 大版本更新,HOT 的功能和语法都会升级。你可以用任何一个版本的 HOT 特性来创建和维护模板,但得记住,一个堆栈用的所有模板和环境文件得是同一个版本,还得在模板里声明 heat_template_version。就像下面这样,最近的版本要么用版本字符串里的日期,要么用 OpenStack 发行版本名来指定。
1 | (overcloud) [stack@director ~]$ openstack orchestration template version list |
HOT 模板里有个可选的 description
键,可以用它来说明这个模板是干嘛用的。如果描述内容比较多,可以用一个 >
符号放在那一行,这样就能写多行文本了。
比如这样:
1 | heat_template_version: queens |
定义输⼊参数
这可是让 HOT 模板变得灵活和可复用的关键一步!在模板开头声明参数,这样就可以在创建具体堆栈的时候,通过一个单独的环境文件传入值,覆盖默认设置。
参数的定义包括一些必要的属性,比如类型、标签、描述、默认值、是否隐藏、约束条件,还有是否不可变。具体长这样:
1 | parameters: |
type:支持的数据类型有字符串、数字、JSON、逗号分隔的列表,还有布尔值。
default:如果没有传入值覆盖它,就用这个默认值。
hidden:如果设置为
true
,参数值就不会显示在创建的堆栈信息里。constraints:这个是用来验证输入参数值的,可以设置多种约束条件。
immutable:如果设置为
true
,一旦声明了参数值,就不能再改了。要是尝试修改,堆栈创建或者更新就会失败。
参数的名字和类型是必须的,其他的属性都是可选的。hidden
和 immutable
默认都是 false
。还有一个 custom_constraints
属性,它可以通过编排插件来增加资源验证。比如在这个例子中,约束条件用了一个叫 cinder.volume
的插件,来验证块存储卷是否存在:
1 | parameters: |
定义资源
接下来是定义资源的部分。每个要创建的资源都是一个独立的嵌套块,包含它的必要属性和属性值,结构大概是这样:
1 | resources: |
resource ID:这是用户定义的、在堆栈中唯一的资源名称。
type:OpenStack 的核心资源类型都包含在编排引擎里。编排还支持资源插件,可以用来提供自定义的资源处理,或者覆盖内置的资源实现。
properties:这个属性用来指定与资源类型相关的属性。属性值可以是硬编码的,也可以用内置函数来获取。
如果你想查看你的 overcloud 上可用的资源类型,可以用下面的命令。
1 | (overcloud) [stack@director ~]$ openstack orchestration resource type list |
如果你想看看某个资源类型的结构,可以用 openstack orchestration resource type show
命令。比如,你想看看负载均衡器成员资源的属性,可以这样操作:
1 | (overcloud) [stack@director ~]$ openstack orchestration resource type show OS::Octavia::PoolMember |
输出会显示资源的属性,比如 address
属性可能有一个 custom_constraint
,要求它必须是一个有效的 IP 地址。
如果想创建多个相同类型的资源,可以用 OS::Heat::ResourceGroup
资源类型。比如,你想创建两个相同的虚拟机实例,可以这样定义:
在这个例子中,count
设置为 2,表示创建两个实例。resource_def
定义了要创建的资源类型和属性。
1 | resources: |
如果需要为每个实例生成唯一名称,可以用 %index%
变量。比如,你想创建 4 个 Web 服务器实例,每个实例的名称都带有编号,可以这样定义:
1 | resources: |
这样,创建的实例名称会是:
webserver0.overcloud.example.com
webserver1.overcloud.example.com
webserver2.overcloud.example.com
webserver3.overcloud.example.com
内置函数
在编排模板中,内置函数是用来在堆栈创建时为定义的属性赋值的。
get_attr
get_attr
函数用来获取资源的属性值。比如,你想获取某个实例的 IP 地址:
1 | resources: |
get_param
get_param
函数用来获取输入参数的值。比如,你想用输入参数设置虚拟机的规格:
1 | parameters: |
get_resource
get_resource
函数用来获取模板中的资源。比如,你想把一个端口资源的 ID 设置为虚拟机的网络端口:
1 | resources: |
str_replace
str_replace
函数用来替换字符串。比如,你想用实例的 IP 地址生成一个 URL:
1 | outputs: |
list_join
list_join
函数用来把多个字符串拼接成一个字符串,中间可以用指定的分隔符分隔。比如,你想把实例名称和随机字符串拼接起来:
1 | resources: |
定义等待条件
在创建堆栈时,有些资源可能需要在某些条件满足后才真正算创建完成。比如,你可能希望在虚拟机上下载并配置好应用程序之后,才认为虚拟机创建完成。这时候,等待条件(Wait Conditions)就派上用场了。
等待条件的作用是暂停堆栈创建过程,直到某个条件完成并发出信号。模板中定义等待条件的任务,以及一个自动生成的 URL(称为等待条件句柄),任务可以通过这个 URL 发送状态。
等待条件的处理过程大概是这样的:
创建等待条件和句柄:在堆栈创建时,等待条件和句柄会被创建,堆栈状态会显示为“创建中”(CREATE_IN_PROGRESS)。堆栈会等待收到成功信号(或者超时)。
执行任务并发送状态:任务会按照定义的流程执行,并通过句柄发送“成功”(SUCCESS)或“失败”(FAILURE)状态。
判断状态:
如果在超时之前收到足够的“成功”信号,等待条件状态变为“创建完成”(CREATE_COMPLETE),堆栈创建继续。
如果超时或者收到“失败”状态,等待条件状态变为“创建失败”(CREATE_FAILED),堆栈创建终止。
示例
定义一个等待条件句柄(OS::Heat::WaitConditionHandle
),它没有可配置的属性:
1 | example_wait_handle: |
然后定义一个等待条件(OS::Heat::WaitCondition
),指定句柄、超时时间和需要接收的成功信号数量:
1 | example_wait_condition: |
最后,在虚拟机的 user_data
脚本中,通过 curl
向句柄发送状态信号:
1 | example_server: |
实例配置方法
在部署实例时,有三种常见的方法可以用来配置软件:
1. 自定义 Glance 镜像
如果你在整个实例生命周期中不需要更改软件配置,可以直接使用一个已经安装并配置好软件的自定义镜像。这种方法最简单,但灵活性最低。
2. user_data 脚本
使用 user_data
脚本和 cloud-init
来配置实例中的预安装软件。这种方法适用于在实例启动时进行一次性的软件配置更改。如果需要更改配置,必须重新创建实例。
例如:
1 | resources: |
如果需要更复杂的脚本,可以用 get_file
函数从文件中获取脚本内容:
1 | resources: |
3. SoftwareDeployment 资源
OS::Heat::SoftwareDeployment
资源类型允许在实例生命周期内多次更改软件配置,而无需重新部署实例。这种方法适用于需要频繁更改软件配置的场景。
要使用 SoftwareDeployment
,需要定义以下三种资源:
- OS::Heat::SoftwareConfig:定义软件配置,可以与多种配置管理工具(如脚本、Ansible、Puppet)配合使用。每次更改配置时,会用新的配置替换旧的配置。
1 | resources: |
- OS::Nova::Server:定义要应用软件配置更改的实例。
user_data_format
属性需要设置为SOFTWARE_CONFIG
。
1 | resources: |
- OS::Heat::SoftwareDeployment:将定义的
SoftwareConfig
应用到实例上。可以通过input_values
设置输入变量的值。
1 | resources: |
软件部署代理
使用 SoftwareDeployment
方法时,需要在实例上安装编排代理(orchestration agents),以便收集和处理配置更改。通常,这些代理会安装在实例镜像中。根据需要,可以安装以下代理包:
python-heat-agent
:支持 Shell 脚本。python-heat-agent-ansible
:支持 Ansible Playbooks。python-heat-agent-puppet
:支持 Puppet 清单。
下面这些代理工具的作用就是帮助在实例上应用软件配置更改。
1. os-collect-config
这个工具的作用是定期轮询编排(Orchestration)API,查看是否有针对服务器资源类型的更新后的资源元数据。简单来说,它就像是一个“侦查员”,不停地去检查有没有新的配置指令发过来。
工作原理:它会定期检查,看看是否有新的配置需要应用到实例上。
应用场景:当你通过 Heat(OpenStack 的编排服务)更新了某个实例的配置时,
os-collect-config
会检测到这些变化。
2. os-refresh-config
这个工具的作用是刷新实例的配置。它会删除旧的配置,并用新的配置替换掉。你可以把它想象成一个“更新管理员”,负责把旧的东西清理掉,然后换上新的。
工作原理:它会清理掉实例上旧的配置文件或设置,然后根据最新的元数据应用新的配置。
应用场景:当你需要对实例进行配置更新时,
os-refresh-config
会确保实例上的配置是最新的。
3. heat-config
这个工具的作用是安装一个 os-refresh-config
脚本,并调用适当的钩子(hooks)来执行配置。它就像是一个“启动器”,负责启动整个配置更新的过程。
工作原理:它会安装必要的脚本,并确保这些脚本能够正确地触发配置更新。
应用场景:当你需要在实例上启动一个配置更新流程时,
heat-config
会负责初始化这个过程。
4. heat-config-hook
这个工具的作用是根据关联的组(group)使用正确的钩子来应用配置更改。它就像是一个“执行者”,负责具体实施配置更改。
工作原理:它会根据配置中定义的组(比如使用 Shell 脚本、Ansible 或 Puppet)选择正确的钩子来应用配置。
应用场景:当你定义了一个配置任务(比如运行一个 Shell 脚本),
heat-config-hook
会确保这个任务被正确执行。
5. heat-config-notify
这个工具的作用是通知编排 API 配置部署是否成功。它就像是一个“汇报员”,负责把配置的结果反馈回去。
工作原理:它会向 Heat API 发送一个信号,告知配置是否成功应用。
应用场景:当配置更新完成后,
heat-config-notify
会告诉 Heat:“嘿,配置已经完成了,这是结果!”
它们是如何协同工作的
想象一下,你有一个虚拟机实例,需要更新它的软件配置。以下是这些工具协同工作的过程:
os-collect-config 检测到 Heat API 发来的更新指令。
os-refresh-config 开始清理旧的配置,并准备应用新的配置。
heat-config 启动整个更新流程,安装必要的脚本。
heat-config-hook 根据配置类型(比如 Shell 脚本),选择正确的钩子来执行配置任务。
heat-config-notify 在配置完成后,向 Heat API 发送信号,告知结果。