How to configure HAProxy and automatic updation of it’s configuration file each time managed node is added using Ansible

Satyam Singh
7 min readMar 23, 2021

Hello Fellow Programmers !!!

Today I would like to share step by step procedure to configure HAProxy and update it’s configuration file automatically each time new Managed Node configured with Apache Webserver joins the inventory.

Content of this Blog

  • About Ansible
  • About HAProxy
  • About Apache HTTPD Webserver
  • Project Understanding

About Ansible

What is Ansible ?

Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.

Why use Ansible ?

  1. Simple
  • Human readable automation
  • No special coding skills needed
  • Tasks executed in order
  • Get productive quickly

2. Powerful

  • App deployment
  • Configuration management
  • Workflow orchestration
  • Orchestrate the app lifecycle

3. Agentless

  • Agentless architecture
  • Uses OpenSSH and WinRM
  • No agents to exploit or update
  • Predictable, reliable and secure

Ansible Documentation :

About HAProxy

  • HAProxy is free, open source software that provides a high availability load balancer and proxy server for TCP and HTTP-based applications that spreads requests across multiple servers.
  • It’s written in C and has a reputation for being fast and efficient in terms of processor and memory usage.

HAProxy Documentation :

About Apache HTTPD Webserver

  • The Apache HTTP Server, colloquially called Apache, is a free and open-source cross-platform web server software, released under the terms of Apache License 2.0.
  • Apache is developed and maintained by an open community of developers under the auspices of the Apache Software Foundation.
  • The vast majority of Apache HTTP Server instances run on a Linux distribution, but current versions also run on Microsoft Windows, OpenVMS and a wide variety of Unix-like systems.

Apache HTTPD Documentation :

Project Understanding

Let’s understand its implementation part by part

Part 1 : Ansible Playbook (main.yml)

1. Common Tasks

  • “Creation of directory to be mounted” : Creation of Mount Directory
- name: Creation of directory to be mounted
file:
state: directory
path: "{{ mount_directory }}"
  • “Mounting directory created to CDROM” : Mount the directory created in previous task to the CDROM
- name: Mounting directory created to CDROM
mount:
src: "/dev/cdrom"
path: "{{ mount_directory }}"
state: mounted
fstype: "iso9660"
  • “YUM Repository -AppStream” : Addition of AppStream YUM repository
- name: YUM Repository - AppStream
yum_repository:
baseurl: "{{ mount_directory }}/AppStream"
name: "DVD1"
description: "YUM Repository - AppStream"
enabled: true
gpgcheck: no
  • “YUM Repository-BaseOS” : Addition of BaseOS YUM repository
- name: YUM Repository - BaseOS
yum_repository:
baseurl: "{{ mount_directory }}/BaseOS"
name: "DVD2"
description: "YUM Repository - BaseOS"
enabled: true
gpgcheck: no
  • “Stopping Firewall Service” : Stops Firewall Service
- name: Stopping Firewall Service
service:
name: "firewalld"
state: stopped
enabled: yes
  • “Setting SELinux Permissive” : Sets SELinux state to permissive
- name: Setting SELinux Permissive
selinux:
policy: targeted
state: permissive

2. loadbalancer (HAProxy)

  • “Installation of HAProxy Software” : Installs HAProxy Software
- name: Installation of HAProxy Software
package:
name: "haproxy"
state: present
  • “HAProxy Configuration File Setup” : Copies the configuration file from templates directory in the Controller Node to the default path of HAProxy configuration file in the Managed Node
- name: HAProxy Configuration File Setup
template:
dest: "/etc/haproxy/haproxy.cfg"
src: "templates/haproxy.cfg"
notify: Restart Load Balancer
  • “Starting Load Balancer Service” : Starts HAProxy Service
- name: Starting Load Balancer Service
service:
name: "haproxy"
state: started
enabled: yes
  • handlers -“Restart Load Balancer” : Restarts HAProxy service in case of change in configuration file(when new managed node configured with Httpd Webserver is added)
- name: Restart Load Balancer
systemd:
name: "haproxy"
state: restarted
enabled: yes

3. webserver (Apache Httpd)

  • “HTTPD Installation” : Installs Apache Httpd Software only when ansible_distribution is RedHat
- name: HTTPD Installation
package:
name: "httpd"
state: present
when: ansible_distribution == "RedHat"
  • “Web Page Setup” : Copies the web page from web directory in Controller Node to the Document Root in the Managed Node
