Overview:

OpenStack Heat can deploy and configure multiple instances in one command using resources we have in OpenStack. That’s called a Heat Stack.

Heat will create instances from images using existing flavors and networks. It can configure LBaaS and provide VIPs for our load-balanced instances. It can also use the metadata service to inject files, scripts or variables after instance deployment. It can use Ceilometer to create alarms based on instance CPU usage and associate actions like spinning up or terminating instances based on CPU load.

OpenStack provides Auto-scaling features through Heat. This feature reduces the need to manually provision instance capacities in advance. You can use Heat resources to detect when a Ceilometer alarm triggers and provision or de-provision a new VM depending on the trigger. These groups of VMs must be under a Load-balancer which distributes the load among the VMs on the scaling group.

Whether you are running one instance or thousands, you can use Autoscaling to detect, increase, decrease, and replace instances without manual intervention.

In the document, the following two policies are defined:

a) When the CPU utilization rate is above 50%, a new instance is created automatically until the number of instances reaches 4.

b) When any CPU utilization rate is below 15%, an instance is terminated until the number of instances reaches 2.

Autoscaling in Heat is done with the help of three main types:

OS::Heat::AutoScalingGroup

An AutoScalingGroup is a resource type that is used to encapsulate the resource that we wish to scale, and some properties related to the scale process.

OS::Heat::ScalingPolicy

A ScalingPolicy is a resource type that is used to define the effect a scale process will have on the scaled resource.

OS::Ceilometer::Alarm

An Alarm is a resource type the is used to define under which conditions the ScalingPolicy should be triggered.

 

Deploying a WordPress Application Stack with an Autoscaling group of Web servers and a Load-balancer.

Complete templates are available in here

The following example uses a snapshot of a VM with Apache already installed and configured over an Ubuntu operating system as a base image.

Parameters:

key_name:
type: string
description: Name of an existing key pair to use for the template
default: dev
image:
type: string
description: Name of image to use for servers
default: ubuntu
flavor:
type: string
description: Flavor to use for servers
default: m1.small
db_name:
type: string
description: WordPress database name
default: wordpress
db_username:
type: string
description: The WordPress database admin account username
default: admin
db_password:
type: string
description: The WordPress database admin account password
default: admin
db_rootpassword:
type: string
description: Root password for MySQL
default: admin
hidden: true
public_net_id:
type: string
description: ID of public n/w for which floating IP will be allocated
default: 7645e3f6-444d-4e4b-ad4f-a9cf49683b2d
private_net_id:
type: string
description: ID of private network into which servers get deployed
default: e232d0c0-4363-4b39-b88a-949e177f058a
private_subnet_id:
type: string
description: ID of private sub network into which servers get deployed
default: a0cf224b-1f42-4650-b219-b9320d4ea06f 

The first resource one will provision is the health monitor configuration that will check the virtual machines under the Load-balancer. If the machine is down, the Load-balancer will not send traffic to it. Create the pool using the health monitor and specifying the protocol, the network and subnet, the algorithm to use for distributing the traffic, and the port that will receive the traffic on the virtual IP. Finally, create the Load-balancer using this pool.

Resources: 
  monitor:
     type: OS::Neutron::HealthMonitor
properties:
     type: TCP
    delay: 3
max_retries: 3
  timeout: 3

lb_vip_port:
     type: OS::Neutron::Port
     properties:
     network_id: { get_param: private_net_id }
     fixed_ips:
     - subnet_id: { get_param: private_subnet_id }

lb_pool_vip:
    type: OS::Neutron::FloatingIPAssociation
    properties:
    floatingip_id: { get_resource: lb_vip_floating_ip }
    port_id: { 'Fn::Select': ['port_id', {get_attr: [pool, vip]}]}

pool:
    type: OS::Neutron::Pool
    properties:
    protocol: HTTP
    monitors: [{get_resource: monitor}]
    subnet_id: {get_param: private_subnet_id}
    lb_method: ROUND_ROBIN
    vip:
    protocol_port: 80

lb:
    type: OS::Neutron::LoadBalancer
    properties:
    protocol_port: 80
    pool_id: {get_resource: pool} 

Associate a public IP for the Load-balancer so that it can be accessed from the Internet. Use the following syntax to create a floating IP for the Load-balancer:

