haproxy

Ansible HAproxy (готовый для OpenStack)

CI Ansible Galaxy

Эта роль поддерживает установку HAproxy на современных дистрибутивах:

  • Rocky Linux 8 / 9
  • Fedora 37 / 38 / 39
  • Debian 10 / 11 / 12
  • Ubuntu 18.04 / 20.04 / 22.04

Роль позволяет настраивать несколько секций HAproxy:

  • Глобальная секция
  • Секция по умолчанию
  • Секция прослушивания
  • Секция фронтенда
  • Секция бэкенда
  • Секция пира
  • Секция статистики

Требования

Эта роль требует как минимум HAproxy 1.5 (поддержка SSL) и Ansible 2.8.

Переменные роли

В директории vars нет переменных, все переменные могут быть переопределены через плейбук.

Пустая переменная, такая как haproxy_global_uid, появится в /etc/haproxy/haproxy.cfg, только если будет определено значение.

Переменные, такие как haproxy_global_stats: [], являются массивами, в этом примере массив пустой. Эту переменную можно объявить двумя способами:

haproxy_global_stats:
  - show-legends
  - show-node
  - refresh 20s
# файл: roles/haproxy/defaults/main.yml
# Sysctl
haproxy_bind_nonlocal_ip: true
haproxy_ip_forward: true

# Общие настройки
haproxy_mode: system  # или docker
haproxy_firewalld: true
haproxy_selinux: true
haproxy_apt_backports: false
# значение по умолчанию для macOS и Docker; переопределяется в `vars/{{ ansible_os_family }}.yml`
haproxy_errors_directory: /usr/local/etc/haproxy/errors

# Настройки пакета
haproxy_package: haproxy
haproxy_selinux_packages:
  - python3-libselinux
  - python3-policycoreutils
haproxy_service: haproxy
haproxy_bin: haproxy
haproxy_config: /etc/haproxy/haproxy.cfg

# Брандмауэр
haproxy_fw_ports:
  - "{{ haproxy_stats_port }}/tcp"

# Глобальные настройки
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
# nbproc устарел. Будет удален в версии 2.5
# haproxy_global_nbproc: 8
# haproxy_global_cpu_maps: [ 1 0, 2 1, 3 2, 4 3, 5 4, 6 5, 7 6, 8 7 ]
haproxy_global_tunes:
  - tune.ssl.default-dh-param: 2048

# Секция по умолчанию
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:

# Список пользователей
haproxy_userlist:
  - stats-auth:
      groups:
        - "admin users admin"
        - "readonly users user"
      users:
        - "admin insecure-password opqrstuvw"
        - "user insecure-password abcdefghi"

# Статистика с HTTP 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

# Статистика с HTTP Basic Auth с использованием списка пользователей
haproxy_stats: true
haproxy_stats_address: "::"
haproxy_stats_port: 8081
haproxy_stats_ssl: false
haproxy_stats_uri: /stats
haproxy_stats_auth:
haproxy_stats_acls:
  - "AUTH http_auth(stats-auth)"
  - "AUTH_ADMIN http_auth_group(stats-auth) admin"
haproxy_stats_options:
  - refresh 5s
  - show-legends
  - show-node
  - http-request auth unless AUTH
  - admin if AUTH_ADMIN

# SSL
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
# смотрите больше деталей в `tasks/docker.yml` и https://docs.ansible.com/ansible/latest/collections/community/general/docker_container_module.html
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"

Зависимости

Нет

Пример плейбука

Приведенные ниже примеры показывают, как определить frontend, backend, listen, peer.

# Фронтенд
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
# Бэкенд
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
# Прослушивание
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 ctrl01inter 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
# Пир
haproxy_peer:
  - remote_peers:
      peers:
        - lb223 10.0.0.223:1024
        - lb224 10.0.0.224:1024
        - lb225 10.0.0.225:1024
# Резолверы
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'

Пример использования Docker

Вот короткий пример того, как использовать роль в другом плейбуке и запустить HAProxy в Docker.

# site.yml
- hosts: haproxy
  name: HAProxy балансировщик нагрузки
  tags:
    - all
    - haproxy
  # может быть включен как через `role`, так и через `include_role`
  # roles:
  #   - uoi-io.haproxy
  tasks:
    - include_role:
        name: uoi-io.haproxy
# (group_vars|environments/<my env>/group_vars/haproxy.yml)
haproxy_mode: docker
haproxy_config: "{{ docker_persistent_path }}/haproxy/haproxy.cfg"
haproxy_firewalld: false
haproxy_selinux: false
# Глобальные настройки
haproxy_global_chroot: ""
# SSL
haproxy_ssl_certificate: /usr/local/etc/haproxy/ssl/haproxy.crt
# Фронтенд
haproxy_frontend:
  # ... определение фронтенда
# Бэкенд
haproxy_backend_checks: "check inter 2000 rise 2 fall 5"
haproxy_backend:
  - my_backend:
      # ... определение бэкенда
      # пример, что хосты могут быть динамически связаны на основе другой группы
      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
haproxy_docker_ports:
  - "6443:6443"
  - "{{ haproxy_stats_port }}:{{ haproxy_stats_port }}"
# haproxy_docker_volumes: []
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"

Репозиторий для RedHat

Если у вас есть собственный репозиторий с HAProxy, вы можете установить файл репозитория. Следующий пример добавит репозиторий с HAProxy 2 для CentOS 8

# Репозиторий
haproxy_repo_yum:
  - name: haproxy
    description: HAProxy 2 репозиторий - $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

Тестирование

Эта роль использует ansible molecule. Вам просто нужно установить molecule через pip и запустить его. В настоящее время конфигурация molecule основана на драйвере docker.

apt/yum install docker
systemctl start docker
pip install docker molecule molecule-plugins pytest-testinfra
molecule test

Лицензия

Apache

Информация об авторе

Эта роль была создана в 2016 году Гаэтаном Треллю (goldyfruit).

Установить
ansible-galaxy install uoi-io/ansible-haproxy
Лицензия
apache-2.0
Загрузки
65415
Владелец