- name: Web Page Setup
template:
dest: "/var/www/html"
src: "web/index.html"
  • “Starting HTTPD Service” : Starts Httpd Service
- name: Starting HTTPD Service
service:
name: "httpd"
state: started
enabled: yes

4. Complete Playbook

- hosts: loadbalancer
vars_files:
- vars.yml
tasks:
- name: Creation of directory to be mounted
file:
state: directory
path: "{{ mount_directory }}"
- name: Mounting directory created to CDROM
mount:
src: "/dev/cdrom"
path: "{{ mount_directory }}"
state: mounted
fstype: "iso9660"
- name: YUM Repository - AppStream
yum_repository:
baseurl: "{{ mount_directory }}/AppStream"
name: "DVD1"
description: "YUM Repository - AppStream"
enabled: true
gpgcheck: no
- name: YUM Repository - BaseOS
yum_repository:
baseurl: "{{ mount_directory }}/BaseOS"
name: "DVD2"
description: "YUM Repository - BaseOS"
enabled: true
gpgcheck: no
- name: Installation of HAProxy Software
package:
name: "haproxy"
state: present
- name: HAProxy Configuration File Setup
template:
dest: "/etc/haproxy/haproxy.cfg"
src: "templates/haproxy.cfg"
notify: Restart Load Balancer
- name: Starting Load Balancer Service
service:
name: "haproxy"
state: started
enabled: yes
- name: Stopping Firewall Service
service:
name: "firewalld"
state: stopped
enabled: yes
- name: Setting SELinux Permissive
selinux:
policy: targeted
state: permissive
handlers:
- name: Restart Load Balancer
systemd:
name: "haproxy"
state: restarted
enabled: yes
- hosts: webserver
vars_files:
- vars.yml
tasks:
- name: Creation of directory to be mounted
file:
state: directory
path: "{{ mount_directory }}"
- name: Mounting directory created to CDROM
mount:
src: "/dev/cdrom"
path: "{{ mount_directory }}"
state: mounted
fstype: "iso9660"
- name: YUM Repository - AppStream
yum_repository:
baseurl: "{{ mount_directory }}/AppStream"
name: "DVD1"
description: "YUM Repository - AppStream"
gpgcheck: no
- name: YUM Repository - BaseOS
yum_repository:
baseurl: "{{ mount_directory }}/BaseOS"
name: "DVD2"
description: "YUM Repository - BaseOS"
gpgcheck: no
- name: HTTPD Installation
package:
name: "httpd"
state: present
when: ansible_distribution == "RedHat"
- name: Web Page Setup
template:
dest: "/var/www/html"
src: "web/index.html"
- name: Setting SELinux Permissive
selinux:
policy: targeted
state: permissive
- name: Stopping Firewall Service
service:
name: "firewalld"
state: stopped
enabled: yes
- name: Starting HTTPD Service
service:
name: "httpd"
state: started
enabled: yes

— — — — — — — — — — — — — — — — — — — — — — — — —

Part 2 : Variable Files (vars.yml)

mount_directory: "/dvd1"

— — — — — — — — — — — — — — — — — — — — — — — — —

Part 3 : Web Page (index.html)

<body bgcolor='aqua'>
<br><br>
<b>IP Addresses</b> : "{{ ansible_all_ipv4_addresses }}"

Specifies Web Page that is accessed from Load Balancer’s IP Address

— — — — — — — — — — — — — — — — — — — — — — — — —

Part 4 : HAProxy Configuration File Template (haproxy.cfg)

#---------------------------------------------------------------------
# Example configuration for a possible web application. See the
# full configuration options online.
#
#
https://www.haproxy.org/download/1.8/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
# utilize system-wide crypto-policies
ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend main
bind *:8080
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .gif .png .css .js
use_backend static if url_static
default_backend app
#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
backend static
balance roundrobin
server static 127.0.0.1:4331 check
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
balance roundrobin
{% for hosts in groups['webserver'] %}
server app1 {{ hosts }}:80 check
{% endfor %}

Jinja template and for loop specified above makes HAProxy configuration file more dynamic as it would add managed nodes specified under ‘webserver’ host dynamically.

— — — — — — — — — — — — — — — — — — — — — — — — —

Part 5 : Output

  1. loadbalancer
HAProxy Configuration File after Ansible Playbook Execution-1
HAProxy Configuration File after Ansible Playbook Execution-2
HAProxy Configuration File after Ansible Playbook Execution-3

2. webserver

Webserver 1
Webserver 2

3. Output GIF

--

--