用 Docker Compose 一键部署高可用集群(MySQL + Tomcat + Nginx)

在五台虚拟机中,将手工搭建的 Keepalived+Nginx+Tomcat+MySQL 高可用架构,用 Docker Compose 实现标准化部署。

前言

之前我花了近一个月的时间,手工搭建了一套基于 Keepalived、Nginx、Tomcat、MySQL 的高可用集群,并成功将各组件容器化。但每次启动仍需要手动执行 docker run 命令,环境迁移时也容易遗漏参数。最近我将这套架构统一用 Docker Compose 管理,实现了"一键启动",这里记录下配置过程,希望对你有帮助。


一、项目架构回顾

整套集群运行在五台 Redhat 虚拟机上,各主机角色及 IP 如下:

主机 IP 地址 服务组件 MySQL 192.168.211.136 MySQL 5.7 Tomcat1 192.168.211.128 Tomcat 11 + JSP 应用 Tomcat2 192.168.211.133 Tomcat 11 + JSP 应用 Master Nginx 192.168.211.134 Nginx + Keepalived (主) Backup Nginx 192.168.211.135 Nginx + Keepalived (备)

· VIP:192.168.211.100,由 Keepalived 管理,用于对外统一入口。 · Nginx:作为反向代理,将请求轮询转发给两台 Tomcat。 · Tomcat:提供 JSP 页面,通过 JDBC 连接 MySQL 展示数据。 · MySQL:存储服务器状态数据。

容器化后,Keepalived 继续运行在宿主机,其他所有服务都跑在 Docker 容器中,且用 Docker Compose 统一管理。


二、Docker Compose 文件编写

1、MySQL 主机(192.168.211.136)

创建目录 /opt/mysql,放入 docker-compose.yml:

复制代码
services:
  mysql:
    image: mysql:5.7
    container_name: mysql
    restart: always
    network_mode: host
    environment:
      MYSQL_ROOT_PASSWORD: AppPass123!
    volumes:
      - /var/lib/mysql:/var/lib/mysql
      - /etc/localtime:/etc/localtime:ro

说明:

· network_mode: host:让容器直接使用宿主机网络,这样其他主机可以通过 192.168.211.136:3306 访问 MySQL。 · 数据卷挂载:将宿主机原有的数据库目录(/var/lib/mysql)挂载进去,保证数据持久化。 · 时区挂载:确保容器时间与宿主机一致。

启动命令:

复制代码
cd /opt/mysql
docker-compose up -d

2、Tomcat 主机

分别在 Tomcat1 和 Tomcat2 上创建 /opt/tomcat1 和 /opt/tomcat2 目录,各放一个 docker-compose.yml。

Tomcat1 的 docker-compose.yml:

复制代码
services:
  tomcat1:
    image: my-tomcat:1.7   # 你的 Tomcat 镜像
    container_name: tomcat1
    restart: always
    ports:
      - "8081:8080"
    volumes:
      - /etc/localtime:/etc/localtime:ro

Tomcat2 的 docker-compose.yml 只需将容器名改为 tomcat2,其他相同:

复制代码
services:
  tomcat2:
    image: my-tomcat:1.7
    container_name: tomcat2
    restart: always
    ports:
      - "8081:8080"
    volumes:
      - /etc/localtime:/etc/localtime:ro

说明:

· 映射 8081:8080:避免与宿主机其他服务冲突,同时方便 Nginx 配置。 · 镜像 my-tomcat:1.7 是我提前构建好的,包含 JSP 应用和 JDBC 驱动。

启动:

复制代码
cd /opt/tomcat1
docker-compose up -d
# 在 Tomcat2 上同样操作

3、Nginx 主机(Master 和 Backup)

Nginx 需要反向代理到两台 Tomcat,因此我们构建了专用镜像 my-nginx:1.1,其中已包含自定义配置文件 tomcat.conf(内容如下):

