【云道】Heat自动伸缩组功能实现

编辑:chen   来源:FitCloud   科技业界   2017-11-13 11:24:16

Heat简介

Heat 是一个基于模板来编排复合云应用的服务,旨在简化OpenStack云资源的创建和生命周期管理。

Heat目标和愿景

Heat提供基于模板的自动化编排能力。根据模板描述的资源和关系,调用OpenStack其它服务的API实例化资源。

模板用来描述一系列云资源以及资源之间的依赖关系,以便Heat按照某个特定的顺序在OpenStack上创建云资源。

模板支持几乎所有的OpenStack的资源,例如:虚拟机、卷、浮动IP、安全组、网络等,同时也支持高级特性,例如虚拟机高可用、亲和性,伸缩组等。

除了基础设施之外,Heat支持软件部署高级特性。即通过Heat可以为虚拟机安装特有的软件及配置信息。

Heat的模板可复制、可定制,可以方便的在任何OpenStack环境上轻易创建用户应用。

Heat支持用户扩展,及其方便的将用户资源加入到Heat服务中来。

自动伸缩原理

通过Heat创建伸缩组、伸缩策略和告警规则,Ceilometer会监控伸缩组内所有虚拟机相关指标,如果指标达到告警规则门限时,会向伸缩策略发送告警,在接收到告警后,伸缩策略会触发伸缩组进行伸缩。如下图:

实战

本文以WordPress为例,从模板到部署实地操作实现一个自动伸缩的博客系统。

WordPress部署图

在此WordPress系统中,用户通过浮动IP接入WordPress系统;AutoScaling Group包含WordPress服务系统,包含多个虚拟机,在业务负载变化的情况下,可以自动创建或删除虚拟机;DB VM是WordPress的数据库,只有一台虚拟机;ScalingPolicy是伸缩策略,定义伸缩组伸缩的方式;Alarm是告警规则,ceilometer通过Alarm中的alarm_actions来发送告警到ScalingPolicy,触发伸缩组伸缩。

模版

参考链接:

https://github.com/openstack/heat-templates/blob/master/hot/F20/WordPress_2_Instances.yaml

heat_template_version: 2013-05-23

 

description: |

  The heat  template is used to demo the wordpress.

parameters:

   wordpress_image:

    type:  string

     description: image for wordpress auto scaling group.

    default:  ubuntu-server-v2

  db_image:

    type:  string

     description: image for database.

    default:  ubuntu-server-v2

   wordpress_flavor:

    type:  string

     description: flavor for auto scaling.

    default:  m1.small

  db_flavor:

    type:  string

     description: flavor for database.

    default:  m1.small

  ext_net:

    type:  string

     description: network id for floating IP.

    default:  AT_ext_net

  az:

    type:  string

     description: availability zone name.

    default:  nova

  admin_pass:

    type:  string

     description: admin password for VMs.

    default:  1qaz@WSX

    hidden:  true

  db_name:

    type:  string

     description: database name for wordpress.

    default:  wordpress

  db_user:

    type:  string

     description: user name of database.

    default:  root

  db_password:

    type:  string

     description: database password for db_user.

    default:  1qaz@WSX

    hidden:  true

