Ansible – HAProxy
In this previous post I setup KeepAliveD using a fictitious tenant using Ansible. In this post I will be building upon that same configuration and creating the HAProxy setup.
Below is the vars/tenant_1.yml file that contains the specific tenant variables that will be used.
---
tenant_name: tenant_1
config_forward_rules_allow_spec: 'false' # set to true to configure specific firewall rules under forward_rules_allow_spec
tenant_subnets:
- { tenant_subnet: '192.168.70.0/24' } # Web
- { tenant_subnet: '192.168.71.0/24' } # App
- { tenant_subnet: '192.168.72.0/24' } # DB
tenant_vips:
- 10.10.10.100
- 10.10.10.101
- 10.10.10.102
- 10.10.10.103
- 10.10.10.104
###### Firewall Setup ######
###### Note.....Firewall rules are by default dropped in default setup ######
# Port specific rules - used to add firewall rules that should be port based rules **Note...SSH is allowed by default so there is no need to specify rules for SSH.
# Another note is that when configuring load balancer setup further down...The ports that will be load balanced will be added to the firewall by default as well.
# This section will normally be used to allow a specific port to a host|subnet etc. which does not require load balancing.
# Make sure to change config_forward_rules_allow_spec at the top to true to ensure the below firewall rules are applied.
forward_rules_allow_spec:
- { protocol: 'tcp', port: '8080', source: '0.0.0.0/0', destination: '192.168.70.0/24' }
# Generic non port specific rules to allow. Ex. allowing a host|subnet to communicate from|to one another on every port available.
forward_rules_allow_gen:
- { source: '192.168.70.0/24', destination: '0.0.0.0/0' }
- { source: '192.168.71.0/24', destination: '0.0.0.0/0' }
- { source: '192.168.72.0/24', destination: '0.0.0.0/0' }
# Define specific rules below to be dropped by firewall. Ex. explicitly denying communications between hosts|subnets.
forward_rules_out_drop:
- { source: '192.168.70.0/24', destination: '192.168.71.0/24' }
- { source: '192.168.70.0/24', destination: '192.168.72.0/24' }
- { source: '192.168.71.0/24', destination: '192.168.70.0/24' }
- { source: '192.168.71.0/24', destination: '192.168.72.0/24' }
- { source: '192.168.72.0/24', destination: '192.168.70.0/24' }
- { source: '192.168.72.0/24', destination: '192.168.71.0/24' }
###### Load Balancer Setup ######
# Allocate vips from tenant_vips assigned above....these will be used as variables for lb_details and lb_defs. You may choose to just enter IP addresses though.
web_vip: '10.10.10.100'
db_vip: '10.10.10.101'
app_vip: '10.10.10.102'
balance_method: 'roundrobin' # Set to one of the below types to configure load balancing method
#leastconn - The server with the lowest number of connections receives the connection
#roundrobin - Each server is used in turns, according to their weights.
#source - Source IP hashed and divided by total weight of servers designates which server will receive the request
# Defines the load balancing group setup
lb_details:
- { name: 'web', protocol: 'tcp', listen_port: '80', tenant_vip: '{{ web_vip }}', balance_type: '{{ balance_method }}' }
- { name: 'db', protocol: 'tcp', listen_port: '3306', tenant_vip: '{{ db_vip }}', balance_type: '{{ balance_method }}' }
- { name: 'rabbitmq-mgmt', protocol: 'tcp', listen_port: '15672', tenant_vip: '{{ app_vip }}', balance_type: '{{ balance_method }}' }
- { name: 'redis', protocol: 'tcp', listen_port: '6379', tenant_vip: '{{ app_vip }}', balance_type: '{{ balance_method }}' }
- { name: 'rabbitmq', protocol: 'tcp', listen_port: '5672', tenant_vip: '{{ app_vip }}', balance_type: '{{ balance_method }}' }
# Defines the load balancing servers within the load balancing group
lb_defs:
- { lb_def_name: 'web', protocol: 'tcp', listen_port: '80', tenant_vip: '{{ web_vip }}', lb_group: 'web', server: 'ans-cloud-web01', backend_port: '80' }
- { lb_def_name: 'web', protocol: 'tcp', listen_port: '80', tenant_vip: '{{ web_vip }}', lb_group: 'web', server: 'ans-cloud-web02', backend_port: '80' }
- { lb_def_name: 'web', protocol: 'tcp', listen_port: '80', tenant_vip: '{{ web_vip }}', lb_group: 'web', server: 'ans-cloud-web03', backend_port: '80' }
- { lb_def_name: 'db', protocol: 'tcp', listen_port: '3306', tenant_vip: '{{ db_vip }}', lb_group: 'db', server: 'ans-cloud-db01', backend_port: '3306' }
- { lb_def_name: 'db', protocol: 'tcp', listen_port: '3306', tenant_vip: '{{ db_vip }}', lb_group: 'db', server: 'ans-cloud-db02', backend_port: '3306' }
- { lb_def_name: 'rabbitmq-mgmt', protocol: 'tcp', listen_port: '15672', tenant_vip: '{{ app_vip }}', lb_group: 'rabbitmq-mgmt', server: 'ans-cloud-app01', backend_port: '15672' }
- { lb_def_name: 'rabbitmq-mgmt', protocol: 'tcp', listen_port: '15672', tenant_vip: '{{ app_vip }}', lb_group: 'rabbitmq-mgmt', server: 'ans-cloud-app02', backend_port: '15672' }
- { lb_def_name: 'rabbitmq-mgmt', protocol: 'tcp', listen_port: '15672', tenant_vip: '{{ app_vip }}', lb_group: 'rabbitmq-mgmt', server: 'ans-cloud-app03', backend_port: '15672' }
- { lb_def_name: 'redis', protocol: 'tcp', listen_port: '6379', tenant_vip: '{{ app_vip }}', lb_group: 'redis', server: 'ans-cloud-app01', backend_port: '6379' }
- { lb_def_name: 'redis', protocol: 'tcp', listen_port: '6379', tenant_vip: '{{ app_vip }}', lb_group: 'redis', server: 'ans-cloud-app02', backend_port: '6379' }
- { lb_def_name: 'redis', protocol: 'tcp', listen_port: '6379', tenant_vip: '{{ app_vip }}', lb_group: 'redis', server: 'ans-cloud-app03', backend_port: '6379' }
- { lb_def_name: 'rabbitmq', protocol: 'tcp', listen_port: '5672', tenant_vip: '{{ app_vip }}', lb_group: 'rabbitmq', server: 'ans-cloud-app01', backend_port: '5672' }
- { lb_def_name: 'rabbitmq', protocol: 'tcp', listen_port: '5672', tenant_vip: '{{ app_vip }}', lb_group: 'rabbitmq', server: 'ans-cloud-app02', backend_port: '5672' }
- { lb_def_name: 'rabbitmq', protocol: 'tcp', listen_port: '5672', tenant_vip: '{{ app_vip }}', lb_group: 'rabbitmq', server: 'ans-cloud-app03', backend_port: '5672' }
Below is the haproxy.cfg.j2 template that I will use.
# {{ ansible_managed }}
global
# log logstash local0 #Change logstash to your naming
log /dev/log local0
log /dev/log local1 notice
# log-send-hostname
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
maxconn 40000
spread-checks 3
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL).
ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL
ssl-default-bind-options no-sslv3
defaults
log global
mode tcp
maxconn 40000
option httplog
option dontlognull
option redispatch
option tcp-smart-accept
option tcp-smart-connect
retries 3
timeout queue 5000
timeout connect 50000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
userlist STATSUSERS
group admin users admin
user admin insecure-password admin
listen admin_page 0.0.0.0:9090
mode http
stats enable
stats refresh 60s
stats uri /
acl AuthOkay_ReadOnly http_auth(STATSUSERS)
acl AuthOkay_Admin http_auth_group(STATSUSERS) admin
stats http-request auth realm admin_page unless AuthOkay_ReadOnly
{% for lb_group_def in lb_details %}
listen {{ tenant_name }}_{{ lb_group_def.name }}-{{ lb_group_def.tenant_vip }}:{{ lb_group_def.listen_port }} {{ lb_group_def.tenant_vip }}:{{ lb_group_def.listen_port }}
mode tcp
option tcpka
option tcplog
#balance leastconn - The server with the lowest number of connections receives the connection
#balance roundrobin - Each server is used in turns, according to their weights.
#balance source - Source IP hashed and divided by total weight of servers designates which server will receive the request
balance {{ lb_group_def.balance_type }}
default-server inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 256 maxqueue 128 weight 100
{% for item in lb_defs %}
{% if item.lb_group == lb_group_def.name %}
server {{ item.server }} {{ item.server }}:{{ item.backend_port }} check
{% endif %}
{% endfor %}
{% endfor %}
And below is what we end up with as an haproxy.cfg for our setup by using the variables and template above.
# Ansible managed: /home/administrator/ansible/projects/ans-cloud-rt01/templates/etc/haproxy/haproxy.cfg.j2 modified on 2015-04-10 12:58:14 by administrator on ansible
global
# log logstash local0 #Change logstash to your naming
log /dev/log local0
log /dev/log local1 notice
# log-send-hostname
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
maxconn 40000
spread-checks 3
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL).
ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL
ssl-default-bind-options no-sslv3
defaults
log global
mode tcp
maxconn 40000
option httplog
option dontlognull
option redispatch
option tcp-smart-accept
option tcp-smart-connect
retries 3
timeout queue 5000
timeout connect 50000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
userlist STATSUSERS
group admin users admin
user admin insecure-password admin
listen admin_page 0.0.0.0:9090
mode http
stats enable
stats refresh 60s
stats uri /
acl AuthOkay_ReadOnly http_auth(STATSUSERS)
acl AuthOkay_Admin http_auth_group(STATSUSERS) admin
stats http-request auth realm admin_page unless AuthOkay_ReadOnly
listen tenant_1_web-10.10.10.100:80 10.10.10.100:80
mode tcp
option tcpka
option tcplog
#balance leastconn - The server with the lowest number of connections receives the connection
#balance roundrobin - Each server is used in turns, according to their weights.
#balance source - Source IP hashed and divided by total weight of servers designates which server will receive the request
balance roundrobin
default-server inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 256 maxqueue 128 weight 100
server ans-cloud-web01 ans-cloud-web01:80 check
server ans-cloud-web02 ans-cloud-web02:80 check
server ans-cloud-web03 ans-cloud-web03:80 check
listen tenant_1_db-10.10.10.101:3306 10.10.10.101:3306
mode tcp
option tcpka
option tcplog
#balance leastconn - The server with the lowest number of connections receives the connection
#balance roundrobin - Each server is used in turns, according to their weights.
#balance source - Source IP hashed and divided by total weight of servers designates which server will receive the request
balance roundrobin
default-server inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 256 maxqueue 128 weight 100
server ans-cloud-db01 ans-cloud-db01:3306 check
server ans-cloud-db02 ans-cloud-db02:3306 check
listen tenant_1_rabbitmq-mgmt-10.10.10.102:15672 10.10.10.102:15672
mode tcp
option tcpka
option tcplog
#balance leastconn - The server with the lowest number of connections receives the connection
#balance roundrobin - Each server is used in turns, according to their weights.
#balance source - Source IP hashed and divided by total weight of servers designates which server will receive the request
balance roundrobin
default-server inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 256 maxqueue 128 weight 100
server ans-cloud-app01 ans-cloud-app01:15672 check
server ans-cloud-app02 ans-cloud-app02:15672 check
server ans-cloud-app03 ans-cloud-app03:15672 check
listen tenant_1_redis-10.10.10.102:6379 10.10.10.102:6379
mode tcp
option tcpka
option tcplog
#balance leastconn - The server with the lowest number of connections receives the connection
#balance roundrobin - Each server is used in turns, according to their weights.
#balance source - Source IP hashed and divided by total weight of servers designates which server will receive the request
balance roundrobin
default-server inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 256 maxqueue 128 weight 100
server ans-cloud-app01 ans-cloud-app01:6379 check
server ans-cloud-app02 ans-cloud-app02:6379 check
server ans-cloud-app03 ans-cloud-app03:6379 check
listen tenant_1_rabbitmq-10.10.10.102:5672 10.10.10.102:5672
mode tcp
option tcpka
option tcplog
#balance leastconn - The server with the lowest number of connections receives the connection
#balance roundrobin - Each server is used in turns, according to their weights.
#balance source - Source IP hashed and divided by total weight of servers designates which server will receive the request
balance roundrobin
default-server inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 256 maxqueue 128 weight 100
server ans-cloud-app01 ans-cloud-app01:5672 check
server ans-cloud-app02 ans-cloud-app02:5672 check
server ans-cloud-app03 ans-cloud-app03:5672 check
Below is the group_vars code used across the different Ansible posts based on tenant setup