本节将演示如何使用 Ansible 自动化部署 HAProxy 负载均衡器,并结合 Apache Web 服务器实现后端服务的负载均衡。我们将通过配置主机清单、编写 Playbook 以及使用 Jinja2 模板动态生成 HAProxy 配置文件来完成整个部署流程。
配置主机清单
首先,在 Ansible 的主机清单文件 hosts 中定义两个主机组:[webservers] 用于存放后端 Web 服务器,[haproxy] 用于部署负载均衡器。同时,为 webservers 组设置变量 http_port。
ini
[kyy@server1 ansible]$ vim hosts
[webservers]
server2
host1
[webservers:vars]
http_port=80
[haproxy]
server1
编写 Keepalived 配置
(此部分为可选的高可用配置示例,用于停止 Keepalived 服务。)
yaml
[kyy@server1 ansible]$ vim keepalived.yml
- name: Start service keepalived
ansible.builtin.service:
name: keepalived
state: stopped
enabled: no
tags: t1
编写主部署 Playbook
创建主 Playbook 文件 haproxy.yml,其核心逻辑是:在 haproxy 组的主机上部署 HAProxy,在 webservers 组的主机上部署 Apache。
yaml
[kyy@server1 ansible]$ vim haproxy.yml
---
- hosts: haproxy,webservers
tasks:
- name: deploy haproxy
block:
- name: install haproxy
ansible.builtin.yum:
name: haproxy
state: present
- name: configure the haproxy
ansible.builtin.template:
src: haproxy.cfg.j2
dest: /etc/haproxy/haproxy.cfg
notify: restart service haproxy
- name: enable service haproxy
ansible.builtin.service:
name: haproxy
state: started
enabled: yes
when: ansible_hostname == 'server1'
name: deploy apache
block:
name: Install the Apache
ansible.builtin.yum:
name: httpd
state: present
name: Ensure the default Apache port is {{ http_port }}
ansible.builtin.template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: restart service httpd
name: Start service httpd, if not started
ansible.builtin.service:
name: httpd
state: started
enabled: yes
name: create index.html
ansible.builtin.copy:
content: "{{ ansible_hostname }}\n"
dest: /var/www/html/index.html
when: ansible_hostname in groups['webservers']
handlers:
name: restart service haproxy
ansible.builtin.service:
name: haproxy
state: restarted
name: restart service httpd
ansible.builtin.service:
name: httpd
state: restarted</code></pre>
6.4 准备 HAProxy 配置模板
将现有的 HAProxy 配置文件复制为 Jinja2 模板 haproxy.cfg.j2,并修改其内容,使其能动态引用 webservers 组中所有主机的信息。
[kyy@server1 ansible]$ ansible-playbook haproxy.yml --syntax-check
playbook: haproxy.yml
[kyy@server1 ansible]$ cp /etc/haproxy/haproxy.cfg .
[kyy@server1 ansible]$ mv haproxy.cfg haproxy.cfg.j2
[kyy@server1 ansible]$ vim haproxy.cfg.j2
frontend main
bind *:80
default_backend app
#---------------------------------------------------------------------
round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
balance roundrobin
{% for host in groups['webservers'] %}
server {{ hostvars[host].ansible_hostname }} {{ hostvars[host].ansible_eth0.ipv4.address }}:{{ hostvars[host].http_port }} check
{% endfor %}
6.5 执行 Playbook 并验证
执行 Playbook,Ansible 将根据主机名自动判断任务执行目标:在 server1(haproxy组)上安装并配置 HAProxy,在 server2 和 host1(webservers组)上安装 Apache。
[kyy@server1 ansible]$ ansible-playbook haproxy.yml
PLAY [haproxy,webservers]
TASK [Gathering Facts]
ok: [host1]
ok: [server2]
ok: [server1]
TASK [install haproxy]
skipping: [server2]
skipping: [host1]
ok: [server1]
TASK [configure the haproxy]
skipping: [server2]
skipping: [host1]
changed: [server1]
TASK [enable service haproxy]
skipping: [server2]
skipping: [host1]
changed: [server1]
TASK [Install the Apache]
skipping: [server1]
ok: [host1]
ok: [server2]
TASK [Ensure the default Apache port is {{ http_port }}]
skipping: [server1]
ok: [host1]
ok: [server2]
TASK [Start service httpd, if not started]
skipping: [server1]
ok: [host1]
ok: [server2]
TASK [create index.html]
skipping: [server1]
ok: [host1]
ok: [server2]
RUNNING HANDLER [restart service haproxy]
changed: [server1]
PLAY RECAP
host1 : ok=5 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
server1 : ok=5 changed=3 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
server2 : ok=5 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
部署完成后,在浏览器中访问负载均衡器的 IP 地址(例如 192.168.223.161:80),HAProxy 将按照轮询(round-robin)策略将请求分发到后端的 Apache 服务器,从而实现负载均衡。
编写haproxy.cfg.j2:模板源文件
编辑 Jinja2 模板,在 backend 段添加循环代码,实现自动读取主机组信息生成后端节点。
HAProxy 前端配置:监听本机所有网卡的 80 端口,所有请求默认转发至后端组
app。Jinja2 循环语句:
groups['webservers']获取清单中 webservers 分组全部主机;循环逐个取出主机存入变量 host,利用
hostvars读取对应主机信息,自动生成多条后端 server 配置;
{% endfor %}结束循环。实现无需手动书写每一台后端节点,动态生成 HAProxy 后端服务器列表。
cpp
[kyy@server1 ansible]$ ansible-playbook haproxy.yml --syntax-check
playbook: haproxy.yml
[kyy@server1 ansible]$ cp /etc/haproxy/haproxy.cfg .
[kyy@server1 ansible]$ mv haproxy.cfg haproxy.cfg.j2
[kyy@server1 ansible]$ vim haproxy.cfg.j2
frontend main
bind *:80
default_backend app
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
balance roundrobin
{% for host in groups['webservers'] %}
server {{ hostvars[host].ansible_hostname }} {{ hostvars[host].ansible_eth0.ipv4.address }}:{{ hostvars[host].http_port }} check
{% endfor %}
运行playbook,成功
java
[kyy@server1 ansible]$ ansible-playbook haproxy.yml
[kyy@server1 ansible]$ ansible-playbook haproxy.yml
PLAY [haproxy,webservers]
TASK [Gathering Facts]
ok: [host1]
ok: [server2]
ok: [server1]
TASK [install haproxy]
skipping: [server2]
skipping: [host1]
ok: [server1]
TASK [configure the haproxy]
skipping: [server2]
skipping: [host1]
changed: [server1]
TASK [enable service haproxy]
skipping: [server2]
skipping: [host1]
changed: [server1]
TASK [Install the Apache]
skipping: [server1]
ok: [host1]
ok: [server2]
TASK [Ensure the default Apache port is {{ http_port }}]
skipping: [server1]
ok: [host1]
ok: [server2]
TASK [Start service httpd, if not started]
skipping: [server1]
ok: [host1]
ok: [server2]
TASK [create index.html]
skipping: [server1]
ok: [host1]
ok: [server2]
RUNNING HANDLER [restart service haproxy]
changed: [server1]
PLAY RECAP
host1 : ok=5 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
server1 : ok=5 changed=3 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
server2 : ok=5 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
浏览器访问192.168.223.161:80


出现的效果是server2,host1轮换出现,说明haproxy部署成功,实现了负载均衡