跳转到: 导航, 搜索

Heat/Blueprints/native-tools-bootstrap-config

Heat 引导配置

--steve-stevebaker (讨论) 04:36, 12 September 2013 (UTC)

注意:此规范仍在讨论中,尚未获得 heat 项目的认可。

背景

编排服务器引导的目的在于提供足够的软件包安装和配置,以便能够移交给完整的配置管理工具。 传统上,这在 heat 模板中通过 heat-cfntools 包中的 cfn-init 实现,但存在以下问题:

  • 需要从模板 UserData 中显式调用
  • 仅限于提供 cfn 兼容的功能
  • 它作用于与实例资源关联的单个元数据块,这使得编写可组合模板(即,将应用程序配置与应用程序正在编排的架构分开的模板)变得困难。

Heat 当前的基础实现依赖于 cloud-init 在启动时将元数据和 UserData 脚本传递到实例。

此蓝图建议将选定的配置管理工具的功能直接暴露在 heat 模板中,以满足服务器配置任务。

与 HOT 蓝图的关系

蓝图 hot-software-config 被标记为依赖于此蓝图。 然而,实际上这些蓝图是相互依赖的,需要协同发展。

为了本规范的目的,假设

  • 蓝图 native-tools-bootstrap-config 指定了 HOT 组件被服务器/实例资源消耗的内部实现方式,以及 heat 与编排服务器之间的交互
  • 蓝图 hot-software-config 指定了 HOT 组件的语法和语义

然而,本规范认为 HOT 配置组件应该透明地暴露正在使用的任何底层引导/配置管理。 这具有以下好处:

  • 无需创建和维护另一个配置管理抽象
  • Heat 可以明确声明它本身不是配置管理工具,方法是记录它原生支持的工具
  • 使用 YAML 作为其原生格式的配置管理工具具有与 Heat 模板更紧密集成的潜力。

本规范中的 HOT 示例仅用于说明目的,具体内容可能会在最终实现中发生变化。

配置管理工具的组件

可以实现组件来暴露特定配置管理工具的功能。 每个组件的实现都将传递包含配置数据的元数据。 它还将生成适当的 cloud-init 用户数据,以在编排服务器上执行以下操作:

  • 调用该工具以使用提供的配置元数据执行配置

对于这些组件,实际的 cloud-init 用户数据是从抽象的组件数据派生的。 这可能会导致组件仅适用于特定版本的 cloud-init。 在这种情况下,组件作者可以选择支持哪些版本的 cloud-init 并明确记录该信息。

os-collect-config

无论使用哪种配置管理工具,该工具都需要配置数据来操作,并且当该数据发生更改时,需要调用该工具(cloud-init 除外,它仅在启动时调用)。

传统上,heat 通过 cloud-init 传递初始元数据,并且可以使用 cfn-hup 来轮询更改并触发基于这些更改的操作。 os-collect-config 是为 TripleO 项目 编写的一个守护程序,用于轮询元数据并在元数据发生更改时运行配置的 CM 工具。 对于本规范中描述的其余组件,假设 os-collect-config 是获取元数据并在元数据发生更改时调用 CM 工具的工具。

需要考虑的 CM 工具

实现以下工具的某种组合的组件足以将此蓝图标记为已完成:

  • cloud-init
  • heat-cfntools cfn-init
  • os-refresh-config / os-apply-config

其他配置管理工具可以考虑在其自己的蓝图中实现 HOT 组件。 它们包含在本规范中,以展示此 cloud-init 方法的范围可以扩展到多远。 这些工具包括:

  • Puppet
  • Ansible
  • Chef
  • SaltStack
  • Windows PowerShell

组件类型命名空间

由于组件是自包含配置管理的表示,因此组件中没有 OpenStack 特定的内容。 因此,组件类型的顶级命名空间应该是 Heat:: 而不是 OS::Heat::。

Heat::CloudInit

建议每个 Component 的子类都可以将其配置的计算资源提供一些元数据,以及将执行所需配置的 cloud-init 用户数据集合。 CloudInit 组件将通过直接暴露适当的 cloud-init 用户数据类型来做到这一点。 这可能仅限于 #cloud-config 文件和用户数据脚本。

cloud-init 版本兼容性

过去,Heat 在尝试使用较新的 cloud-init 功能时受到阻碍,因为启动的操作系统使用了较旧版本的 cloud-init。 希望通过透明地将 cloud-init 配置暴露到模板中来缓解此问题,以便用户仅使用服务器镜像支持的 cloud-init 功能。

堆栈更新

cloud-init 用于首次启动配置。 这意味着使用不同的 Heat::CloudInit 数据更新堆栈无法应用于正在运行的服务器。 鉴于这种情况,选项是:

  • 不实现 Heat::CloudInit;仅实现用于可以针对服务器的生命周期重复运行的配置管理工具的组件
  • 如果尝试更改现有的 Heat::CloudInit 配置数据,则使服务器 UpdateReplace

示例

cloud-init 示例可以在 HOT 模板中以以下方式表示:

