用 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 进行更高级的编排。

相关推荐
深念Y2 小时前
Docker Desktop 版本与 IDEA 插件兼容性
docker·云原生·容器·api·idea·wsl
slyybw2 小时前
MySQL SQL语句
sql·mysql·oracle
jgbazsh2 小时前
【MySQL】mysqldump使用方法
数据库·mysql·oracle
吾诺2 小时前
如何在Linux中找到MySQL的安装目录
linux·运维·mysql
lijwsunyt2 小时前
Ubuntu虚拟机部署OpenClaw全踩坑实录|本地访问+模型配置一站式解决
linux·运维·ubuntu
夜猫子ing2 小时前
《UNIX高级环境编程》 第十四章 高级I/O(一文读懂UNIX下高级I/O)
运维·服务器·网络
悲伤小伞2 小时前
10-MySQL_事务管理
linux·数据库·c++·mysql·centos
钰衡大师2 小时前
MySQL服务器表导入本地开发环境
服务器·mysql
小马爱打代码2 小时前
Spring Boot内嵌容器深度解析:Tomcat是如何被启动的?
spring boot·后端·tomcat