1 创建测试目录和文件
[root@docker-a ~]# mkdir lee
[root@docker-a ~]# cd lee/
[root@docker-a lee]# touch docker-compose.yml # 容器编排工具Docker Compose 默认识别docker-compose.yml文件
2 编写docker-compose.yml文件和haproxy.cfg文件
2.1 核心配置说明
2.1.1 服务结构
- 共定义 3 个服务:
web1
、web2
(Nginx 网页服务)和haproxy
(负载均衡服务) - 形成 "负载均衡器 + 两个后端服务" 的经典架构,通过 Haproxy 分发请求到 web1 和 web2
2.1.2 网络通信
mynet1
是核心通信网络,三个服务都加入此网络,确保 Haproxy 能访问后端 Nginx- 容器间可通过容器名(如
web1
、web2
)直接通信(Docker 内置 DNS 解析) mynet2
为预留网络,可用于后续扩展其他服务(如添加数据库时使用)
2.1.3 数据持久化
- Nginx 的网页内容通过
volumes
挂载到宿主机,实现:- 宿主机直接修改网页内容(无需进入容器)
- 容器重建后数据不丢失(内容保存在宿主机)
2.1.4 端口策略
- Nginx 容器使用
expose: 80
:仅在内部网络暴露端口,外部无法直接访问(增强安全性) - Haproxy 使用
ports: 80:80
:将宿主机 80 端口开放,作为外部访问的唯一入口
2.1.5 重启策略
restart: always
确保服务在意外退出或服务器重启后自动恢复,提高可用性
2.2 工作流程
- 外部用户访问宿主机的 80 端口(如
http://192.168.36.101
) - 请求通过端口映射进入 Haproxy 容器的 80 端口
- Haproxy 根据
haproxy.cfg
中的配置(如轮询策略),将请求转发到web1:80
或web2:80
- Nginx 容器处理请求,返回
/usr/share/nginx/html
目录下的index.html
内容(来自宿主机挂载的目录)
2.3 编写docker-compose.yml文件
[root@docker-a lee]# vim docker-compose.yml
services:
# 第一个Nginx服务容器(web1)
web1:
# 使用的基础镜像:最新版Nginx
image: nginx:latest
# 容器的自定义名称(便于识别和操作)
container_name: web1
# 重启策略:总是重启(容器退出时自动重启,包括系统启动时)
restart: always
# 加入的网络(与Haproxy共享mynet1网络实现通信)
networks:
- mynet1
# 暴露容器内部端口(仅在容器所在网络内可见,外部无法直接访问)
expose:
- 80 # Nginx默认监听的端口
# 数据卷挂载(将宿主机目录与容器内目录关联,实现文件共享和持久化)
volumes:
# 宿主机目录:/docker/web/html1 映射到容器内Nginx的默认网页目录
# 这样修改宿主机的/html1目录内容,容器内会实时同步
- /docker/web/html1:/usr/share/nginx/html
# 第二个Nginx服务容器(web2),与web1配置类似,用于提供不同内容实现负载均衡效果
web2:
image: nginx:latest
container_name: web2
restart: always
networks:
- mynet1 # 同样加入mynet1网络,确保Haproxy能访问
expose:
- 80
volumes:
# 与web1使用不同的宿主机目录,以便存放不同的网页内容
- /docker/web/html2:/usr/share/nginx/html
# Haproxy负载均衡服务,用于分发请求到web1和web2
haproxy:
# 使用2.3版本的Haproxy镜像(需与配置文件兼容)
image: haproxy:2.3
container_name: haproxy
restart: always
# 加入两个网络:
# - mynet1:用于与web1、web2通信,获取后端服务
# - mynet2:可用于连接其他服务(当前配置中未使用,预留扩展)
networks:
- mynet1
- mynet2
# 挂载Haproxy配置文件:宿主机的haproxy.cfg映射到容器内的默认配置路径
# 注意:不同版本Haproxy的默认配置路径可能不同,2.3版本路径为/usr/local/etc/haproxy/
volumes:
- /docker/conf/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
# 端口映射:将宿主机的80端口映射到容器内的80端口
# 外部访问宿主机80端口时,请求会转发到Haproxy容器的80端口
ports:
- 80:80
# 定义网络配置
networks:
# 第一个网络:供web1、web2和haproxy内部通信
mynet1:
# 使用bridge驱动(Docker默认的网络驱动,创建独立的网络命名空间)
driver: bridge
# 第二个网络:预留网络,可用于扩展其他服务(如数据库、缓存等)
mynet2:
driver: bridge
2.3.1 启动配置文件
[root@docker-a lee]# docker compose up -d
2.4 编写haproxy.cfg文件
[root@docker-a lee]# vim /docker/conf/haproxy/haproxy.cfg
[root@docker-a lee]# cat /docker/conf/haproxy/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
listen webcluster # 定义一个名为webcluster的监听集群
bind *:80 # 监听所有网络接口的80端口(接收外部HTTP请求)
mode http # 工作模式为HTTP(专门处理HTTP协议)
balance roundrobin # 负载均衡算法:轮询(依次分发请求到后端服务器)
# 定义后端服务器1:web1容器的80端口
server server1 web1:80 check inter 2 rise 3
# 定义后端服务器2:web2容器的80端口
server server2 web2:80 check inter 2 rise 3
[root@docker-a lee]#
2.4.1 写入测试内容
[root@docker-a lee]# echo web1 > /docker/web/html1/index.html
[root@docker-a lee]# echo web2 > /docker/web/html2/index.html
[root@docker-a lee]# cat /docker/web/html1/index.html
web1
[root@docker-a lee]# cat /docker/web/html2/index.html
web2
[root@docker-a lee]#
2.4.2 重启所有容器
[root@docker-a lee]# docker compose down
[root@docker-a lee]# docker compose up -d
[root@docker-a lee]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e201c44d759b haproxy:2.3 "docker-entrypoint.s…" 10 seconds ago Up 9 seconds 0.0.0.0:80->80/tcp, [::]:80->80/tcp haproxy
c16240d3589d nginx:latest "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 80/tcp web2
7c474eee1643 nginx:latest "/docker-entrypoint.…" 10 seconds ago Up 9 seconds 80/tcp web1
3 测试效果
[root@docker-a lee]# curl 192.168.36.101
web1
[root@docker-a lee]# curl 192.168.36.101
web2
[root@docker-a lee]# curl 192.168.36.101
web1
[root@docker-a lee]# curl 192.168.36.101
web2
通过此配置,可以实现简单的负载均衡和高可用架构,适合作为 Web 服务的基础部署方案。