components:
  # Writing out arbitrary files
  write_foo_bar:
    type: Heat::CloudInit
    config:
      cloud_config:
        write_files:
        - encoding: b64
          content: foo_bar_contents
          owner: root:root
          path: /foo/bar
          permissions: '0644'
  # Adding a yum repository
  repo_epel_5_testing:
    type: Heat::CloudInit
    config:
      cloud_config:
        yum_repos:
          epel-testing:
            baseurl: http://download.fedoraproject.org/pub/epel/testing/5/$basearch
            enabled: false
            failovermethod: priority
            gpgcheck: true
            gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL
            name: Extra Packages for Enterprise Linux 5 - Testing
  # Install arbitrary packages
  install_things:
    type: Heat::CloudInit
    config:
      cloud_config:
        packages:
        - pwgen
        - pastebinit
        - [libpython2.7, 2.7.3-0ubuntu3.
  some_user_data:
    # User-Data Script
    type: Heat::CloudInit
    config:
      user_data: |
        #!/bin/sh
        echo "Hello World.  The time is now $(date -R)!" | tee /root/output.txt
...
resources:
  the_server:
    type: OS::Nova::Server
    properties:
      components:
      - name: install_things
      - name: write_foo_bar
        params:         
          foo_bar_contents:
            get_param: the_file_contents
      - name: repo_epel_5_testing
      - name: some_user_data

Heat::SoftwareConfig

Heat 软件配置传统上使用 cfn-init AWS::CloudFormation::Init 元数据执行。 Heat::SoftwareConfig 组件将使用 cfn-init 执行配置管理。 这提供了软件配置的基本表示,但对于许多用户而言,它将满足他们的配置需求。 现有的指南描述了如何创建 heat-cfntools 启用的镜像,并且一些发行版现在将 heat-cfntools 作为云镜像默认安装的一部分进行打包。

我们应该考虑根本不实现此组件,以便引导配置由 Heat::CloudInit 处理,任何进一步的配置都由所选的配置管理组件处理。 在这种情况下,cfn-init 的使用将仅限于与 AWS 兼容的模板。

一个示例用法

components:
  install_mysql:
    type: Heat::SoftwareConfig
    config:
      packages:
        yum:
          mysql: []
          mysql-server: []
      services:
        systemd:
          mysqld: {enabled: 'true', ensureRunning: 'true'}
  install_wordpress:
    type: Heat::SoftwareConfig
    config:
      packages:
        yum:
          httpd: []
          wordpress: []
      services:
        systemd:
          httpd: {enabled: 'true', ensureRunning: 'true'}
  foo_file:
    type: Heat::SoftwareConfig
    config:
      files:
        /tmp/foo/bar:
          content: 'foo_bar_contents'
...
resources:
  the_server:
    type: OS::Nova::Server
    properties:
      components:
      - name: install_mysql
      - name: install_wordpress
      - name: foo_file
        params:         
          foo_bar_contents:
            get_param: the_file_contents

这将为 the_server 提供以下内容:

  • 包含指定配置任务的 cfn-init AWS::CloudFormation::Init 的元数据
  • 一个脚本,由 os-collect-config 执行,该脚本实际运行 /opt/aws/bin/cfn-init

the_server 的所有 Heat::SoftwareConfig 组件将合并到一个 AWS::CloudFormation::Init 元数据单元中。 AWS::CloudFormation::Init configSets 可用于表示每个组件的工作并强制执行它们执行的顺序。 例如,上述 the_server 构建的元数据将是 json 等效的:

AWS::CloudFormation::Init:
  configSets:
    components: [install_mysql, install_wordpress, foo_file]
  install_mysql:
    packages:
      yum:
        mysql: []
        mysql-server: []
    services:
      systemd:
        mysqld: {enabled: 'true', ensureRunning: 'true'}
  install_wordpress:
    packages:
      yum:
        httpd: []
        wordpress: []
    services:
      systemd:
        httpd: {enabled: 'true', ensureRunning: 'true'}
  foo_file:
    files:
      /tmp/foo/bar:
        content: 'foo_bar_contents'

这将由运行 cfn-init -c components 的 os-collect-config 调用

Heat::Config

os-refresh-configos-apply-configTripleO 项目使用的轻量级配置管理工具。

TripleO 强烈倾向于使用黄金镜像,其中以下内容已在启动服务器的镜像上:

  • os-refresh-config、os-apply-config 和 os-collect-config
  • 所有需要安装在服务器上的其他软件包
  • os-refresh-config run-parts 脚本,这些脚本按顺序执行,由元数据更改触发
  • os-apply-config 模板,这些模板将元数据转换为应用程序配置文件

在这种情况下,Heat::Config 组件的唯一目的是在不进行任何修改或 cloud-init 用户数据的情况下传递元数据,例如:

components:
  mysql_configure:
    type: Heat::Config
    config:
      mysql:
        create-users:
          - database: keystone
            username: keystone
            password: KeystoneDBPassword
          - database: heat
            username: heat
            password: HeatDBPassword
...
resources:
  the_server:
    type: OS::Nova::Server
    properties:
      components:
      - name: mysql_configure
        params:
          KeystoneDBPassword:
            get_param: KeystoneDBPassword
          HeatDBPassword:
            get_param: HeatDBPassword

由于 Heat::Config 没有执行带有传递变量的配置脚本的底层工具,因此组件参数 KeystoneDBPassword 和 HeatDBPassword 使用 HOT 函数 fn_replace 样式的替换来替换为它们真实值。 或者,可以修改 os-apply-config 以支持在调用时传递变量。

对于用户无法或不愿使用黄金镜像的情况,Heat::Config 应该能够在缺少已安装软件包、os-refresh-config 脚本和 os-apply-config 模板的原始镜像上工作。 这些可以通过 Heat::CloudInit 组件安装。 考虑以下示例:

components:
  mysql_install:
    type: Heat::CloudInit
    config:
      cloud_config:
        packages:
        - mysql-server-5.5
        - mysql-client-5.5
        write_files:
        - path: /opt/stack/os-apply-config/templates/etc/mysql/dbusers.json
          content: {{mysql.create-users}}
        - path: /opt/stack/os-config-refresh/post-configure.d/50-mysql-users
          permissions: '0755'
          content: |
            #!/usr/bin/python
            # Assert users that came from metadata config
            # ...
  mysql_configure:
    type: Heat::Config
    config:
      mysql:
        create-users:
          - database: keystone
            username: keystone
            password: KeystoneDBPassword
          - database: heat
            username: heat
            password: HeatDBPassword
...
resources:
  the_server:
    type: OS::Nova::Server
    properties:
      components:
      - name: mysql_install
      - name: mysql_configure
        params:
          KeystoneDBPassword:
            get_param: KeystoneDBPassword
          HeatDBPassword:
            get_param: HeatDBPassword

os-apply-config 当前作用于单个顶级元数据块,这意味着需要做出一些设计决策来处理服务器上的多个 Heat::Config 组件。 一些选项是:

  • 浅层或深层合并策略,最终得到一个元数据块来调用 os-config-applier
  • 修改 os-apply-config 以接受要按顺序应用的元数据块列表,而不是单个块

Heat::Puppet

一个允许使用 Puppet 配置服务器的组件,可以通过指定 puppet master 或允许指定 manifest 并启动时应用它来实现。

带有 master 服务器的 Puppet

components:
  puppet_slave:
    type: Heat::Puppet
...
resources:
  the_server:
    type: OS::Nova::Server
    properties:
      components:
      - name: puppet_slave
        params:
          puppet_server:
            get_param: puppet_server
          puppet_certname: "%i.%f"
          puppet_ca_cert:
            get_param: puppet_cert

参数 puppet_server、puppet_certname 和 puppet_ca_cert 将记录为配置 puppet 代理的特殊参数。 Heat::Puppet 实现需要确保如果 puppet_server 在堆栈更新期间发生更改,则服务器上的 puppet 代理将使用新的 puppet_server 进行重新配置。

无服务器 Puppet

components:
  the_component:
    type: Heat::Puppet
    config:
      manifest: |
        file {'testfile':
          path    => '/tmp/testfile',
          ensure  => present,
          mode    => 0640,
          content => $testfile_content,
        }
...
resources:
  the_server:
    type: OS::Nova::Server
    properties:
      components:
      - name: the_component
        params:         
          testfile_content: 'I am a test file.'

由于 puppet 具有 manifest 变量的概念,因此传递到组件参数的值将在调用 manifest 时映射到 puppet 变量。

Heat::Ansible

Ansible 通常被认为是一种无代理配置工具,它通过从调用 playbook 的位置通过 SSH 连接到服务器来配置服务器。 但是,Ansible 还支持 pull-mode playbook,其中每个服务器重复轮询 playbook,并在 playbook 发生更改时以本地模式执行 playbook。

这种操作模式与 Heat 很好地匹配,其中 playbook 可以在启动时通过 cloud-init 传递,并且后续 playbook 的更改可以由 os-collect-config 拾取以重新运行 ansible-playbook。

鉴于 Ansible 是用 python 编写的,并且 playbook 格式是 YAML,因此它具有与 Heat 很好地集成的潜力。

components:
  the_component:
    type: Heat::Ansible
    config:
      user: root
      tasks:
      - name: ensure apache is at the latest version
        yum: pkg=httpd state=latest
      - name: write the apache config file
        template: src=/srv/httpd.j2 dest=/etc/httpd.conf
        notify:
        - restart apache
      - name: ensure apache is running
        service: name=httpd state=started
      handlers:
        - name: restart apache
          service: name=httpd state=restarted
...
resources:
  the_server:
    type: OS::Nova::Server
    properties:
      components:
      - name: the_component
        params:         
          http_port:
            get_param: apache_port
          max_clients: 
            get_param: max_clients

Ansible 也有自己的变量概念,因此与 puppet 一样,可以使用指定的组件参数的值设置变量。