OpenStack编排服务

Heat(编排服务)简介

Heat是一个使用声明性模板格式,通过OpenStack 原生 REST API 编排复合云应用程序的服务。

Heat模板指定了资源之间的关系(例如,某个卷连接到某个实例)。这样,Heat 就可以调用 OpenStack API,以正确的顺序创建所有基础设施,从而完全启动应用程序。开发人员能够在程序中使用模板以实现资源的自动化部署。

Heat特点

  • 标准化和可重复性:使用 Heat 可以将基础设施和应用程序的配置标准化为模板,在不同环境中重复使用,确保配置的一致性和可重复性。

  • 简化复杂性:定义资源之间的依赖关系和配置规则,简化复杂的资源编排过程,减少手动操作和错误。

  • 弹性和可伸缩性:通过定义资源组和循环实现资源的弹性扩展和收缩,根据需求自动调整资源。

  • 可视化和审计:提供堆栈拓扑图的可视化功能,记录堆栈的操作和资源状态变化,用于跟踪和审计。

Heat基本概念

  • 堆栈(stack):管理资源的集合,单个模板中定义的实例化资源的集合,是 Heat 管理应用程序的逻辑单元,往往对应一个应用程序。

  • 模板(template):描述了所有组件资源以及组件资源之间的关系,是 Heat 的核心。

  • 资源(resource):将在编排期间创建或修改的对象,可以是网络、路由器、子网、实例、卷、浮动IP、安全组等。

Heat架构

1701649019123.png
  • heat command-line client:CLI 通过与 heat-api 通信,来调用 API 实现相关功能。

  • heat-api:实现 OpenStack 原生支持的 REST API,通过把 API 请求经由 AMQP 传送给 Heat engine 来处理 API 请求。

  • heat-engine:执行模板内容,完成应用系统的创建和部署,并把执行结果返回给 API 调用者。

Heat命令

1701649471789.png

Heat编排实验

作业与实验环境

超星网址
使用虚拟机openstack-allinone,账户root,密码000000

  1. VmWare 网络设置

    在编辑->虚拟网络编辑器中将 Vmnet1 网卡的子网由原来的 192.168.10.0 改为 192.168.100.0

    1701610472777.png
  2. 上传镜像

    Horizon 登录地址 192.168.100.10/dashboard,使用域 xiandian、用户名 admin、密码 000000 登录,上传本地的 cirros 镜像到 OpenStack 平台:

    1701650465473.png
  3. 执行身份认证

    # 加载管理员认证环境变量,后续 openstack/heat 命令会自动使用
    [root@controller ~]# source /etc/keystone/admin-openrc.sh