resources:

  network:

    type:  OS::Neutron::Net

    properties:

       admin_state_up: True

      name:  wordpress_network

      shared:  False

  subnet:

    type:  OS::Neutron::Subnet

    properties:

      network:  {get_resource: network}

       allocation_pools: [{"start": 192.168.10.30, "end":  192.168.10.50}, {"start": 192.168.10.100, "end":  192.168.10.130}]

      cidr:  192.168.10.0/24

       enable_dhcp: True

       gateway_ip: 192.168.10.254

      name:  heat_subnet

  router:

    type:  OS::Neutron::Router

    properties:

      admin_state_up:  True

       distributed: False

      ha: False

       external_gateway_info: {"network": {get_param: ext_net}}

  router_interface:

    type:  OS::Neutron::RouterInterface

    properties:

      router:  {get_resource: router}

      subnet:  {get_resource: subnet}

  autoscaling:

    type:  OS::Heat::AutoScalingGroup

    properties:

      min_size:  1

      max_size:  5

      resource:

        type: lb_server.yaml

         properties:

           image_id: { get_param: wordpress_image }

           flavor_id: { get_param: wordpress_flavor }

           subnet_id: {get_resource: subnet}

           pool_id: {get_resource: lb_pool}

          az:  {get_param: az}

           admin_pass: {get_param: admin_pass}

           db_name: {get_param: db_name}

           db_user: {get_param: db_user}

           db_password: {get_param: db_password}

           db_ip: {get_attr: [db_server, first_address]}

          metadata:  {"metering.stack": {get_param: "OS::stack_id"}}

  db_server:

    type:  OS::Nova::Server

    properties:

      image:  {get_param: db_image}

      flavor:  {get_param: db_flavor}

      networks:  [{subnet: {get_resource: subnet}}]

       availability_zone: {get_param: az}

       user_data:

         str_replace:

           template: |

             #!/bin/bash -v

            yum  -y install mariadb mariadb-server

             touch /var/log/mariadb/mariadb.log

             chown mysql.mysql /var/log/mariadb/mariadb.log

             systemctl start mariadb.service

 

            #  Setup MySQL root password and create a user

             mysqladmin -u root password db_rootpassword

            cat  << EOF | mysql -u root --password=db_rootpassword

             CREATE DATABASE db_name;

             GRANT ALL PRIVILEGES ON db_name.* TO "db_user"@"%"

            IDENTIFIED BY  "db_password";

             FLUSH PRIVILEGES;

             EXIT

            EOF

           params:

             db_rootpassword: { get_param: db_password }

             db_name: { get_param: db_name }

            db_user:  { get_param: db_user }

             db_password: { get_param: db_password }

  loadbalancer:

    type:  OS::Neutron::LBaaS::LoadBalancer

    properties:

       vip_subnet: {get_resource: subnet}

      name:  wordpress_lb

  listener:

    type:  OS::Neutron::LBaaS::Listener

    properties:

      name:  wordpress_listener

      protocol:  HTTP

       protocol_port: 80

       loadbalancer: {get_resource: loadbalancer}

  lb_pool:

    type:  OS::Neutron::LBaaS::Pool

    properties:

       lb_algorithm: ROUND_ROBIN

      protocol:  HTTP

      listener:  {get_resource: listener}

  floating_ip:

    type:  OS::Neutron::FloatingIP

    properties:

       floating_network: {get_param: ext_net}

  floating_associate:

    type:  OS::Neutron::FloatingIPAssociation

    properties:

       floatingip_id: {get_resource: floating_ip}

      port_id:  {get_attr: [loadbalancer, vip_port_id]}

  policy_scalingout:

    type:  OS::Heat::ScalingPolicy

    properties:

       adjustment_type: change_in_capacity

       auto_scaling_group_id: {get_resource: autoscaling}

       scaling_adjustment: 1

      cooldown:  60

  policy_scalingin:

    type:  OS::Heat::ScalingPolicy

    properties:

       adjustment_type: change_in_capacity

       auto_scaling_group_id: {get_resource: autoscaling}

       scaling_adjustment: -1

      cooldown:  60

  alarm_cpu_high:

    type:  OS::Aodh::Alarm

    properties:

       meter_name: cpu_util

      period:  60

       evaluation_periods: 1

       statistic: avg

       threshold: 80

       alarm_actions:

        -  {get_attr: [policy_scalingout, alarm_url]}

      comparison_operator: gt

       matching_metadata: {'metadata.user_metadata.stack': {get_param:  "OS::stack_id"}}

  alarm_cpu_low:

    type:  OS::Aodh::Alarm

    properties:

       meter_name: cpu_util

      period:  60

       evaluation_periods: 1

       statistic: avg

       threshold: 30

       alarm_actions:

        -  {get_attr: [policy_scalingin, alarm_url]}

       comparison_operator: lt

      matching_metadata:  {'metadata.user_metadata.stack': {get_param: "OS::stack_id"}}

outputs:

  db_ip:

    value:  {get_attr: [db_server, first_address]}

   wordpress_url:

    value:

      Fn::Join:

      - ''

      - -  http://

        -  {get_attr: [floating_ip, floating_ip_address]}

        -  /wordpress

 

在此模版中,伸缩组以lb_server.yaml作为伸缩的对象,lb_server.yaml定义如下:

嵌套模版lb_server.yaml:

heat_template_version:  2013-05-23

 

description: |

  The heat template is used to create a  server from image.

parameters:

  image_id:

    type: string

    description: The image ID for booting  server.

    default: 1d0d54e7-1998-4a08-834b-5180cab13281

  flavor_id:

    type: string

    description: The flavor ID from booting  server.

    default: m1.small

  subnet_id:

    type: string

    description: The subnet ID for server  nic.

    default:  ea0defc8-0300-46c3-b23f-be7d77f59465

  az:

    type: string

    description: The availability zone name  for server.

    default: nova

  pool_id:

    type: string

    description: The loadbalance pool id fro  member.

    default: no_default

  admin_pass:

    type: string

    description: admin password for VMs.

    hidden: true

  db_name:

    type: string

    description: database name for wordpress.

    default: wordpress

  db_user:

    type: string

    description: user name of database.

    default: root

  db_password:

    type: string

    description: database password for  db_user.

    default: 1qaz@WSX

    hidden: true

  db_ip:

    type: string

     description: database ip.

  metadata:

    type: json