复制代码
upstream web {
    server 192.168.211.128:8081;
    server 192.168.211.133:8081;
}
server {
    listen 80;
    server_name 192.168.211.100;
    location / {
        proxy_pass http://web;
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

在 Master 和 Backup 主机上,分别创建 /opt/nginx-master 和 /opt/nginx-backup 目录,放入相同的 docker-compose.yml:

复制代码
services:
  nginx:
    image: my-nginx:1.1
    container_name: nginx
    restart: always
    network_mode: host
    volumes:
      - /etc/localtime:/etc/localtime:ro

说明:

· network_mode: host:让 Nginx 容器直接监听宿主机的 80 端口,便于与 Keepalived 配合。 · 启动前务必停止宿主机上的 nginx 服务,避免端口冲突:

复制代码
systemctl stop nginx
systemctl disable nginx
systemctl mask nginx
pkill -9 nginx

启动:

复制代码
cd /opt/nginx-master
docker-compose up -d
# Backup 主机同样操作

三、验证与测试

1、检查容器状态

在各主机上执行 docker-compose ps,所有容器应显示 Up 状态。

2、测试 MySQL 连接

在任意 Tomcat 主机上:

复制代码
curl http://192.168.211.128:8081/testdb.jsp

应显示数据库中的表格数据。

3、测试反向代理

直接访问 Master IP:

复制代码
curl http://192.168.211.134

应返回 Tomcat 页面。多次刷新,观察轮询到两台 Tomcat。

4、测试 VIP 高可用

访问 VIP:

复制代码
curl http://192.168.211.100

同样能正常返回。停止 Master 上的 Nginx 容器(docker stop nginx),等待几秒,VIP 应漂移到 Backup,再次访问 VIP 依然正常。


四、踩坑记录

· MySQL 数据目录权限:容器内 MySQL 用户 UID=999,宿主机数据目录需 chown 999:999 /var/lib/mysql,否则容器无法写入。 · Tomcat 驱动缺失:记得在 Dockerfile 中添加 MySQL 驱动 JAR,否则 testdb.jsp 会报 ClassNotFoundException。 · Nginx 配置不生效:检查容器内 /etc/nginx/conf.d/ 是否存在 tomcat.conf,若没有则重新构建镜像或挂载配置文件。 · 端口冲突:启动 Nginx 容器前,务必彻底停止宿主机 nginx 服务,并用 ss -tlnp 确认 80 端口未被占用。 · YAML 缩进:Docker Compose 对缩进敏感,务必使用空格,不要用 Tab。


五、总结

通过 Docker Compose,我们将原本分散在五台虚拟机上的手工部署,变成了每个主机上一个简单明了的 YAML 文件。现在,无论是重启服务器,还是在新环境中重建,只需执行 docker-compose up -d 即可一键启动所有容器(Keepalived 仍需手动启动,但可用 systemd 管理)。

这种标准化方式不仅减少了人为失误,还让整个架构变得可移植、可复现。接下来,我会继续引入 Prometheus 监控和 Grafana 可视化,并尝试用 Kubernetes 进行更高级的编排。

相关推荐
Agent产品评测局20 分钟前
企业邮件处理自动化落地,分类回复全流程实现方法 —— 2026企业级智能体选型与落地全景指南丨Agent产品测评局
运维·人工智能·ai·chatgpt·自动化
升职佳兴22 分钟前
重启 Docker 导致 VMware 虚拟机断网:一次完整的故障排查记录
运维·docker·容器
HYNuyoah24 分钟前
docker网站配置迁移(旧换新)
java·docker·容器
同聘云25 分钟前
阿里云国际站服务器高防是什么意思?如何选择高防服务器?
运维·服务器·网络
农村小镇哥33 分钟前
PHP递归遍历+MYSQL介绍+MYSQL基本操作
开发语言·mysql·php
A_QXBlms1 小时前
企业微信客户管理自动化:利用API同步客户标签与画像
运维·自动化·企业微信
如来神掌十八式1 小时前
nginx基础知识
运维·nginx
赵渝强老师1 小时前
【赵渝强老师】MySQL数据库的分库与分表
数据库·mysql
网络点点滴1 小时前
创建一个简单的web服务器
运维·服务器·前端
私人珍藏库1 小时前
【Android】Operit AI v1.10.0+11 豆包ai手机开源版 自动化手机
运维·自动化