通过模板启动一个堆栈

  1. 创建模板文件

    新建模板文件 demo.yaml 并将以下内容保存:

    heat_template_version: 2015-04-30
    description: Heat 编排示例
    
    resources:
      # 创建私有网络
      my_network:
        type: OS::Neutron::Net
        properties:
          name: private-iso-net
    
      # 创建私有子网
      my_subnet:
        type: OS::Neutron::Subnet
        properties:
          name: private-iso-net-subnet
          network_id: { get_resource: my_network }
          # 子网网段(CIDR 格式)
          cidr: 192.168.200.0/24
          # 网关 IP 地址
          gateway_ip: 192.168.200.1
          # DNS 服务器地址
          dns_nameservers: ["114.114.114.114", "8.8.8.8"]
          ip_version: 4
          # 启用 DHCP,自动分配 IP
          enable_dhcp: true
  2. 创建堆栈

    根据模板文件创建堆栈:

    # 创建堆栈(-t 指定模板文件,test_net 为堆栈名)
    # 堆栈会按模板顺序创建私有网络与子网
    [root@controller ~]# openstack stack create -t demo.yaml test_net
    +---------------------+-----------------------------------------------------------------+
    | Field               | Value                                                           |
    +---------------------+-----------------------------------------------------------------+
    | id                  | be89980b-a28e-4110-97d4-1b7a0284b045                            |
    | stack_name          | test_net                                                        |
    | description         | Create an isolated private network and subnet without a router. |
    | creation_time       | 2025-12-03T19:04:48                                             |
    | updated_time        | None                                                            |
    | stack_status        | CREATE_IN_PROGRESS                                              |
    | stack_status_reason |                                                                 |
    +---------------------+-----------------------------------------------------------------+
    
    # 查看堆栈资源,确认各资源状态(查看名称、ID、类型、状态)
    [root@controller ~]# openstack stack resource list test_net
    +---------------+--------------------------------------+---------------------+-----------------+---------------------+
    | resource_name | physical_resource_id                 | resource_type       | resource_status | updated_time        |
    +---------------+--------------------------------------+---------------------+-----------------+---------------------+
    | my_subnet     | a93cdcce-ba23-4743-bb95-dcf15ca18897 | OS::Neutron::Subnet | CREATE_COMPLETE | 2025-12-03T20:09:57 |
    | my_network    | 35f5a966-3f0e-496c-94cb-36e9ac600755 | OS::Neutron::Net    | CREATE_COMPLETE | 2025-12-03T20:09:57 |
    +---------------+--------------------------------------+---------------------+-----------------+---------------------+
    
    # 查看网络列表
    [root@controller ~]# openstack network list
    +--------------------------------------+-----------------+--------------------------------------+
    | ID                                   | Name            | Subnets                              |
    +--------------------------------------+-----------------+--------------------------------------+
    | c4c7e383-ade0-4d50-bf55-1b56dcf45fa7 | private-iso-net | 1bb613ed-8062-4e40-9614-4d90892fbfbc |
    +--------------------------------------+-----------------+--------------------------------------+
    
    # 查看子网列表
    [root@controller ~]# openstack subnet list    
    +--------------------------------------+------------------------+--------------------------------------+------------------+
    | ID                                   | Name                   | Network                              | Subnet           |
    +--------------------------------------+------------------------+--------------------------------------+------------------+
    | 1bb613ed-8062-4e40-9614-4d90892fbfbc | private-iso-net-subnet | c4c7e383-ade0-4d50-bf55-1b56dcf45fa7 | 192.168.200.0/24 |
    +--------------------------------------+------------------------+--------------------------------------+------------------+

    作业1:执行 openstack stack resource list test_net 查看堆栈资源列表后截图。

  3. 删除堆栈

    删除堆栈后,相应的资源会被自动删除:

    # 删除堆栈(y 确认后会级联删除模板创建的资源)
    [root@controller ~]# openstack stack delete test_net
    Are you sure you want to delete this stack(s) [y/N]? y
    [root@controller ~]# 
    
    # 验证子网已删除
    [root@controller ~]# openstack subnet list          
    
    # 验证网络已删除
    [root@controller ~]# openstack network list          
    
    [root@controller ~]# 
  4. 添加云主机资源

    编写以下模板内容保存到 demo.yaml 文件中 resources 下,和 my_network 以及 my_subnet 平级:

    # 创建云主机实例
    my_instance:
      type: OS::Nova::Server
      properties:
        name: my-test-instance
        # 指定镜像和规格
        image: cirros
        flavor: m1.small
        # 指定网络
        networks:
          - network: { get_resource: my_network }
  5. 重新创建堆栈

    重新创建堆栈,包含网络、子网和云主机:

    # 创建堆栈,包含网络、子网和云主机资源
    [root@controller ~]# openstack stack create -t demo.yaml test
    +---------------------+--------------------------------------+
    | Field               | Value                                |
    +---------------------+--------------------------------------+
    | id                  | f24806af-af0b-4bd4-a756-1f6eb032f086 |
    | stack_name          | test                                 |
    | description         | No description                       |
    | creation_time       | 2025-12-03T20:12:57                  |
    | updated_time        | None                                 |
    | stack_status        | CREATE_IN_PROGRESS                   |
    | stack_status_reason |                                      |
    +---------------------+--------------------------------------+
    
    # 查看资源列表,确认实例、网络、子网均创建完成
    [root@controller ~]# openstack stack resource list test
    +---------------+--------------------------------------+---------------------+-----------------+---------------------+
    | resource_name | physical_resource_id                 | resource_type       | resource_status | updated_time        |
    +---------------+--------------------------------------+---------------------+-----------------+---------------------+
    | my_instance   | 08379aaa-e2f9-4b03-82e7-44c486b8f26b | OS::Nova::Server    | CREATE_COMPLETE | 2025-12-03T20:12:57 |
    | my_subnet     | 4fcba899-bb37-48ad-b7a4-39764701060b | OS::Neutron::Subnet | CREATE_COMPLETE | 2025-12-03T20:12:57 |
    | my_network    | 644c93f6-c62a-4393-ad5e-b1f085c51ab0 | OS::Neutron::Net    | CREATE_COMPLETE | 2025-12-03T20:12:57 |
    +---------------+--------------------------------------+---------------------+-----------------+---------------------+
  6. 查看实例运行状态

    在 Horizon 上查看实例运行状态:

    1701651161368.png

    或者通过 OpenStack 命令查看实例列表:

    # 列出当前项目中的云主机
    [root@controller ~]# openstack server list
    +--------------------------------------+--------------------------------------+--------+---------------------+
    | ID                                   | Name                                 | Status | Networks            |
    +--------------------------------------+--------------------------------------+--------+---------------------+
    | 2324c631-cf3e-49eb-a8e2-be384341e4ac | demo-struct-my_instance-clk6vt6fuwe4 | ACTIVE |                     |
    +--------------------------------------+--------------------------------------+--------+---------------------+

    作业2:在原有模板内添加实例资源后创建堆栈,使用openstack stack resource list test查看堆栈资源列表后截图。

  7. 删除堆栈

    # 删除包含实例的堆栈
    [root@controller ~]# openstack stack delete test
    Are you sure you want to delete this stack(s) [y/N]? y

