The following section details different methods that you can use to create a basic layer 4 loadbalancer for your instances.
While each of the examples below will have their own set of requirements, there are some things that you need to prepare no matter which method you are wanting to use. These include:
Sourcing an openrc file
Uploading or creating your own SSH key
Whitelisting your IP address so that you can interact with the cloud from your command line.
Installing the necessary tools for your chosen example. You can find instructions for this in the starting section of the documents.
Once these requirements are met, you can continue with any of the examples below:
This example illustrates how to load balance traffic on port 80 and 443 for two compute instances running a mock Python Flask web application.
If you already have two or more compute instances running a web application listening on ports 80 and 443, you can skip this step. Otherwise, launch two compute instances and follow the instructions below to run a simple Flask web application in each.
The Flask app binds to ports 80 and 443 respectively and will send a simple HTTP response when a request is received on the listening ports.
First we will have to create a copy of the flask_app.py script (shown below) on each server. The easiest way to do this, is to have a program like vim so you can copy paste the code into the new file you create on your instances.
Note
You must also make sure that you have a security group that allows access to your instances from both the HTTP port (80) and the HTTPS port (443) otherwise the listeners and members (which are explained further on) won’t be able to access your instances, meaning you will not be able to test the results of the load-balancer.
script flask_app.py
import argparse
import socket
import sys
from flask import Flask
def check_arg(args=None):
parser = argparse.ArgumentParser(
description='Simple Flask app to test load balancer service')
parser.add_argument('-p', '--port',
required='True',
help='port for the web server to bind to')
parser.add_argument('-u', '--url',
default=None,
help='url for the server to respond with')
results = parser.parse_args(args)
return (results.port, results.url)
host_name = socket.gethostname()
host_ip = socket.gethostbyname(host_name)
app = Flask(__name__)
@app.route("/")
def hello():
if server_url is None:
return "Server : {} @ {}".format(host_name, host_ip)
else:
return "Welcome to {} @ {}".format(server_url, host_ip)
@app.route("/health")
def health():
return "healthy!"
if __name__ == '__main__':
server_port, server_url = check_arg(sys.argv[1:])
app.run(host='0.0.0.0', port=server_port)
Once you have a copy of the flask_app.py file, ssh to your instances and follow the instructions below to install the required dependencies.
Note
In order to be able to bind to ports 80 & 443 the application needs to run as the root user.
# sudo to the root account
$ sudo -i
# install the required system packages
$ apt install virtualenv python-pip
# create a virtual environment
$ virtualenv venv
# activate the virtual environment
$ source venv/bin/activate
# install Flask into the virtual environment
$ pip install flask
# exit the virtual environment
$ deactivate
In each compute instance, start two instances of the application (each in their own terminal session) ensuring that there is one listening on port 80 and the other on port 443.
# sudo to the root account
$ sudo -i
# activate the virtual environment
$ source venv/bin/activate
# run the flask app - providing the correct port numbers
$ python flask_app.py -p <port_number>
The output for the services running on port 80 will look similar to this:
root@server-1:~# python flask_app.py -p 80
* Serving Flask app "flask_app" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
10.0.0.9 - - [28/Jun/2018 06:09:43] "GET /health HTTP/1.0" 200 -
Now, we create the loadbalancer. It will be called lb_test_1 and it’s virtual IP address (VIP) will be attached to the local subnet private-subnet.
Note
If you wish to run the tests included with this example, you will need to have root access on the test instances. If you do not have that level of access then substitute 8080 and 8443 wherever you see 80 and 443 respectively.
$ source example-openrc.sh
$ export SUBNET=`openstack subnet list --name private-subnet -f value -c ID`
$ openstack loadbalancer create --vip-subnet-id ${SUBNET} --name lb_test_1
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| admin_state_up | True |
| created_at | 2017-11-02T21:32:52 |
| description | |
| flavor | |
| id | 547deffe-55fc-49be-ac52-xxxxxxxxxxxx |
| listeners | |
| name | lb_test_1 |
| operating_status | OFFLINE |
| pools | |
| project_id | a3a9af91b9e547739xxxxxxcc2acded0 |
| provider | octavia |
| provisioning_status | PENDING_CREATE |
| updated_at | None |
| vip_address | 10.0.0.3 |
| vip_network_id | 6e743092-a06a-4234-9fce-xxxxxxxxxxxx |
| vip_port_id | 693039f6-1896-4094-8f96-xxxxxxxxxxxx |
| vip_subnet_id | 1c221166-3cb3-4534-915a-xxxxxxxxxxxx |
+---------------------+--------------------------------------+
Once the operating_status
of the load balancer is ACTIVE
, we will
create two listeners, both will use TCP as their protocol and they will listen
on ports 80 and 443 respectively.
$ openstack loadbalancer list
+--------------------------------------+-----------+----------------------------------+-------------+---------------------+----------+
| id | name | project_id | vip_address | provisioning_status | provider |
+--------------------------------------+-----------+----------------------------------+-------------+---------------------+----------+
| 547deffe-55fc-49be-ac52-xxxxxxxxxxxx | lb_test_1 | a3a9af91b9e547739xxxxxxcc2acded0 | 10.0.0.16 | ACTIVE | octavia |
+--------------------------------------+-----------+----------------------------------+-------------+---------------------+----------+
$ openstack loadbalancer listener create --name 80_listener --protocol TCP --protocol-port 80 lb_test_1
+---------------------------+--------------------------------------+
| Field | Value |
+---------------------------+--------------------------------------+
| admin_state_up | True |
| connection_limit | -1 |
| created_at | 2017-11-08T22:42:28 |
| default_pool_id | None |
| default_tls_container_ref | None |
| description | |
| id | de21c777-1c98-4061-aa86-xxxxxxxxxxxx |
| insert_headers | None |
| l7policies | |
| loadbalancers | 547deffe-55fc-49be-ac52-xxxxxxxxxxxx |
| name | 80_listener |
| operating_status | OFFLINE |
| project_id | a3a9af91b9e547739xxxxxxcc2acded0 |
| protocol | TCP |
| protocol_port | 80 |
| provisioning_status | PENDING_CREATE |
| sni_container_refs | [] |
| updated_at | None |
+---------------------------+--------------------------------------+
$ openstack loadbalancer listener create --name 443_listener --protocol TCP --protocol-port 443 lb_test_1
+---------------------------+--------------------------------------+
| Field | Value |
+---------------------------+--------------------------------------+
| admin_state_up | True |
| connection_limit | -1 |
| created_at | 2018-06-25T01:13:06 |
| default_pool_id | None |
| default_tls_container_ref | None |
| description | |
| id | 724816cc-2dbd-42c8-9b61-xxxxxxxxxxxx |
| insert_headers | None |
| l7policies | |
| loadbalancers | bfc1a299-3ec2-4681-974a-xxxxxxxxxxxx |
| name | 443_listener |
| operating_status | OFFLINE |
| project_id | eac679e489614xxxxxxce29d755fe289 |
| protocol | TCP |
| protocol_port | 443 |
| provisioning_status | PENDING_CREATE |
| sni_container_refs | [] |
| timeout_client_data | |
| timeout_member_connect | |
| timeout_member_data | |
| timeout_tcp_inspect | |
| updated_at | None |
+---------------------------+--------------------------------------+
To view the newly created listeners.
$ openstack loadbalancer listener list
+--------------------------------------+-----------------+--------------+----------------------------------+----------+---------------+----------------+
| id | default_pool_id | name | project_id | protocol | protocol_port | admin_state_up |
+--------------------------------------+-----------------+--------------+----------------------------------+----------+---------------+----------------+
| 380ea1df-e043-4167-90ca-xxxxxxxxxxxx | None | 80_listener | eac679e489614xxxxxxce29d755fe289 | TCP | 80 | True |
| 724816cc-2dbd-42c8-9b61-xxxxxxxxxxxx | None | 443_listener | eac679e489614xxxxxxce29d755fe289 | TCP | 443 | True |
+--------------------------------------+-----------------+--------------+----------------------------------+----------+---------------+----------------+
Then add a pool to each listener.
$ openstack loadbalancer pool create --name 80_pool --listener 80_listener --protocol TCP --lb-algorithm ROUND_ROBIN
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| admin_state_up | True |
| created_at | 2018-06-25T01:30:17 |
| description | |
| healthmonitor_id | |
| id | 96dde7c5-77c5-4ffe-9542-xxxxxxxxxxxx |
| lb_algorithm | ROUND_ROBIN |
| listeners | 380ea1df-e043-4167-90ca-xxxxxxxxxxxx |
| loadbalancers | bfc1a299-3ec2-4681-974a-xxxxxxxxxxxx |
| members | |
| name | 80_pool |
| operating_status | OFFLINE |
| project_id | eac679e489614xxxxxxce29d755fe289 |
| protocol | TCP |
| provisioning_status | PENDING_CREATE |
| session_persistence | None |
| updated_at | None |
+---------------------+--------------------------------------+
$ openstack loadbalancer pool create --name 443_pool --listener 443_listener --protocol TCP --lb-algorithm ROUND_ROBIN
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| admin_state_up | True |
| created_at | 2018-06-25T01:31:04 |
| description | |
| healthmonitor_id | |
| id | da26844d-921d-4045-af24-xxxxxxxxxxxx |
| lb_algorithm | ROUND_ROBIN |
| listeners | 724816cc-2dbd-42c8-9b61-xxxxxxxxxxxx |
| loadbalancers | bfc1a299-3ec2-4681-974a-xxxxxxxxxxxx |
| members | |
| name | 443_pool |
| operating_status | OFFLINE |
| project_id | eac679e489614xxxxxxce29d755fe289 |
| protocol | TCP |
| provisioning_status | PENDING_CREATE |
| session_persistence | None |
| updated_at | None |
+---------------------+--------------------------------------+
Now add the members to the pools… When creating members, make sure that you
use the local addresses of your instances. In our example we use 10.0.0.4
and 10.0.0.6
however this may be different for your instances, it almost certainly will be
different, so you should double check the following code before putting it in
the command line.
$ openstack loadbalancer member create --name 80_member_1 --address 10.0.0.4 --protocol-port 80 80_pool
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| address | 10.0.0.4 |
| admin_state_up | True |
| created_at | 2018-06-25T01:37:46 |
| id | 5ce83425-9d85-4da4-a057-xxxxxxxxxxxx |
| name | 80_member_1 |
| operating_status | NO_MONITOR |
| project_id | eac679e489614xxxxxxce29d755fe289 |
| protocol_port | 80 |
| provisioning_status | PENDING_CREATE |
| subnet_id | None |
| updated_at | None |
| weight | 1 |
| monitor_port | None |
| monitor_address | None |
+---------------------+--------------------------------------+
$ openstack loadbalancer member create --name 80_member_2 --address 10.0.0.6 --protocol-port 80 80_pool
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| address | 10.0.0.6 |
| admin_state_up | True |
| created_at | 2018-06-25T01:38:48 |
| id | 5f973af6-7d59-4f64-a0b8-xxxxxxxxxxxx |
| name | 80_member_2 |
| operating_status | NO_MONITOR |
| project_id | eac679e489614xxxxxxce29d755fe289 |
| protocol_port | 80 |
| provisioning_status | PENDING_CREATE |
| subnet_id | None |
| updated_at | None |
| weight | 1 |
| monitor_port | None |
| monitor_address | None |
+---------------------+--------------------------------------+
Check that the members were created
$ openstack loadbalancer member list 80_pool
+--------------------------------------+-------------+----------------------------------+---------------------+----------+---------------+------------------+--------+
| id | name | project_id | provisioning_status | address | protocol_port | operating_status | weight |
+--------------------------------------+-------------+----------------------------------+---------------------+----------+---------------+------------------+--------+
| 5ce83425-9d85-4da4-a057-xxxxxxxxxxxx | 80_member_1 | eac679e489614xxxxxxce29d755fe289 | ACTIVE | 10.0.0.4 | 80 | NO_MONITOR | 1 |
| 5f973af6-7d59-4f64-a0b8-xxxxxxxxxxxx | 80_member_2 | eac679e489614xxxxxxce29d755fe289 | ACTIVE | 10.0.0.6 | 80 | NO_MONITOR | 1 |
+--------------------------------------+-------------+----------------------------------+---------------------+----------+---------------+------------------+--------+
Now repeat for the service on port 443
$ openstack loadbalancer member create --name 443_member_1 --address 10.0.0.4 --protocol-port 443 443_pool
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| address | 10.0.0.4 |
| admin_state_up | True |
| created_at | 2018-06-25T01:43:41 |
| id | ec245cb0-7548-4b25-881f-xxxxxxxxxxxx |
| name | 443_member_1 |
| operating_status | NO_MONITOR |
| project_id | eac679e489614xxxxxxce29d755fe289 |
| protocol_port | 443 |
| provisioning_status | PENDING_CREATE |
| subnet_id | None |
| updated_at | None |
| weight | 1 |
| monitor_port | None |
| monitor_address | None |
+---------------------+--------------------------------------+
$ openstack loadbalancer member create --name 443_member_2 --address 10.0.0.6 --protocol-port 443 443_pool
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| address | 10.0.0.6 |
| admin_state_up | True |
| created_at | 2018-06-25T01:44:19 |
| id | f91e7d8e-a932-43da-8c9f-xxxxxxxxxxxx |
| name | 443_member_2 |
| operating_status | NO_MONITOR |
| project_id | eac679e489614xxxxxxce29d755fe289 |
| protocol_port | 443 |
| provisioning_status | PENDING_CREATE |
| subnet_id | None |
| updated_at | None |
| weight | 1 |
| monitor_port | None |
| monitor_address | None |
+---------------------+--------------------------------------+
$ openstack loadbalancer member list 443_pool
+--------------------------------------+--------------+----------------------------------+---------------------+----------+---------------+------------------+--------+
| id | name | project_id | provisioning_status | address | protocol_port | operating_status | weight |
+--------------------------------------+--------------+----------------------------------+---------------------+----------+---------------+------------------+--------+
| ec245cb0-7548-4b25-881f-xxxxxxxxxxxx | 443_member_1 | eac679e489614xxxxxxce29d755fe289 | ACTIVE | 10.0.0.4 | 443 | NO_MONITOR | 1 |
| f91e7d8e-a932-43da-8c9f-xxxxxxxxxxxx | 443_member_2 | eac679e489614xxxxxxce29d755fe289 | ACTIVE | 10.0.0.6 | 443 | NO_MONITOR | 1 |
+--------------------------------------+--------------+----------------------------------+---------------------+----------+---------------+------------------+--------+
Create a health monitor to check the state of the members of the pool. This example performs a simple static request at the URL path ‘/health’.
$ openstack loadbalancer healthmonitor create --name 80_healthcheck --delay 60 --timeout 20 --max-retries 2 --url-path /health --type http 80_pool
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| project_id | eac679e489614xxxxxxce29d755fe289 |
| name | 80_healthcheck |
| admin_state_up | True |
| pools | 96dde7c5-77c5-4ffe-9542-xxxxxxxxxxxx |
| created_at | 2018-06-25T21:22:25 |
| provisioning_status | PENDING_CREATE |
| updated_at | None |
| delay | 60 |
| expected_codes | 200 |
| max_retries | 2 |
| http_method | GET |
| timeout | 20 |
| max_retries_down | 3 |
| url_path | /health |
| type | HTTP |
| id | d8c8c074-574a-4e41-8c43-xxxxxxxxxxxx |
| operating_status | OFFLINE |
+---------------------+--------------------------------------+
Here is a brief description of some of the parameters used in the health monitor example.
url_path
: Path part of the URL that should be retrieved from the
back-end server. By default this is “/”.
delay
: Number of seconds to wait between health checks.
timeout
: Number of seconds to wait for any given health check to
complete. Timeout should always be smaller than delay.
max-retries
: Number of subsequent health checks a given back-end server
must fail before it is considered down, or that a failed back-end server
must pass to be considered up again.
The final step is to assign a floating ip address to the VIP port on the loadbalancer. In order to do this we need to create a floating ip, find the VIP Port ID and then assign it a floating ip address.
export FIP=`openstack floating ip create public-net -f value -c floating_ip_address`
export VIP_PORT_ID=`openstack loadbalancer show lb_test_1 -f value -c vip_port_id`
openstack floating ip set --port $VIP_PORT_ID $FIP
If you need to retrieve the VIP for the loadbalancer
export VIP=$(openstack loadbalancer show lb_test_1 -f value -c vip_address)
openstack floating ip list | grep $VIP | awk '{ print $4}'
Test the following:
Connect to the loadbalancer VIP from a browser. The output should alternate between both back-end servers on port 80.
Connect to the healtmonitor URL on $VIP/health
Connect to $VIP:443 to confirm that the second service is also loadbalanced
Heat is the native Openstack orchestration tool and functions by reading a template file and creating the resources defined within. In the following example, we are going to use a template to create a loadbalancer which will look after two webserver instances on ports 80 and 443 (for both webservers).
If you do not have the underlying resources required to run a set of webservers i.e. a network and a router; you can find the instructions for creating them in this section of the documents. Given that there is a heat template in that section, you could even take a snippet of that template and include it in your own here, allowing you to construct your own template for future use. Additionally, if you need to create the simulated webservers themselves, there are instructions in the CLI section of this page on how to set them up correctly.
Once you have these resources created, we are going to need to gather some information about them before we can construct our heat template. We will need to find the following variables for our template:
The subnet ID of the network your webservers are on. You can find this information using the following:
$ openstack subnet list
+--------------------------------------+---------------------+--------------------------------------+-----------------+
| ID | Name | Network | Subnet |
+--------------------------------------+---------------------+--------------------------------------+-----------------+
| xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | private-subnet | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | 192.168.3.0/24 |
+--------------------------------------+---------------------+--------------------------------------+-----------------+
You will need the internal IP addresses of your two webservers:
$ openstack server list
+--------------------------------------+-----------------------+--------+----------------------------------------------+--------------------------+---------+
| ID | Name | Status | Networks | Image | Flavor |
+--------------------------------------+-----------------------+--------+----------------------------------------------+--------------------------+---------+
| 52d0d0af-8d0b-4bf8-8264-xxxxxxxxxxxx | webserver-heat-test-2 | ACTIVE | lb-docs-tests=192.168.0.43 | N/A (booted from volume) | c1.c1r1 |
| bfc4e791-717f-4777-a7f3-xxxxxxxxxxxx | webserver-heat-test | ACTIVE | lb-docs-tests=192.168.0.42 | N/A (booted from volume) | c1.c1r1 |
+--------------------------------------+-----------------------+--------+----------------------------------------------+--------------------------+---------+
# We are taking the IP addresses: 192.168.0.43 and 192.168.0.42
Now that we have these variables, we can begin constructing out template.
For this example, we are going to provide a template which you can use to create your load balancer. You will have to change the “parameters” section of this file to include the variables you collected in the previous step:
heat_template_version: 2016-10-14
description: |
The heat template is used to create a load balancer for a basic webserver
parameters:
vip_subnet_id:
description: Should be a subnet of webserver_network_id
type: string
default: <INSERT SUBNET OF WEBSERVERS>
public_network:
description: Public network name, could get by 'openstack network list --external'
type: string
default: public-net
pool_member_1:
description: the first webserver that you want the loadbalancer to balance
type: string
default: <INTERNAL IP OF FIRST WEBSERVER>
pool_member_2:
description: the second webserver that you want to be loadbalanced
type: string
default: <INTERNAL IP OF SECOND WEBSERVER>
resources:
security_group:
type: OS::Neutron::SecurityGroup
properties:
rules: [
{protocol: "tcp", "port_range_min": 80, "port_range_max": 80},
{protocol: "tcp", "port_range_min": 443, "port_range_max": 443},
]
loadbalancer:
type: OS::Octavia::LoadBalancer
properties:
vip_subnet: {get_param: vip_subnet_id}
name: Loadbalancer-heat-test
loadbalancer_public_ip:
type: OS::Neutron::FloatingIP
properties:
floating_network: {get_param: public_network}
port_id: {get_attr: [loadbalancer, vip_port_id]}
listener:
type: OS::Octavia::Listener
properties:
name: webserver_listener
protocol: HTTP
protocol_port: 80
loadbalancer: {get_resource: loadbalancer}
loadbalancer_pool:
type: OS::Octavia::Pool
properties:
name: webserver-pool
lb_algorithm: ROUND_ROBIN
protocol: HTTP
listener: {get_resource: listener}
loadbalancer_pool_member_1:
type: OS::Octavia::PoolMember
properties:
address: {get_param: pool_member_1}
pool: {get_resource: loadbalancer_pool}
protocol_port: 80
loadbalancer_pool_member_2:
type: OS::Octavia::PoolMember
properties:
address: {get_param: pool_member_2}
pool: {get_resource: loadbalancer_pool}
protocol_port: 80
loadbalancer_healthmonitor:
type: OS::Octavia::HealthMonitor
properties:
delay: 5
max_retries: 3
pool: {get_resource: loadbalancer_pool}
timeout: 15
type: HTTP
http_method: GET
expected_codes: 200
outputs:
lb_ip:
value: {get_attr: [loadbalancer_public_ip, floating_ip_address]}
lb_vip:
value: {get_attr: [loadbalancer, vip_address]}
Reading through the template you can see which resources are being created and how they relate to one another. Once you have saved this template and changed the necessary parameters, we can verify the syntax of our template is correct by using the following code:
$ openstack orchestration template validate -t heat-load-balancer.yaml
Environment:
event_sinks: []
parameter_defaults: {}
parameters: {}
resource_registry:
resources: {}
Description: 'The heat template is used to create a load balancer for a basic webserver'
Parameters:
pool_member_1:
Default: 192.168.0.43
Description: the first webserver that you want the loadbalancer to balance
Label: pool_member_1
NoEcho: 'false'
Type: String
pool_member_2:
Default: 192.168.0.42
Description: the second webserver that you want to be loadbalanced
Label: pool_member_2
NoEcho: 'false'
Type: String
public_network:
Default: public-net
Description: Public network name, could get by 'openstack network list --external'
Label: public_network
NoEcho: 'false'
Type: String
vip_subnet_id:
Default: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Description: Should be a subnet of webserver_network_id
Label: vip_subnet_id
NoEcho: 'false'
Type: String
Once you have confirmed that your template is formatted correctly and that it is going to create the correct resources, we can run the following command to create our stack:
$ openstack stack create -t heat-load-balancer.yaml heat-lb-stack
+---------------------+---------------------------------------------------------------------------+
| Field | Value |
+---------------------+---------------------------------------------------------------------------+
| id | bedbf02b-0094-44c8-a423-xxxxxxxxxxxx |
| stack_name | heat-lb-stack |
| description | The heat template is used to create a load balancer for a basic webserver |
| | |
| creation_time | 2021-01-28T21:36:20Z |
| updated_time | None |
| stack_status | CREATE_IN_PROGRESS |
| stack_status_reason | Stack CREATE started |
+---------------------+---------------------------------------------------------------------------+
Now we should have our stack created and our loadbalancer running on our webserver instances.
If you have created resources using Heat then it is also a good idea to remove them using Heat as well. This is so that your stack is not left with missing resources or in a faulty state.
To remove all the resources created with our template; you can run the following command:
$ openstack stack delete <name of your stack>>
Are you sure you want to delete this stack(s) [y/N]? y
For this example, we assume that you already have some knowledge of how Terraform functions and that you know how to construct a Terraform template. If you have not used terraform before, or are not sure how to use it on the Catalyst Cloud, you can find a good starting example under the first instance section of the documents. If you are wanting an even more in depth look at Terraform, you can also check the Terraform documentation.
As we mentioned earlier, this tutorial assumes that you already have installed the necessary tools to work with a terraform template. If you have not downloaded and installed terraform, you can follow our guide in the getting started section of the docs.
Once you have the correct tools ready, we can start working on our template. The template file that we are going to use for this example, is going to create a load balancer to manage a pair of webservers. You can use the script explained in the CLI example to create your own set of simulated webservers.
A key difference between this example and the CLI example is that we are focusing on having the webservers respond and balanced only on port 80. Which means that we can ignore the instructions from the CLI example referencing port 443.
Once you have a set of webservers that are serving traffic on port 80, we need to gather the necessary information that our template requires. Lets start with getting our subnet ID for the network we are going to have our loadbalancer on:
$ source example-openRC.sh
$ openstack subnet list
+--------------------------------------+---------------------+--------------------------------------+-----------------+
| ID | Name | Network | Subnet |
+--------------------------------------+---------------------+--------------------------------------+-----------------+
| aaaXXXXXX-XXXX-XXXXXXXX-XXXXX-jmu2r3 | lb-docs-test-subnet | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | 192.168.0.0/24 |
+--------------------------------------+---------------------+--------------------------------------+-----------------+
Once you have your subnet ID, next you will need to get the local IP of your webservers:
$ openstack server list
+--------------------------------------+--------------------+--------+----------------------------+--------------------------+---------+
| ID | Name | Status | Networks | Image | Flavor |
+--------------------------------------+--------------------+--------+----------------------------+--------------------------+---------+
| 28ad54af-e0d2-47c9-8855-xxxxxxxxxxxx | webserver-2 | ACTIVE | private-net=192.168.3.41 | N/A (booted from volume) | c1.c1r1 |
| 6ea96e5e-8b67-4ec3-80a3-xxxxxxxxxxxx | webserver-1 | ACTIVE | private-net=192.168.3.40 | N/A (booted from volume) | c1.c1r1 |
+--------------------------------------+--------------------+--------+----------------------------+--------------------------+---------+
# From this output, we can find the IP addresses under the "Networks" section:
# Member_1 = 192.168.3.41 , Member_2 = 192.168.3.40
After you have gathered this information, you need to construct a template to create your loadbalancer. You can use the following as a base and insert the information we gathered earlier into the variables provided:
# Configure the OpenStack Provider
# This example relies on OpenStack environment variables
# If you wish to set these credentials manualy please consult
# https://www.terraform.io/docs/providers/openstack/index.html
provider "openstack" {
use_octavia = true # You must have set the "use_octavia" parameter to true, otherwise you will not be able to create a loadbalancer
}
# Set the public network that our resources are going to use further down in the template.
variable "public_network_id" {
default = "f10ad6de-a26d-4c29-8c64-xxxxxxxxxxxx"
}
# Depending on which region you are using, the public_network_id will need to be changed:
#nz-por-1 849ab1e9-7ac5-4618-8801-xxxxxxxxxxxx
#nz-hlz-1 f10ad6de-a26d-4c29-8c64-xxxxxxxxxxxx
# Include a valid VIP subnet_id to be used for your load balancer later.
variable "vip_subnet" {
default = "<INSERT SUBNET ID>"
}
variable "public_network" {
default = "public-net"
}
# Include the first webserver IP
variable "pool_member_1_address" {
default = "<LOCAL IP ADDRESS OF WEBSERVER 1>"
}
# Include the second webserver IP
variable "pool_member_2_address" {
default = "<LOCAL IP ADDRESS OF WEBSERVER 2>"
}
#-----------------------------------------------------------------------------------------------
# Create loadbalancer
resource "openstack_lb_loadbalancer_v2" "terra_load_balancer" {
name = "terraform-lb"
vip_subnet_id = var.vip_subnet
security_group_ids = [openstack_networking_secgroup_v2.secgroup_1.id]
}
# Create a pool for our loadbalancer
resource "openstack_lb_pool_v2" "pool_1" {
name = "webserver-pool"
protocol = "TCP"
listener_id = openstack_lb_listener_v2.listener_1.id
lb_method = "ROUND_ROBIN"
}
# create a member and specify the pool it belongs to
resource "openstack_lb_member_v2" "member_1" {
name = "member-1"
pool_id = openstack_lb_pool_v2.pool_1.id
address = var.pool_member_1_address
protocol_port = 80
}
# create a member and specify the pool it belongs to
resource "openstack_lb_member_v2" "member_2" {
name = "member-2"
pool_id = openstack_lb_pool_v2.pool_1.id
address = var.pool_member_2_address
protocol_port = 80
}
# Create a listener
resource "openstack_lb_listener_v2" "listener_1" {
name = "listener-1"
protocol = "TCP"
protocol_port = 80
loadbalancer_id = openstack_lb_loadbalancer_v2.terra_load_balancer.id
}
# Request a floating IP
resource "openstack_networking_floatingip_v2" "fip_1" {
pool = "public-net"
}
# Associate floating IP
resource "openstack_networking_floatingip_associate_v2" "fip_associate" {
floating_ip = openstack_networking_floatingip_v2.fip_1.address
port_id = openstack_lb_loadbalancer_v2.terra_load_balancer.vip_port_id
}
# Create a security group
resource "openstack_networking_secgroup_v2" "secgroup_1" {
name = "secgroup_1"
}
# Create security group rule
resource "openstack_networking_secgroup_rule_v2" "secgroup_rule_1" {
direction = "ingress"
ethertype = "IPv4"
protocol = "TCP"
port_range_min = 80
port_range_max = 80
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.secgroup_1.id
}
# Create health monitor for LB
resource "openstack_lb_monitor_v2" "monitor_1" {
pool_id = openstack_lb_pool_v2.pool_1.id
type = "HTTP"
http_method = "GET"
expected_codes = 200
delay = 5
timeout = 15
max_retries = 3
}
Once you have your template ready with the correct variables, you can run the
terraform plan
command to get an output of what resources your template is
going to construct for you:
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# openstack_lb_listener_v2.listener_1 will be created
+ resource "openstack_lb_listener_v2" "listener_1" {
+ admin_state_up = true
+ connection_limit = (known after apply)
+ default_pool_id = (known after apply)
+ id = (known after apply)
+ loadbalancer_id = (known after apply)
+ name = "listener-1"
+ protocol = "HTTP"
+ protocol_port = 80
+ region = (known after apply)
+ tenant_id = (known after apply)
+ timeout_client_data = (known after apply)
+ timeout_member_connect = (known after apply)
+ timeout_member_data = (known after apply)
+ timeout_tcp_inspect = (known after apply)
}
# openstack_lb_loadbalancer_v2.terra_load_balancer will be created
+ resource "openstack_lb_loadbalancer_v2" "terra_load_balancer" {
+ admin_state_up = true
+ id = (known after apply)
+ loadbalancer_provider = (known after apply)
+ name = "terraform-lb"
+ region = (known after apply)
+ security_group_ids = (known after apply)
+ tenant_id = (known after apply)
+ vip_address = (known after apply)
+ vip_network_id = (known after apply)
+ vip_port_id = (known after apply)
+ vip_subnet_id = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
# openstack_lb_member_v2.member_1 will be created
+ resource "openstack_lb_member_v2" "member_1" {
+ address = "XXXXXXXXXXXXXXX"
+ admin_state_up = true
+ id = (known after apply)
+ name = "member-1"
+ pool_id = (known after apply)
+ protocol_port = 80
+ region = (known after apply)
+ tenant_id = (known after apply)
+ weight = (known after apply)
}
# openstack_lb_member_v2.member_2 will be created
+ resource "openstack_lb_member_v2" "member_2" {
+ address = "XXXXXXXXXXXXXXX"
+ admin_state_up = true
+ id = (known after apply)
+ name = "member-2"
+ pool_id = (known after apply)
+ protocol_port = 80
+ region = (known after apply)
+ tenant_id = (known after apply)
+ weight = (known after apply)
}
# openstack_lb_monitor_v2.monitor_1 will be created
+ resource "openstack_lb_monitor_v2" "monitor_1" {
+ admin_state_up = true
+ delay = 5
+ expected_codes = "200"
+ http_method = "GET"
+ id = (known after apply)
+ max_retries = 3
+ max_retries_down = (known after apply)
+ pool_id = (known after apply)
+ region = (known after apply)
+ tenant_id = (known after apply)
+ timeout = 15
+ type = "HTTP"
+ url_path = (known after apply)
}
# openstack_lb_pool_v2.pool_1 will be created
+ resource "openstack_lb_pool_v2" "pool_1" {
+ admin_state_up = true
+ id = (known after apply)
+ lb_method = "ROUND_ROBIN"
+ listener_id = (known after apply)
+ name = "webserver-pool"
+ protocol = "HTTP"
+ region = (known after apply)
+ tenant_id = (known after apply)
+ persistence {
+ cookie_name = (known after apply)
+ type = (known after apply)
}
}
# openstack_networking_floatingip_associate_v2.fip_associate will be created
+ resource "openstack_networking_floatingip_associate_v2" "fip_associate" {
+ fixed_ip = (known after apply)
+ floating_ip = (known after apply)
+ id = (known after apply)
+ port_id = (known after apply)
+ region = (known after apply)
}
# openstack_networking_floatingip_v2.fip_1 will be created
+ resource "openstack_networking_floatingip_v2" "fip_1" {
+ address = (known after apply)
+ all_tags = (known after apply)
+ dns_domain = (known after apply)
+ dns_name = (known after apply)
+ fixed_ip = (known after apply)
+ id = (known after apply)
+ pool = "public-net"
+ port_id = (known after apply)
+ region = (known after apply)
+ tenant_id = (known after apply)
}
# openstack_networking_secgroup_rule_v2.secgroup_rule_1 will be created
+ resource "openstack_networking_secgroup_rule_v2" "secgroup_rule_1" {
+ direction = "ingress"
+ ethertype = "IPv4"
+ id = (known after apply)
+ port_range_max = 80
+ port_range_min = 80
+ protocol = "tcp"
+ region = (known after apply)
+ remote_group_id = (known after apply)
+ remote_ip_prefix = "XXXXXXXXXX"
+ security_group_id = (known after apply)
+ tenant_id = (known after apply)
}
# openstack_networking_secgroup_v2.secgroup_1 will be created
+ resource "openstack_networking_secgroup_v2" "secgroup_1" {
+ all_tags = (known after apply)
+ description = (known after apply)
+ id = (known after apply)
+ name = "secgroup_1"
+ region = (known after apply)
+ tenant_id = (known after apply)
}
Plan: 10 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
At this point, after you have checked the plan and made sure all of the
resources are correct and that the template is has no formatting problems, you
can run the terraform apply
command and begin creating your resources:
$ terraform apply
... # truncated output for brevity.
Plan: 10 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
openstack_networking_secgroup_v2.secgroup_1: Creating...
openstack_networking_floatingip_v2.fip_1: Creating...
openstack_networking_secgroup_v2.secgroup_1: Creation complete after 2s [id=04a48ceb-44c4-4f71-9c16-xxxxxxxxxxxx]
openstack_networking_secgroup_rule_v2.secgroup_rule_1: Creating...
openstack_lb_loadbalancer_v2.terra_load_balancer: Creating...
openstack_networking_secgroup_rule_v2.secgroup_rule_1: Creation complete after 0s [id=46f0734a-0468-4e03-a5fa-xxxxxxxxxxxx]
openstack_networking_floatingip_v2.fip_1: Creation complete after 7s [id=cd8006d1-1010-47d8-b6af-xxxxxxxxxxxx]
openstack_lb_loadbalancer_v2.terra_load_balancer: Still creating... [10s elapsed]
openstack_lb_loadbalancer_v2.terra_load_balancer: Still creating... [20s elapsed]
openstack_lb_loadbalancer_v2.terra_load_balancer: Still creating... [30s elapsed]
openstack_lb_loadbalancer_v2.terra_load_balancer: Still creating... [40s elapsed]
openstack_lb_loadbalancer_v2.terra_load_balancer: Still creating... [50s elapsed]
openstack_lb_loadbalancer_v2.terra_load_balancer: Still creating... [1m0s elapsed]
openstack_lb_loadbalancer_v2.terra_load_balancer: Still creating... [1m10s elapsed]
openstack_lb_loadbalancer_v2.terra_load_balancer: Creation complete after 1m11s [id=5529a920-c32e-4eda-b533-xxxxxxxxxxxx]
openstack_networking_floatingip_associate_v2.fip_associate: Creating...
openstack_lb_listener_v2.listener_1: Creating...
openstack_networking_floatingip_associate_v2.fip_associate: Creation complete after 1s [id=cd8006d1-1010-47d8-b6af-xxxxxxxxxxxx]
openstack_lb_listener_v2.listener_1: Creation complete after 9s [id=56b09389-bcd5-4e02-9eeb-xxxxxxxxxxxx]
openstack_lb_pool_v2.pool_1: Creating...
openstack_lb_pool_v2.pool_1: Creation complete after 5s [id=be81e2b6-927f-4f7a-affb-xxxxxxxxxxxx]
openstack_lb_member_v2.member_1: Creating...
openstack_lb_member_v2.member_2: Creating...
openstack_lb_monitor_v2.monitor_1: Creating...
openstack_lb_member_v2.member_1: Creation complete after 8s [id=9190707b-2358-422d-8cdd-xxxxxxxxxxxx]
openstack_lb_monitor_v2.monitor_1: Creation complete after 9s [id=67c133f7-3857-425c-8f4a-xxxxxxxxxxxx]
openstack_lb_member_v2.member_2: Still creating... [10s elapsed]
openstack_lb_member_v2.member_2: Creation complete after 17s [id=d30ee7dc-63f4-4e41-8f27-xxxxxxxxxxxx]
Apply complete! Resources: 10 added, 0 changed, 0 destroyed.
Should you wish to remove these resources, you can use the command:
$ terraform destroy
Plan: 0 to add, 0 to change, 10 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
openstack_networking_secgroup_rule_v2.secgroup_rule_1: Destroying... [id=46f0734a-0468-4e03-a5fa-xxxxxxxxxxxx]
openstack_networking_floatingip_associate_v2.fip_associate: Destroying... [id=cd8006d1-1010-47d8-b6af-xxxxxxxxxxxx]
openstack_lb_member_v2.member_2: Destroying... [id=d30ee7dc-63f4-4e41-8f27-xxxxxxxxxxxx]
openstack_lb_member_v2.member_1: Destroying... [id=9190707b-2358-422d-8cdd-xxxxxxxxxxxx]
openstack_lb_monitor_v2.monitor_1: Destroying... [id=67c133f7-3857-425c-8f4a-xxxxxxxxxxxx]
openstack_networking_floatingip_associate_v2.fip_associate: Destruction complete after 1s
openstack_networking_floatingip_v2.fip_1: Destroying... [id=cd8006d1-1010-47d8-b6af-xxxxxxxxxxxx]
openstack_networking_secgroup_rule_v2.secgroup_rule_1: Destruction complete after 6s
openstack_networking_floatingip_v2.fip_1: Destruction complete after 6s
openstack_lb_monitor_v2.monitor_1: Destruction complete after 8s
openstack_lb_member_v2.member_1: Destruction complete after 9s
openstack_lb_member_v2.member_2: Still destroying... [id=d30ee7dc-63f4-4e41-8f27-xxxxxxxxxxxx, 10s elapsed]
openstack_lb_member_v2.member_2: Destruction complete after 11s
openstack_lb_pool_v2.pool_1: Destroying... [id=be81e2b6-927f-4f7a-affb-xxxxxxxxxxxx]
openstack_lb_pool_v2.pool_1: Destruction complete after 3s
openstack_lb_listener_v2.listener_1: Destroying... [id=56b09389-bcd5-4e02-9eeb-xxxxxxxxxxxx]
openstack_lb_listener_v2.listener_1: Destruction complete after 5s
openstack_lb_loadbalancer_v2.terra_load_balancer: Destroying... [id=5529a920-c32e-4eda-b533-xxxxxxxxxxxx]
openstack_lb_loadbalancer_v2.terra_load_balancer: Destruction complete after 7s
openstack_networking_secgroup_v2.secgroup_1: Destroying... [id=04a48ceb-44c4-4f71-9c16-xxxxxxxxxxxx]
openstack_networking_secgroup_v2.secgroup_1: Destruction complete after 9s
Destroy complete! Resources: 10 destroyed.
The following example assumes that you already have some understanding of how Ansible playbooks work and how to construct your own. If you have not used Ansible before or are not sure about how to use it on the Catalyst cloud, a good starting point is our example under the first instance section of the documents. You can also find more information about Ansible in general on the Ansible homepage.
Unlike the other examples, our ansible playbook will create its own webserver alongside the load balancer. Therefore we have to gather additional information about our resources before we can start using our playbook.
We will need to prepare a number of variables for our playbook:
A name for your webserver
A name for your load balancer
An image to use for your webserver:
$ openstack image list
+--------------------------------------+-----------------------------------------------------------------+--------+
| ID | Name | Status |
+--------------------------------------+-----------------------------------------------------------------+--------+
| 683f76b0-eec2-43c3-9143-xxxxxxxxxxxx | atomic-7-x86_64 | active |
| 7f352450-e87f-42b9-8238-xxxxxxxxxxxx | atomic-7-x86_64-20170502 | active |
| bc84a4a4-d73c-44c8-a65e-xxxxxxxxxxxx | atomic-7-x86_64-20170608 | active |
| 0be2db8d-017b-464f-8a46-xxxxxxxxxxxx | atomic-7-x86_64-20170714 | active |
| eedefeab-34d3-4f73-8421-xxxxxxxxxxxx | atomic-7-x86_64-20181018 | active |
| ... Truncated for brevity | | |
+--------------------------------------+-----------------------------------------------------------------+--------+
A flavor to use for your webserver:
$ openstack flavor list
+--------------------------------------+------------+--------+------+-----------+-------+-----------+
| ID | Name | RAM | Disk | Ephemeral | VCPUs | Is Public |
+--------------------------------------+------------+--------+------+-----------+-------+-----------+
| 00e563b6-11e2-4468-ac55-xxxxxxxxxxxx | c1.c16r24 | 24576 | 10 | 0 | 16 | True |
| 01ecf2cc-2047-4606-a53b-xxxxxxxxxxxx | c1.c8r6 | 6144 | 10 | 0 | 8 | True |
| 02cb8214-2121-4d0d-b7fd-xxxxxxxxxxxx | c1.c4r24 | 24576 | 10 | 0 | 4 | True |
| 07585040-f887-4ddb-a0d5-xxxxxxxxxxxx | c1.c8r16 | 16384 | 10 | 0 | 8 | True |
| 1c558eba-0d8a-4d09-86dd-xxxxxxxxxxxx | c1.c32r24 | 24576 | 10 | 0 | 32 | True |
| ... Truncated for Brevity | | | | | | |
+--------------------------------------+------------+--------+------+-----------+-------+-----------+
The name of an existing network &
The name of the public net to connect to:
$ openstack network list
+--------------------------------------+--------------------------+--------------------------------------+
| ID | Name | Subnets |
+--------------------------------------+--------------------------+--------------------------------------+
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | public-net | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | existing-private-net | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
+--------------------------------------+--------------------------+--------------------------------------+
The name of an existing keypair:
$ openstack keypair list
+-----------------+-------------------------------------------------+
| Name | Fingerprint |
+-----------------+-------------------------------------------------+
| your-keypair | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+-----------------+-------------------------------------------------+
A list of any security groups you want to attach to your load balancer
$ openstack security group list
+--------------------------------------+-------------------+--------------------------------------------+---------+------+
| ID | Name | Description | Project | Tags |
+--------------------------------------+-------------------+--------------------------------------------+---------+------+
| xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | sec-group | security group to allow traffic on port 80 | None | [] |
+--------------------------------------+-------------------+--------------------------------------------+---------+------+
The name of your subnet
$ openstack subnet list
+--------------------------------------+---------------------+--------------------------------------+-----------------+
| ID | Name | Network | Subnet |
+--------------------------------------+---------------------+--------------------------------------+-----------------+
| xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | private-subnet | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | 192.168.3.0/24 |
+--------------------------------------+---------------------+--------------------------------------+-----------------+
Once you have all of these resources you can move on to constructing your playbook.
For this example we will provide a template for your playbook. You will need to
add the variables you collected in the previous step to the vars
section
of the template, but once this is done you should have a fully functioning
Ansible playbook you can use to create a simulated webserver and a loadbalancer
which looks after it:
#!/usr/bin/env ansible-playbook
#
# This playbook creates an instance running a simple webserver listening on
# port 80 and adds a load balancer to it. A floating ip is created and associated
# with the load balancer automatically. The floating ip address can be found
# in the `public_vip_address` field of the final output.
#
# Please refer to https://docs.ansible.com/ansible/latest/collections/openstack/cloud/loadbalancer_module.html
# for more detailed information about os_loadbalancer ansible module usage.
#
---
- name: Create loadbalancer and add a simple webserver
hosts: localhost
vars:
vm_name: <insert_webserver_name>
image: ubuntu-20.04-x86_64 # image used for webserver
flavor: c1.c1r1 # A flavor with 1 core and 1 GB of RAM
network: <insert_network_name>
kaypair: <insert_key_name>
security_groups:
- <insert_lb_secgroup>
lb_name: <insert_load_balancer_name>
vip_subnet: <insert_subnet_name>
public_network: public-net
tasks:
- name: Create a simple webserver
openstack.cloud.server:
name: "{{ vm_name }}"
state: present
auto_ip: true
flavor: "{{ flavor }}"
image: "{{ image }}"
key_name: "{{ kaypair }}"
network: "{{ network }}"
security_groups: "{{ security_groups }}"
config_drive: true
userdata: |
{%- raw -%}#!/usr/bin/python
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
import time
PORT_NUMBER = 80
class myHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
res_content = "Hello %s:%s - %s\n" % (self.client_address[0], self.client_address[1], time.strftime("%H:%M:%S", time.gmtime()))
self.wfile.write(res_content)
return
try:
server = HTTPServer(('', PORT_NUMBER), myHandler)
print 'Started httpserver on port ' , PORT_NUMBER
server.serve_forever()
except KeyboardInterrupt:
print 'shutting down the web server...'
server.socket.close()
{% endraw %}
- name: Gather facts about webserver
openstack.cloud.server_info:
server: "{{ vm_name }}"
- name: Create the openstack loadbalancer
openstack.cloud.loadbalancer:
name: "{{ lb_name }}"
state: present
vip_subnet: "{{ vip_subnet }}"
auto_public_ip: yes
public_network: "{{ public_network }}"
wait: yes
timeout: "600"
listeners:
- name: listener-80
protocol: TCP
protocol_port: 80
pool:
name: listener_80_pool
protocol: TCP
members:
- name: member-1
address: openstack.cloud.server.ip
protocol_port: 80
subnet: <<INSERT THE NAME OF YOUR SUBNET HERE>> #using a reference to the variable does not work for this declaration
vars:
query: 'addresses.{{ network }}[?"OS-EXT-IPS:type"==`fixed`].addr | [0]'
register: lb_info
- name: Create a health monitor for our load balancer
openstack.cloud.lb_health_monitor:
wait: true
admin_state_up: True
expected_codes: '200'
max_retries_down: '3'
http_method: GET
url_path: "/status"
pool: "listener_80_pool"
name: 'healthmonitor01'
delay: '10'
max_retries: '3'
resp_timeout: '5'
state: present
Once you have changed the variables in your template we can move on to building the resources on your project.
Firstly, we need to know exactly what tasks our playbook is going to take. We can use the following command to display each of our playbook’s tasks:
$ ansible-playbook --list-tasks create_loadbalancer_playbook.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
playbook: create_loadbalancer_playbook.yaml
play #1 (localhost): Create loadbalancer and add a simple webserver TAGS: []
tasks:
Create a simple webserver TAGS: []
Gather facts about webserver TAGS: []
Create the openstack loadbalancer TAGS: []
Create a health monitor for our load balancer TAGS: []
Now that we know what tasks our playbook is going to perform, we can run our playbook and create our webserver and load balancer.
To run our playbook we use the following:
$ ansible-playbook create_loadbalancer_playbook.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Create loadbalancer and add a simple webserver] ***************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************
ok: [localhost]
TASK [Create a simple webserver] ************************************************************************************************************************************
ok: [localhost]
TASK [Gather facts about webserver] *********************************************************************************************************************************
ok: [localhost]
TASK [Create the openstack loadbalancer] ****************************************************************************************************************************
ok: [localhost]
TASK [Create a health monitor for our load balancer] ****************************************************************************************************************
ok: [localhost]
PLAY RECAP **********************************************************************************************************************************************************
localhost : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Once your playbook has completed, you should be able to see your loadbalancer on your project:
$ openstack loadbalancer list
+--------------------------------------+------------+----------------------------------+--------------+---------------------+------------------+----------+
| id | name | project_id | vip_address | provisioning_status | operating_status | provider |
+--------------------------------------+------------+----------------------------------+--------------+---------------------+------------------+----------+
| a797a67d-bab5-4ae5-af30-xxxxxxxxxxxx | ansible-lb | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | 192.168.0.39 | ACTIVE | ONLINE | amphora |
+--------------------------------------+------------+----------------------------------+--------------+---------------------+------------------+----------+
To delete your resources you will need to construct another Ansible playbook. With the variable names that you used in the previous playbook, you will need to fill out the following template.This playbook will delete the webserver, loadbalancer, and healthmonitor created in the previous playbook:
#!/usr/bin/env ansible-playbook
#
---
- name: Clean up the resources from the previous playbook
hosts: localhost
vars:
vm_name: <insert_webserver_name>
lb_name: <insert_load_balancer_name>
health_monitor: <insert_health_monitor_name>
tasks:
- name: Gather facts about webserver
openstack.cloud.server_info:
server: "{{ vm_name }}"
- name: Remove the openstack loadbalancer
openstack.cloud.loadbalancer:
state: absent
name: "{{ lb_name }}"
- name: Remove the webserver
openstack.cloud.server:
state: absent
name: "{{ vm_name }}"
Once you have set your variables you simply run the playbook like we did previously:
$ ansible-playbook remove_loadbalancer_playbook.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Clean up the resources from the previous playbook] ************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************
ok: [localhost]
TASK [Gather facts about webserver] *********************************************************************************************************************************
ok: [localhost]
TASK [Remove the openstack loadbalancer] ****************************************************************************************************************************
changed: [localhost]
PLAY RECAP **********************************************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0