uoi-io.haproxy
Ansible HAproxy (Ready for OpenStack)
This tool helps you install HAproxy on recent Linux versions:
- Rocky Linux 8 / 9
- Fedora 37 / 38 / 39
- Debian 10 / 11 / 12
- Ubuntu 18.04 / 20.04 / 22.04
You can set up different parts of HAproxy using this tool:
- Global settings
- Default settings
- Listen settings
- Frontend settings
- Backend settings
- Peer settings
- Stats settings
Requirements
You need at least HAproxy 1.5 (with SSL support) and Ansible 2.8.
Role Variables
There are no variables in the vars
folder; all variables can be changed in the playbook.
If you leave a variable like haproxy_global_uid
empty, it will show up in the /etc/haproxy/haproxy.cfg
only if given a value.
Some variables like haproxy_global_stats: []
are lists (arrays). In this case, the list is empty. You can define this variable in two ways:
haproxy_global_stats:
- show-legends
- show-node
- refresh 20s
# file: roles/haproxy/defaults/main.yml
# Sysctl settings
haproxy_bind_nonlocal_ip: true
haproxy_ip_forward: true
# Common settings
haproxy_mode: system # or docker
haproxy_firewalld: true
haproxy_selinux: true
haproxy_apt_backports: false
haproxy_errors_directory: /usr/local/etc/haproxy/errors # default for macOS & Docker
# Package settings
haproxy_package: haproxy
haproxy_selinux_packages:
- python3-libselinux
- python3-policycoreutils
haproxy_service: haproxy
haproxy_bin: haproxy
haproxy_config: /etc/haproxy/haproxy.cfg
# Firewall settings
haproxy_fw_ports:
- "{{ haproxy_stats_port }}/tcp"
# Global settings
haproxy_global_maxconn: 4000
haproxy_global_chroot: /var/lib/haproxy
haproxy_global_group: haproxy
haproxy_global_user: haproxy
haproxy_global_uid:
haproxy_global_gid:
haproxy_global_pidfile: /var/run/haproxy.pid
haproxy_global_ca_base:
haproxy_global_crt_base:
haproxy_global_ssl_bind_options:
haproxy_global_ssl_bind_ciphers:
haproxy_global_ssl_bind_ciphersuites:
haproxy_global_ssl_server_options:
haproxy_global_ssl_server_ciphers:
haproxy_global_ssl_server_ciphersuites:
haproxy_global_ssl_server_verify:
haproxy_global_stats: []
haproxy_global_description:
haproxy_global_ulimit_n:
haproxy_global_logs:
- 127.0.0.1 local0 debug
haproxy_global_daemon: true
haproxy_global_tunes:
- tune.ssl.default-dh-param: 2048
# Default settings
haproxy_default_logs:
- global
haproxy_default_log_format:
haproxy_default_mode:
haproxy_default_maxconn: 4000
haproxy_default_options:
- dontlognull
- forwardfor
- http-server-close
haproxy_default_retries: 3
haproxy_default_timeouts:
- http-request 10s
- queue 1m
- connect 10s
- client 1m
- server 1m
- http-keep-alive 10s
- check 10s
haproxy_default_balance:
haproxy_default_errorfiles:
- "400 {{ haproxy_errors_directory }}/400.http"
- "403 {{ haproxy_errors_directory }}/403.http"
haproxy_default_http_check:
haproxy_default_monitor_uri:
haproxy_default_unique_id_format:
# Userlist
haproxy_userlist:
- stats-auth:
groups:
- "admin users admin"
- "readonly users user"
users:
- "admin insecure-password opqrstuvw"
- "user insecure-password abcdefghi"
# Stats with Basic Auth
haproxy_stats: true
haproxy_stats_address: '*'
haproxy_stats_port: 9001
haproxy_stats_ssl: false
haproxy_stats_user: haproxy-stats
haproxy_stats_password: B1Gp4sSw0rD!!
haproxy_stats_uri: /
haproxy_stats_options:
- refresh 20s
- show-legends
- show-node
- hide-version
haproxy_stats_http_requests:
- use-service prometheus-exporter if { path /metrics }
haproxy_stats_listener_options:
- dontlog-normal
haproxy_stats_timeouts:
- client 100s
- server 100s
- connect 100s
- queue 100s
# SSL settings
haproxy_ssl_certificate: /etc/ssl/uoi.io/uoi.io.pem
haproxy_ssl_options: no-sslv3 no-tls-tickets force-tlsv12
haproxy_ssl_ciphers: AES128+EECDH:AES128+EDH
haproxy_ssl: 'ssl crt {{ haproxy_ssl_certificate }} ciphers {{ haproxy_ssl_ciphers }} {{ haproxy_ssl_options }}'
# Docker settings
haproxy_docker_name: "haproxy"
haproxy_docker_image: "haproxy:alpine"
haproxy_docker_network_mode: default
haproxy_docker_network_name: "haproxy"
haproxy_docker_pull: true
haproxy_docker_recreate: false
haproxy_docker_ports:
- "8443:8443"
- "{{ haproxy_stats_port }}:{{ haproxy_stats_port }}"
haproxy_docker_sysctls:
net.ipv4.ip_nonlocal_bind: "{{ 1 if haproxy_bind_nonlocal_ip|bool else 0 }}"
net.ipv4.ip_forward: "{{ 1 if haproxy_ip_forward|bool else 0 }}"
net.core.somaxconn: 4096
net.ipv4.tcp_syncookies: 1
haproxy_docker_ulimits:
- "nofile:262144:262144"
haproxy_docker_volumes:
- {{ haproxy_config }}+":/usr/local/etc/haproxy/haproxy.cfg:ro"
Dependencies
None
Example Playbook
Here are examples showing how to set up frontend
, backend
, listen
, and peer
.
# Frontend
haproxy_frontend:
- dashboard_cluster:
binds_ssl:
- :443 ssl crt /etc/ssl/uoi.io/uoi.io.pem no-sslv3
reqadds:
- X-Forwarded-Proto:\ https
default_backend: dashboard_backend
logs:
- 127.0.0.1 local0 debug
acls:
- url_static path_beg -i /static /images /javascript /stylesheets
- url_static path_end -i .jpg .gif .png .css .js
bind_process:
- 1
log_formats:
- "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
use_backends:
- static if url_static
capture:
- request header Host len 64
- request header X-Forwarded-For len 64
# Backend
haproxy_backend:
- dashboard_backend:
balance: source
default_server: "inter 2s downinter 5s rise 3 fall 2 slowstart 30s maxconn 30 maxqueue 64 weight 100"
http_checks:
- 'send meth GET uri /check-haproxy.php hdr Host haproxy.check-vhost.de'
- 'expect string "All services running fine"'
bind_process:
- 1
server_templates:
- srv 3 service.local:80 check resolvers mydns init-addr none
servers:
- ctrl01 10.0.0.67:80 check inter 2000 rise 2 fall 5
- ctrl02 10.0.0.68:80 check inter 2000 rise 2 fall 5
- ctrl03 10.0.0.69:80 check inter 2000 rise 2 fall 5
- static:
balance: roundrobin
compression:
- algo gzip deflate
- type text/css text/html application/javascript
bind_process:
- 1
servers:
- cnd01 10.0.0.70:8080 check
- cnd02 10.0.0.71:8080 check
- cnd03 10.0.0.71:8080 check
# Listen
haproxy_listen:
- dashboard_cluster:
mode: http
description: Horizon Dashboard
balance: roundrobin
default_server: "inter 2s downinter 5s rise 3 fall 2 slowstart 30s maxconn 30 maxqueue 64 weight 100"
binds:
- 10.0.0.100:80
binds_ssl:
- :443 ssl crt /etc/ssl/uoi.io/uoi.io.pem no-sslv3
options: [ tcpka, httpchk, tcplog ]
http-check: GET /auth/login
cookie: SERVERID insert indirect nocache
capture:
- cookie SERVERID len 32
timeouts:
- client 90m
- server 90m
bind_process:
- 1
http_requests:
- set-header X-Haproxy-Current-Date %T
servers:
- ctrl01 10.0.0.67:80 check cookie ctrl01 inter 2000 rise 2 fall 5
- ctrl02 10.0.0.68:80 check cookie ctrl02 inter 2000 rise 2 fall 5
- ctrl03 10.0.0.69:80 check cookie ctrl03 inter 2000 rise 2 fall 5
- neutron_api_cluster:
binds_ssl:
- 10.0.0.100:9696 {{ haproxy_ssl }}
options: [ tcpka, httpchk, tcplog ]
bind_process: [ 2, 3, 4, 5, 6, 7 ]
balance: source
servers:
- ctrl01 10.0.0.62:9696 check inter 2000 rise 2 fall 5
- ctrl02 10.0.0.63:9696 check inter 2000 rise 2 fall 5
- ctrl03 10.0.0.64:9696 check inter 2000 rise 2 fall 5
# Peer
haproxy_peer:
- remote_peers:
peers:
- lb223 10.0.0.223:1024
- lb224 10.0.0.224:1024
- lb225 10.0.0.225:1024
# Resolvers
haproxy_resolvers:
- mydns:
nameservers:
- 'dns1 10.0.0.1:53'
- 'dns3 [email protected]:53'
parse_resolv_conf: true
resolve_retries: 5
timeouts:
- 'resolve 1s'
- 'retry 1s'
holds:
- 'other 30s'
- 'refused 30s'
- 'nx 30s'
- 'valid 30s'
Using with Docker
Here’s a simple example of using this tool in a playbook to run HAProxy inside Docker.
# site.yml
- hosts: haproxy
name: HAProxy load balancer
tags:
- all
- haproxy
tasks:
- include_role:
name: uoi-io.haproxy
# (group_vars|environments/<your_env>/group_vars/haproxy.yml)
haproxy_mode: docker
haproxy_config: "{{ docker_persistent_path }}/haproxy/haproxy.cfg"
haproxy_firewalld: false
haproxy_selinux: false
# Global settings
haproxy_global_chroot: ""
# SSL settings
haproxy_ssl_certificate: /usr/local/etc/haproxy/ssl/haproxy.crt
# Frontend
haproxy_frontend:
# ... frontend setup
# Backend settings
haproxy_backend_checks: "check inter 2000 rise 2 fall 5"
haproxy_backend:
- my_backend:
# ... backend setup
servers: |-
{%- set _list = [] %}
{%- for _host in groups['MY_BACKEND_GROUP'] %}
{%- set _list = _list.append(_host.split('.')[0] ~ ' ' ~ _host ~ ':' ~ MY_SERVICE_PORT ~ ' ' ~ haproxy_backend_checks) %}
{%- endfor %}
{{- _list }}
# Docker settings
haproxy_docker_ports:
- "6443:6443"
- "{{ haproxy_stats_port }}:{{ haproxy_stats_port }}"
haproxy_docker_volumes:
- "{{ haproxy_config }}:/usr/local/etc/haproxy/haproxy.cfg:ro"
- "{{ docker_persistent_path }}/haproxy/haproxy.key:/usr/local/etc/haproxy/ssl/haproxy.crt.key:ro"
- "{{ docker_persistent_path }}/haproxy/haproxy.crt:/usr/local/etc/haproxy/ssl/haproxy.crt:ro"
Custom Repository for RedHat
If you have your own repository for HAProxy, you can set it up easily. For example, here’s how to add a repository for HAProxy 2 on CentOS 8:
# Repository
haproxy_repo_yum:
- name: haproxy
description: HAProxy 2 repository - $basearch
baseurl: https://download.copr.fedorainfracloud.org/results/pzinchuk/haproxy/epel-8-$basearch/
priority: 1
gpgcheck: true
file: haproxy
repo_gpgcheck: false
skip_if_unavailable: true
gpgkey: https://download.copr.fedorainfracloud.org/results/pzinchuk/haproxy/pubkey.gpg
enabled: true
state: present
Testing
This tool uses Ansible Molecule.
You just need to install Molecule using pip
and run it. Currently, it’s set up to use the docker
driver.
apt/yum install docker
systemctl start docker
pip install docker molecule molecule-plugins pytest-testinfra
molecule test
License
Apache
Author Information
This tool was created in 2016 by Gaëtan Trellu (goldyfruit).
Install and configure HAproxy
ansible-galaxy install uoi-io.haproxy