模板文件基本构成

一个典型的 Heat 模板包含以下部分:

heat_template_version: 2015-04-30

description: Simple template to deploy a single compute instance

resources:
  my_instance:
    type: OS::Nova::Server
    properties:
      image: cirros
      flavor: m1.small
  • heat_template_version:每个模板文件必须要包含的键,值是具体的版本号(如 2013-05-23),参考 Heat template version list 获取版本号。

  • description:可选的键,用来描述模板所执行操作,支持多行文本。

  • resources:必须要包含的键,至少需要定义一个 resource,例子中定义了一个实例资源并包含了若干个属性。

模板文件的输入参数

模板文件中的 parameters 段允许用户在构建的过程中自定义模板。比如用户可以提供 镜像ID实例类型 来构建堆栈,通过输入参数可以使得模板更容易重用。

  1. 引入数据参数

    以下是一个引入数据参数的模板示例,参考修改上文的 demo.yaml 文件:

    heat_template_version: 2015-04-30
    
    description: Simple template to deploy a single compute instance
    
    parameters:
      # 定义镜像参数
      image_id:
        type: string
        label: Image ID
        description: Image to be used for compute instance
      # 定义实例类型参数
      flavor:
        type: string
        label: Instance Type
        description: Type of instance (flavor) to be used
    
    resources:
      my_instance:
        type: OS::Nova::Server
        properties:
          # 使用 get_param 获取用户提供的镜像参数
          image: { get_param: image_id }
          # 使用 get_param 获取用户提供的规格参数
          flavor: { get_param: flavor }

    模板中的参数必须在构建堆栈的过程中提供,get_param 内建函数检索用户所提供的值并用于相关属性。

  2. 通过传递参数创建堆栈

    # 传参创建堆栈(--parameter 注入镜像与规格参数)
    [root@controller ~]# openstack stack create -t demo.yaml demo-struct --parameter image_id=cirros --parameter flavor=m1.small
    +---------------------+-----------------------------------------------------+
    | Field               | Value                                               |
    +---------------------+-----------------------------------------------------+
    | id                  | f3ab8bbe-f769-495f-88db-46a6a373aa22                |
    | stack_name          | demo-struct                                         |
    | description         | Simple template to deploy a single compute instance |
    | creation_time       | 2023-12-04T09:24:14                                 |
    | updated_time        | None                                                |
    | stack_status        | CREATE_IN_PROGRESS                                  |
    | stack_status_reason |                                                     |
    +---------------------+-----------------------------------------------------+
  3. 设置默认参数

    给模板设置默认参数,默认参数可以当用户没有提供参数时用来构建堆栈。参考代码片段修改 demo.yaml 文件:

    parameters:
      flavor:
        type: string
        label: Instance Type
        description: Flavor to be used
        # 设置默认值
        default: m1.small

    当模板中没有设置默认参数时,用户必须提供所有参数,否则堆栈就会创建失败。

  4. 使用默认参数创建堆栈

    修改完以上片段后只提供 image 参数来启动一个堆栈:

    # 仅提供镜像参数(--parameter 注入参数)
    # flavor 使用模板中的默认值 m1.small
    [root@controller ~]# openstack stack create -t demo.yaml demo-struct --parameter image_id=cirros
    +---------------------+-----------------------------------------------------+
    | Field               | Value                                               |
    +---------------------+-----------------------------------------------------+
    | id                  | 1765bf8d-f792-4ac7-b842-664773fa79c1                |
    | stack_name          | demo-struct                                         |
    | description         | Simple template to deploy a single compute instance |
    | creation_time       | 2023-12-04T09:38:36                                 |
    | updated_time        | None                                                |
    | stack_status        | CREATE_IN_PROGRESS                                  |
    | stack_status_reason | Stack CREATE started                                |
    +---------------------+-----------------------------------------------------+

    作业3:使用默认参数的方式启动堆栈后上传截图。

  5. 限制参数值

    对于用户输入的参数可以进行限制。通过在 parameters 段中添加 constraints 属性并定义一个列表来限制用户输入的参数,参考以下片段修改 demo.yaml

    parameters:
        flavor:
            type: string
            label: Instance Type
            description: Type of instance (flavor) to be used
            # 限制参数的允许值
            constraints:
            - allowed_values: [ m1.medium, m1.large, m1.xlarge ]
              description: Value must be one of m1.medium, m1.large or m1.xlarge.

    除了直接对参数的值做限制以外还可以使用多个条件进行限制,以下是一个限制指定创建数据库密码的参数的示例:

    parameters:
        database_password:
            type: string
            label: Database Password
            description: Password to be used for database
            # 隐藏密码输入
            hidden: true
            # 设置多个约束条件
            constraints:
            # 限制密码长度(6-8 位)
            - length: { min: 6, max: 8 }
              description: Password length must be between 6 and 8 characters.
            # 限制密码只能包含字母和数字
            - allowed_pattern: "[a-zA-Z0-9]+"
              description: Password must consist of characters and numbers only.
            # 限制密码必须以大写字母开头
            - allowed_pattern: "[A-Z]+[a-zA-Z0-9]*"
              description: Password must start with an uppercase character.

编写一个模板文件

参考以下代码编写一个模板文件,实现从卷启动实例:

resources:
  # 创建可启动的卷(包含操作系统)
  bootable_volume:
    type: OS::Cinder::Volume
    properties:
      size: 10
      image: ubuntu-trusty-x86_64

  # 从卷启动实例
  instance:
    type: OS::Nova::Server
    properties:
      flavor: m1.small
      networks:
        - network: private
      # 配置块设备映射,从卷启动
      block_device_mapping:
        - device_name: vda
          # 指定启动卷
          volume_id: { get_resource: bootable_volume }
          # 实例删除时不删除卷
          delete_on_termination: false

作业4:进入实例的控制台后截图上传。