lb_vip_floating_ip:
type: OS::Neutron::FloatingIP
properties:
floating_network_id: { get_param: public_net_id }
port_id: { get_resource: lb_vip_port }

Use the following syntax to create the Auto-scaling group (VMs) which will be acting as the web servers for the WordPress application:

web_server_group:
type: OS::Heat::AutoScalingGroup
properties:
min_size: 2
max_size: 4
resource:
type: Lib::INF::LB
properties:
flavor: {get_param: flavor}
image: {get_param: image}
key_name: dev
pool_id: {get_resource: pool}
metadata: {"metering.server_group": {get_param: "OS::stack_id"}}
user_data:
str_replace:
template: |
       #!/bin/bash -ex
       sed -i 's/172.16.*.*/8.8.8.8/g' /etc/resolv.conf
       # install dependencies
       apt-get update
       apt-get -y install php5 libapache2-mod-php5 php5-mysql php5-gd mysql-client
       wget http://wordpress.org/latest.tar.gz
       tar -xzf latest.tar.gz
       cp wordpress/wp-config-sample.php wordpress/wp-config.php
       sed -i 's/database_name_here/$db_name/' wordpress/wp-config.php
       sed -i 's/username_here/$db_user/' wordpress/wp-config.php
       sed -i 's/password_here/$db_password/' wordpress/wp-config.php
       sed -i 's/localhost/$db_host/' wordpress/wp-config.php
       rm /var/www/html/index.html
       cp -R wordpress/* /var/www/html/
       chown -R www-data:www-data /var/www/html/ 
       chmod -R g+w /var/www/html/
       params:
       $db_name: {get_param: db_name}
       $db_user: {get_param: db_username}
       $db_password: {get_param: [db_password, value]}
       $db_host: {get_attr: [wp_dbserver, first_address]}

                               Here the highlighted part indicates that another YAML file is called upon to create a custom resource. For this a template file is created to define this resource in this case Load-balancing server, and URL to the template file is provided in the environment file. This Load-balancer file will be doing the important function of adding the web server to the load balancing pool using the resource ‘member’.

The Load-balancer server YAML file is given below.

heat_template_version: 2013-05-23
description: A load-balancer server
parameters:
image:
type: string
description: Image used for servers
key_name:
type: string
description: SSH key to connect to the servers
flavor:
type: string
description: flavor used by the servers
pool_id:
type: string
description: Pool to contact
user_data:
type: string
description: Server user_data
metadata:
type: json
network:
type: string
description: Network used by the server
default: private
resources:
server:
type: OS::Nova::Server
properties:
name: web-server
flavor: {get_param: flavor}
image: {get_param: image}
key_name: {get_param: key_name}
metadata: {get_param: metadata}
user_data: {get_param: user_data}
user_data_format: RAW
networks: [{network: {get_param: network} }]
member:
type: OS::Neutron::PoolMember
properties:
pool_id: {get_param: pool_id}
address: {get_attr: [server, first_address]}
protocol_port: 80
outputs:
server_ip:
description: IP Address of the load-balanced server.
value: { get_attr: [server, first_address] }
lb_member:
description: LB member details.
value: { get_attr: [member, show] }

 

Use the following syntax to create scaling policies:

web_server_scaleup_policy:
type: OS::Heat::ScalingPolicy
properties:
adjustment_type: change_in_capacity
auto_scaling_group_id: {get_resource: web_server_group}
cooldown: 60
scaling_adjustment: 1
web_server_scaledown_policy:
type: OS::Heat::ScalingPolicy
properties:
adjustment_type: change_in_capacity
auto_scaling_group_id: {get_resource: web_server_group}
cooldown: 60
scaling_adjustment: -1

 

Use Ceilometer to establish the alarms (both high and low) for the auto-scaling group for a specific metric. Use the following syntax to create Ceilometer alarms:

cpu_alarm_high:
       type: OS::Ceilometer::Alarm
       properties:
       description: Scale-up if the average CPU > 50% for 1 minute
       meter_name: cpu_util
       statistic: avg
       period: 60
       evaluation_periods: 1
       threshold: 50
       alarm_actions:
          - {get_attr: [web_server_scaleup_policy, alarm_url]}
       matching_metadata: {'metadata.user_metadata.stack': {get_param: "OS::stack_id"}}
       comparison_operator: gt

cpu_alarm_low:
       type: OS::Ceilometer::Alarm
       properties:
       description: Scale-down if the average CPU < 15% for 1 minute
       meter_name: cpu_util
       statistic: avg
       period: 60
       evaluation_periods: 1
       threshold: 15
       alarm_actions:
          - {get_attr: [web_server_scaledown_policy, alarm_url]}
       matching_metadata: {'metadata.user_metadata.stack': {get_param: "OS::stack_id"}}
       comparison_operator: lt

The first resource is the Nova server that you will initialize from a specific image. In our example, this is Ubuntu 14.04 with Apache2 already installed and configured. This won’t be a part of the Auto-scaling group and we’ll use it as the database server of the WordPress application.

resources:
wp_dbserver:
type: OS::Nova::Server
properties:
name: wp_db_server
image: {get_param: image}
key_name: dev
networks:
- port: { get_resource: wp_dbserver_port }
user_data_format: RAW
user_data:
str_replace:
params:
__mysql_root_password__: {get_param: [db_rootpassword, value]}
__database_name__: {get_param: db_name}
__database_user__: {get_param: db_username}
__database_password__: {get_param: [db_password, value]}
template: |
#!/bin/bash
apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get install -y mysql-server
mysqladmin -u root password "__mysql_root_password__"
sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
service mysql restart
mysql -u root --password="__mysql_root_password__" <<EOF
CREATE DATABASE __database_name__;
CREATE USER '__database_user__'@'localhost';
SET PASSWORD FOR 
'__database_user__'@'localhost'=PASSWORD("__database_password__");
GRANT ALL PRIVILEGES ON __database_name__.* TO 
'__database_user__'@'localhost' IDENTIFIED BY '__database_password__';
CREATE USER '__database_user__'@'%';
SET PASSWORD FOR '__database_user__'@'%'=PASSWORD("__database_password__");
GRANT ALL PRIVILEGES ON __database_name__.* TO '__database_user__'@'%' IDENTIFIED BY '__database_password__';
FLUSH PRIVILEGES;
EOF

Now to call upon the Load-balancer server file, we’ll use an Environment file which is described below.

resource_registry:
Lib::INF::LB: https://raw.githubusercontent.com/infrastacklabs/test/master/lb.yaml

Here the URL points to the location where the Load-balancer YAML file is stored.

 

Launching the stack on Horizon with this Heat template:

Login to OpenStack environment, open the Orchestration part on the left tab and click on Launch stack as shown in the picture.

autoscalingLB1

 

Click on Launch stack. And select the WordPress.yaml file and the env.yaml file. Click on next.

autoscalingLB2

 

Verify the parameters and click on launch.

autoscalingLB3

 

This should launch the Heat Stack.

autoscalingLB4

Wait a few mins to get the MySQL and WordPress installed in the corresponding servers.

 

One should be able to see a new Load-balancer in the Networks> Load balancer section with a public IP assigned to it.

autoscalingLB5 - Copy

 

Running this public IP should land the Apache welcome page on the browser.

autoscalingLB6

 

Stack should be creating three servers in total, two web-servers and one DB server with MYSQL installed.

autoscalingLB7

 

 

Assign a public IP to any of the web-servers and access it using the browser. It should land a WordPress installation page like below.

autoscalingLB8 - Copy

 

Install the application

autoscalingLB9 - Copy

 

autoscalingLB10

 

Login with the given credentials and one should be able to access the WordPress dashboard.

autoscalingLB11 - Copy

 

Scaling:

Scaling can be done in two ways: Manual and Automatic.

By Using Ceilometer Alarms, the heat stack should be able to scale the servers depending on the CPU usage of the webersvers in the group.

By invoking the webhook URLs in the Stack Overview, one should be able to scale down and scale up the number of web servers in the group.

autoscalingLB12

 

For example:

Running the scale up URL should create a new web server and it should be added under the Load-balancer.

autoscalingLB13

 

autoscalingLB14

Here by using OpenStack Heat, Ceilometer and Load-balancer, we’are able to create an Application infrastructure that contains a Database server and a group of web servers that can be auto-scaled depending up on the CPU usage on these servers. This Load-balancer automatically registers the instances in the group and distributes incoming traffic across the instances.

Advertisements