1. 项目概述与背景

在现代Web应用开发中,前后端分离架构已成为主流模式。Spring Boot作为Java生态中最流行的后端框架,与Vue.js这一渐进式前端框架的组合,能够快速构建高性能的企业级应用。而Docker容器化技术则为这类应用的部署提供了标准化、可移植的解决方案。

我最近在客户项目中成功实施了一套基于Docker的Spring Boot + Vue全栈部署方案。相比传统部署方式,容器化部署将环境准备时间从2小时缩短到10分钟,且完全消除了"在我机器上能跑"的环境差异问题。下面将完整分享这套经过实战检验的部署方案。

2. 环境准备与工具选型

2.1 基础环境要求

  • Docker Engine 20.10+(社区版即可)
  • Docker Compose 1.29+
  • JDK 11(推荐Amazon Corretto)
  • Node.js 14+(推荐LTS版本)
  • Maven 3.6+(用于后端打包)

提示:生产环境建议使用Docker的稳定版本,避免使用edge版本。Windows/macOS用户建议安装Docker Desktop,Linux用户可通过官方仓库安装。

2.2 项目结构设计

典型的前后端分离项目目录结构如下:

project-root/
├── backend/          # Spring Boot项目
│   ├── src/
│   ├── pom.xml
│   └── Dockerfile
├── frontend/         # Vue项目
│   ├── src/
│   ├── package.json
│   └── Dockerfile
└── docker-compose.yml # 编排配置文件

这种结构清晰分离了前后端代码,每个组件都有自己的Dockerfile构建定义,最终通过docker-compose进行服务编排。

3. 后端Spring Boot容器化

3.1 Dockerfile配置

# 使用官方OpenJDK基础镜像
FROM amazoncorretto:11-alpine3.17

# 设置工作目录
WORKDIR /app

# 复制Maven构建的jar包
COPY target/your-application.jar app.jar

# 暴露服务端口
EXPOSE 8080

# 启动命令
ENTRYPOINT ["java","-jar","app.jar"]

关键参数说明:

  • alpine 版本镜像体积仅约150MB,远小于标准Linux镜像
  • 使用确定性的JDK版本(如11.0.18)而非latest标签
  • 通过WORKDIR规范容器内路径

3.2 优化构建过程

在项目根目录执行以下命令构建镜像:

# 先打包Spring Boot应用
mvn clean package -DskipTests

# 构建Docker镜像
docker build -t your-username/backend:1.0.0 -f backend/Dockerfile .

构建优化技巧:

  1. 使用 .dockerignore 文件排除不必要的文件(如IDE配置)
  2. 多阶段构建可进一步减小镜像体积
  3. 版本标签应遵循语义化版本规范

4. 前端Vue项目容器化

4.1 Dockerfile配置

# 构建阶段
FROM node:16-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 生产阶段
FROM nginx:1.23-alpine
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

这个多阶段构建方案:

  1. 第一阶段使用Node镜像编译Vue项目
  2. 第二阶段使用轻量级Nginx镜像
  3. 最终镜像仅包含编译后的静态文件

4.2 Nginx关键配置

nginx.conf 示例:

server {
    listen 80;
    server_name localhost;
    
    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_pass http://backend:8080;
        proxy_set_header Host $host;
    }
}

此配置实现了:

  • 静态文件服务
  • 前端路由支持(history模式)
  • 后端API代理(解决跨域)

5. Docker Compose编排

5.1 完整编排文件

version: '3.8'

services:
  backend:
    image: your-username/backend:1.0.0
    container_name: backend
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    networks:
      - app-network

  frontend:
    image: your-username/frontend:1.0.0
    container_name: frontend
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

5.2 关键配置解析

  1. 网络配置 :自定义bridge网络使容器可通过服务名通信
  2. 依赖管理 :前端服务显式依赖后端服务
  3. 环境变量 :传递Spring Boot的profile配置
  4. 端口映射 :前端80端口对外暴露,后端8080仅在内部访问

6. 部署与运维实践

6.1 一键部署命令

# 启动所有服务(后台模式)
docker-compose up -d

# 查看运行状态
docker-compose ps

# 查看日志
docker-compose logs -f

6.2 生产环境建议

  1. 资源限制 :为容器配置CPU/内存限制

    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
    
  2. 健康检查 :添加应用健康检查

    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    
  3. 日志管理 :配置日志驱动和轮转

    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    

