1. 项目背景与核心挑战
前后端分离架构已成为现代Web开发的主流模式,但随之而来的部署复杂度却让很多团队头疼。我最近刚完成一个电商平台的重构,将原本单体架构拆分为前端Vue.js+后端Spring Boot的分离架构,部署时遇到了典型问题:
- 前端静态资源需要Nginx托管
- 后端需要Tomcat容器
- MySQL和Redis需要独立服务
- 各组件间的网络通信需要配置
- 开发/测试/生产环境的一致性保障
传统部署方式需要分别在服务器上安装配置这些服务,费时费力且容易出错。而Docker容器化方案能完美解决这些问题——这正是本文要分享的多容器编排实战经验。
2. 整体架构设计
2.1 容器规划
对于典型的前后端分离项目,我建议采用以下容器分工方案:
| 容器类型 | 技术选型 | 职责说明 |
|---|---|---|
| 前端容器 | Nginx | 托管编译后的静态资源 |
| 后端容器 | Tomcat/JDK | 运行业务Java代码 |
| 数据库容器 | MySQL 8.0 | 持久化数据存储 |
| 缓存容器 | Redis 6 | 会话管理/热点数据缓存 |
| 代理容器 | Nginx | 反向代理和负载均衡(可选) |
2.2 网络设计
容器间通信采用自定义bridge网络,相比默认的bridge网络具有以下优势:
- 自动DNS解析服务名称(容器间可直接通过服务名访问)
- 更好的隔离性
- 可自定义子网和网关
# 创建专属网络 docker network create app-network3. 容器化实施细节
3.1 前端容器构建
前端以Vue项目为例,关键点在于:
- 构建阶段使用Node镜像编译
- 运行阶段使用Nginx镜像托管dist产物
# 阶段一:构建 FROM node:16 as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 阶段二:运行 FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80关键技巧:nginx.conf需要配置API请求转发,否则会出现跨域问题:
location /api { proxy_pass http://backend:8080; }3.2 后端容器优化
Spring Boot项目的Dockerfile常见误区是直接打包整个工程,导致镜像臃肿。推荐分层构建:
# 构建阶段 FROM maven:3.8-jdk-11 as builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 运行阶段 FROM openjdk:11-jre-slim COPY --from=builder /app/target/*.jar /app.jar ENTRYPOINT ["java","-jar","/app.jar"]避坑指南:
- 使用go-offline提前下载依赖,避免每次构建重复下载
- JRE基础镜像比JDK节省约200MB空间
- 生产环境建议添加JVM内存参数:
-XX:MaxRAMPercentage=75.0
3.3 数据库容器配置
MySQL容器需要重点关注数据持久化和初始配置:
services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: app_db MYSQL_USER: app_user MYSQL_PASSWORD: userpass volumes: - mysql_data:/var/lib/mysql networks: - app-network volumes: mysql_data:重要安全提示:
- 永远不要使用弱密码
- 生产环境应限制root账户远程访问
- 建议定期备份volume数据
4. Docker Compose编排
完整的docker-compose.yml示例:
version: '3.8' services: frontend: build: ./frontend ports: - "80:80" networks: - app-network depends_on: - backend backend: build: ./backend environment: - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/app_db - SPRING_REDIS_HOST=redis networks: - app-network depends_on: - mysql - redis mysql: image: mysql:8.0 # ...同上文MySQL配置... redis: image: redis:6 networks: - app-network networks: app-network: driver: bridge启动命令:
docker-compose up -d --build5. 生产环境优化建议
5.1 镜像瘦身技巧
- 多阶段构建(如上文示例)
- 使用Alpine基础镜像
- 合并RUN指令减少镜像层
- 定期执行
docker system prune
5.2 日志管理方案
services: backend: logging: driver: "json-file" options: max-size: "10m" max-file: "3"5.3 健康检查配置
healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] interval: 30s timeout: 5s retries: 36. 常见问题排查
6.1 容器启动顺序问题
症状:后端启动时连接MySQL失败
解决方案:
- 使用depends_on声明依赖
- 在后端应用中添加连接重试逻辑
spring.datasource.hikari.connection-timeout=300006.2 前端跨域问题
即使配置了Nginx转发,仍可能出现跨域错误。检查:
- 后端是否需要配置CORS
@Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); } }; }6.3 内存泄漏诊断
- 查看容器内存使用:
docker stats- 进入容器分析:
docker exec -it backend bash jcmd 1 VM.native_memory summary7. 进阶扩展方向
7.1 Kubernetes迁移
当单机Docker无法满足需求时,可平滑迁移到K8s:
- 将docker-compose.yml转换为k8s yaml
- 使用Ingress替代Nginx代理
- 配置HPA自动扩缩容
7.2 CI/CD集成
在GitHub Actions中自动化构建:
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: docker-compose up -d --build7.3 监控方案
推荐组合:
- Prometheus + Grafana监控指标
- ELK收集日志
- AlertManager告警
经过这套容器化改造后,我们的电商平台部署时间从2小时缩短到5分钟,环境一致性得到保障,新成员上手速度提升60%。这种架构特别适合需要快速迭代的中大型项目。