resources:

  server:

    type: OS::Nova::Server

    properties:

      availability_zone: {get_param: az}

      image: { get_param: image_id }

      flavor: { get_param: flavor_id }

      networks: [{subnet: {get_param:  subnet_id}}]

      admin_pass: {get_param: admin_pass}

      metadata: {get_param: metadata}

      user_data_format: RAW

      user_data:

        str_replace:

          template: |

            #!/bin/bash -v

            yum -y install httpd wordpress

            sed -i "/Deny from  All/d" /etc/httpd/conf.d/wordpress.conf

            sed -i "s/Require local/Require  all granted/" /etc/httpd/conf.d/wordpress.conf

            sed -i  s/database_name_here/db_name/ /etc/wordpress/wp-config.php

            sed -i  s/username_here/db_user/       /etc/wordpress/wp-config.php

            sed -i  s/password_here/db_password/   /etc/wordpress/wp-config.php

            sed -i  s/localhost/db_ipaddr/         /etc/wordpress/wp-config.php

            setenforce 0 # Otherwise net  traffic with DB is disabled

            systemctl start httpd.service

          params:

            db_rootpassword: { get_param:  db_password }

            db_name: { get_param: db_name }

            db_user: { get_param: db_user }

            db_password: { get_param:  db_password }

            db_ipaddr: { get_param: db_ip }

  pool_member:

    type: OS::Neutron::LBaaS::PoolMember

    properties:

      address: {get_attr: [server,  first_address]}

      pool: {get_param: pool_id}

      protocol_port: 80

      subnet: {get_param: subnet_id}

 

lb_server.yaml中包含虚拟机和PoolMember,主要目的是创建虚拟机,同时将虚拟机加入到LB中,以达到业务负载均衡的目的。

创建Stack

1.登录OpenStack控制节点;

2.创建保存模版文件的目录:

# mkdir ~/templates

3.进入目录,创建wordpress.yaml文件,复制文档中的wordpress.yaml文件内容到新创建的文件,保存并退出;

4.在同级目录下,创建lb_server.yaml文件,复制文档中的lb_server.yaml文件内容到新创建的文件,保存并退出;

5.用以下命令创建Stack:

# cd ~/templates

# heat stack-create -f wordpress.yaml -P “wordpress_image=xxx; db_image=xxx;  wordpress_flavor=xxx; db_flavor=xxx; ext_net=xxx; az=xxx; admin_pass=xxx;  db_name=xxx; db_user=xxx;  db_password=xxx” WordPressDemo

6.等待Stack创建成功后,用以下命令查看Stack的outputs,wordpress_url就是WordPress访问的入口地址,如下图:

7.用以下命令查看伸缩组内的虚拟机。

# 查询Stack下的伸缩组资源

# heat resource-list WordPressDemo

# 查询autoscaling下的资源

# heat resource-list 4eee662e-d5a6-40c5-98a6-377ae9eea2a0  -n 3

可以看出,在伸缩组内有1台虚拟机,1个PoolMember。

登录WordPress

使用https://10.0.2.117/wordpress链接进入WordPress登陆页面,如下图:

伸缩

在模版中,设置了两个伸缩策略:

1.当CPU平均使用率超过80%时,ceilometer向policy_scaleout发送告警,触发伸缩组创建一台虚拟机;

2.当CPU平均使用率低于30%时,ceilometer向policy_scalein发送告警,触发伸缩组删除一台虚拟机。

为了测试,我们使用heat resource-signal命令模拟ceilometer向policy_scalingout和policy_scalingin两个策略发送告警。

# 触发伸缩组创建一台虚拟机

# heat  resource-signal WordPressDemo policy_scalingout

# 查询嵌套模版下的资源列表

# heat resource-list 4eee662e-d5a6-40c5-98a6-377ae9eea2a0  -n 3

通过查看伸缩组下的资源列表,可以看到有2台虚拟机和2个PoolMember。

# 触发伸缩组删除一台虚拟机

# heat  resource-signal WordPressDemo policy_scalingin

# 查询嵌套模版下的资源列表

# heat resource-list 4eee662e-d5a6-40c5-98a6-377ae9eea2a0  -n 3

通过查看伸缩组下的资源列表,可以看到只剩余1台虚拟机和1个PoolMember。

业务测试

在伸缩操作完成后,我们通过浮动IP访问WordPress,业务功能正常。

总结

Heat提供伸缩组的能力,旨在简化用户的运维操作。Ceilometer根据提供的指标,采集伸缩组内所有虚拟机指标的平均值,在超过阈值时向绑定的ScalingPolicy发送告警;ScalingPolicy定义伸缩组伸缩方式,接收到告警后,触发伸缩组创建或删除虚拟机。

所以在用户应用业务负载变化比较频繁时,可以帮助客户按照负载来自动调整业务虚拟机数量。

参考链接

模版参考: https://github.com/openstack/heat-templates/blob/master/hot/F20/WordPress_2_Instances.yaml

模版版本号及函数参考:https://docs.openstack.org/heat/latest/template_guide/hot_spec.html

模版资源列表:https://docs.openstack.org/heat/latest/template_guide/index.html

嵌套模版编写方式:https://docs.openstack.org/heat/latest/template_guide/composition.html

操作示例:https://docs.openstack.org/heat/latest/install/launch-instance.html

Heat相关命令行参考:https://docs.openstack.org/heat/latest/getting_started/create_a_stack.html

作者简介:

李毅,烽火通信云计算高级软件工程师,一直从事OpenStack编排和告警相关工作,对Heat、Ceilometer、Gnocchi、Senlin服务有较为深入的研究,目前为OpenStack开源社区Senlin项目的core member。

标签: 云计算,type,伸缩,get_param,虚拟机,创建,OS