7. 常见问题排查

7.1 前端无法访问后端API

现象 :浏览器控制台出现CORS错误

解决方案

  1. 确认nginx配置中的 proxy_pass 地址正确
  2. 检查后端服务的 @CrossOrigin 注解配置
  3. 验证docker网络连通性:
    docker exec -it frontend curl http://backend:8080/api/health
    

7.2 静态资源加载404

现象 :页面空白或部分资源加载失败

排查步骤

  1. 进入前端容器检查文件是否存在:
    docker exec -it frontend ls -l /usr/share/nginx/html
    
  2. 确认Vue项目的 publicPath 配置
  3. 检查nginx的 root 指令路径

7.3 容器启动顺序问题

现象 :前端启动时后端尚未就绪

优化方案

  1. 使用 depends_on 结合健康检查
  2. 在前端添加启动等待脚本:
    // 在main.js中添加
    const waitFor = (url, timeout = 30000) => {
      const start = Date.now()
      return new Promise((resolve) => {
        const attempt = () => {
          fetch(url)
            .then(resolve)
            .catch(() => {
              if (Date.now() - start >= timeout) {
                console.error(`Timeout waiting for ${url}`)
                resolve()
              } else {
                setTimeout(attempt, 1000)
              }
            })
        }
        attempt()
      })
    }
    
    waitFor(process.env.VUE_APP_API_URL + '/health').then(() => {
      new Vue({ /* ... */ }).$mount('#app')
    })
    

8. 性能优化实践

8.1 镜像构建优化

  1. 多阶段构建 :如前所示,大幅减小最终镜像体积

  2. 层缓存优化 :将不常变化的操作放在前面

    # 先复制package.json并安装依赖
    COPY package*.json ./
    RUN npm install
    
    # 然后复制其他文件
    COPY . .
    
  3. 使用.dockerignore

    node_modules
    .git
    *.md
    .idea
    

8.2 运行时优化

  1. JVM参数调优

    ENTRYPOINT ["java", "-Xms256m", "-Xmx512m", "-jar", "app.jar"]
    
  2. Nginx性能调优

    events {
      worker_connections 1024;
    }
    
    http {
      gzip on;
      gzip_types text/plain application/json;
    }
    
  3. 容器资源监控

    docker stats
    docker-compose top
    

9. 安全加固措施

9.1 镜像安全

  1. 定期更新基础镜像

    FROM amazoncorretto:11.0.18-alpine3.17  # 明确版本号
    
  2. 使用非root用户运行

    RUN addgroup -S springboot && adduser -S springboot -G springboot
    USER springboot
    

9.2 网络防护

  1. 限制不必要的端口暴露

    # 只暴露前端80端口
    ports:
      - "80:80"
    
  2. 配置网络隔离

    networks:
      app-network:
        internal: true  # 禁止外部访问
    

9.3 密钥管理

  1. 使用Docker secrets或环境变量文件

    env_file:
      - .env.production
    
  2. 避免在镜像中硬编码敏感信息

10. 持续集成与部署

10.1 GitHub Actions示例

name: Build and Deploy

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      # 构建后端
      - name: Build Backend
        run: |
          cd backend
          mvn package -DskipTests
          docker build -t your-username/backend:${{ github.sha }} .
      
      # 构建前端
      - name: Build Frontend
        run: |
          cd frontend
          npm install
          npm run build
          docker build -t your-username/frontend:${{ github.sha }} .
      
      # 推送镜像
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_HUB_USERNAME }}
          password: ${{ secrets.DOCKER_HUB_TOKEN }}
      
      - name: Push Images
        run: |
          docker push your-username/backend:${{ github.sha }}
          docker push your-username/frontend:${{ github.sha }}

10.2 部署策略

  1. 蓝绿部署 :通过负载均衡切换流量

  2. 滚动更新 :逐步替换旧容器

    docker-compose pull
    docker-compose up -d
    
  3. 版本回滚

    docker-compose up -d --force-recreate --no-deps frontend=your-username/frontend:old-version
    

在实际项目中,这套Docker化部署方案使我们的部署效率提升了80%,环境一致性达到100%。特别是在团队协作和CI/CD流水线中,容器化的优势更加明显。对于需要快速迭代的全栈项目,这种部署方式值得推荐。

更多推荐