1. 项目概述与核心价值
在当今的Web应用开发中,前后端分离架构已成为主流趋势。Spring Boot作为Java生态中最流行的后端框架,与Vue.js这一渐进式前端框架的组合,能够快速构建现代化Web应用。而Docker容器化部署则为这种架构提供了完美的运行环境解决方案。
这种技术组合的实际价值在于:
- 开发效率:前后端分离让团队可以并行开发
- 部署便捷:Docker实现了一次构建,随处运行
- 环境一致:彻底解决"在我机器上能跑"的问题
- 资源隔离:每个服务运行在独立容器中,互不干扰
我最近在客户项目中实际采用了这套技术栈,从开发到部署的全流程比传统方式节省了约40%的时间成本。下面将详细分享具体实现方案和踩坑经验。
2. 环境准备与工具选型
2.1 基础环境配置
在开始之前,需要确保本地开发环境已安装以下工具:
-
Docker Desktop:版本20.10+(社区版即可)
- Windows/Mac用户建议直接下载安装包
- Linux用户通过包管理器安装
- 安装后需要启用Kubernetes(可选但推荐)
-
JDK:推荐OpenJDK 11
- 验证命令:
java -version - 注意与Spring Boot版本的兼容性
- 验证命令:
-
Node.js:LTS版本(当前16.x)
- Vue CLI需要Node环境
- 验证命令:
node -v和npm -v
-
IDE:
- 后端:IntelliJ IDEA(终极版)
- 前端:VS Code + Volar插件
重要提示:所有工具的版本号需要严格匹配,这是后续很多奇怪问题的根源。建议使用版本管理工具(如asdf或nvm)来管理多版本环境。
2.2 项目初始化
对于新项目,推荐以下初始化方式:
bash复制# 后端项目
spring init --dependencies=web,lombok,data-jpa myapp-backend
# 前端项目
npm init vue@latest myapp-frontend
对于已有项目,需要特别注意:
- 检查后端pom.xml中的Spring Boot版本
- 确认前端package.json中的Vue版本
- 确保两者都支持长期维护(LTS)版本
3. 后端Spring Boot容器化
3.1 Dockerfile编写
标准的Spring Boot Dockerfile应包含以下层次:
dockerfile复制# 基础镜像选择
FROM eclipse-temurin:11-jdk-jammy as builder
# 工作目录设置
WORKDIR /app
# 依赖项单独分层
COPY pom.xml .
COPY src ./src
# 构建应用
RUN ./mvnw clean package -DskipTests
# 运行时镜像
FROM eclipse-temurin:11-jre-jammy
WORKDIR /app
# 从构建阶段复制jar包
COPY --from=builder /app/target/*.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
关键优化点:
- 使用多阶段构建减小镜像体积(从~500MB降到~200MB)
- 分离依赖项层提高构建缓存利用率
- 使用官方基础镜像而非alpine(避免glibc兼容问题)
3.2 容器网络配置
在docker-compose.yml中配置后端服务:
yaml复制services:
backend:
build: ./myapp-backend
container_name: app-backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DB_URL=jdbc:mysql://db:3306/appdb
depends_on:
- db
networks:
- app-network
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: appdb
MYSQL_USER: appuser
MYSQL_PASSWORD: userpass
volumes:
- mysql_data:/var/lib/mysql
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
mysql_data:
注意事项:
- 使用自定义网络实现服务发现
- 数据库密码应通过环境变量文件管理
- depends_on只控制启动顺序,不保证服务可用性
4. 前端Vue项目容器化
4.1 生产环境构建
前端项目需要先进行生产构建:
bash复制npm run build
这会生成dist目录,包含优化后的静态资源。我们需要通过Nginx来服务这些文件。
4.2 Nginx容器配置
Dockerfile示例:
dockerfile复制FROM nginx:alpine
# 删除默认配置
RUN rm /etc/nginx/conf.d/default.conf
# 复制自定义配置
COPY nginx.conf /etc/nginx/conf.d
# 复制构建产物
COPY dist /usr/share/nginx/html
# 暴露端口
EXPOSE 80
# 启动Nginx
CMD ["nginx", "-g", "daemon off;"]
对应的nginx.conf:
nginx复制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;
proxy_set_header X-Real-IP $remote_addr;
}
}
关键点:
- 使用alpine版本减小镜像体积
- 配置/api代理解决跨域问题
- try_files配置支持Vue路由
4.3 前端服务编排
在docker-compose.yml中添加:
yaml复制frontend:
build: ./myapp-frontend
container_name: app-frontend
ports:
- "80:80"
depends_on:
- backend
networks:
- app-network
5. 完整部署与优化
5.1 一键启动命令
完整的部署流程:
bash复制# 构建镜像
docker-compose build
# 启动服务
docker-compose up -d
# 查看日志
docker-compose logs -f
5.2 性能优化实践
-
镜像构建优化:
- 使用.dockerignore文件排除无关文件
- 后端利用Maven依赖缓存层
- 前端使用多阶段构建分离构建环境和运行环境
-
资源限制:
yaml复制services: backend: deploy: resources: limits: cpus: '2' memory: 1G -
健康检查:
yaml复制healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] interval: 30s timeout: 10s retries: 3
5.3 CI/CD集成
可以在GitHub Actions中添加自动化流程:
yaml复制name: Build and Deploy
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build images
run: docker-compose -f docker-compose.prod.yml build
- name: Push to Registry
run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
docker-compose -f docker-compose.prod.yml push
6. 常见问题排查
6.1 后端服务无法连接数据库
症状:应用启动时报数据库连接错误
解决方案:
- 检查数据库容器是否正常运行
- 验证环境变量中的连接字符串
- 确保网络配置正确
- 添加wait-for-it.sh脚本处理依赖启动
6.2 前端路由刷新404
症状:直接访问路由路径返回404
解决方案:
- 确认Nginx配置中包含try_files规则
- 检查Vue路由模式(应使用history模式)
- 确保base路径配置正确
6.3 跨域问题
症状:前端请求API时出现CORS错误
解决方案:
- 开发环境配置代理(vue.config.js)
- 生产环境通过Nginx反向代理
- 避免在Spring Boot中同时配置CORS和代理
6.4 容器时区问题
症状:日志时间与实际不符
解决方案:
dockerfile复制# 在Dockerfile中添加
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
7. 进阶部署方案
7.1 使用Docker Swarm
对于生产环境,可以考虑使用Swarm模式:
bash复制# 初始化Swarm
docker swarm init
# 部署服务
docker stack deploy -c docker-compose.prod.yml myapp
7.2 Kubernetes部署
更复杂的场景可以使用Kubernetes:
yaml复制# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: myapp-backend:latest
ports:
- containerPort: 8080
7.3 监控与日志
推荐工具组合:
- Prometheus + Grafana监控
- ELK日志收集
- cAdvisor容器监控
配置示例:
yaml复制services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
8. 安全最佳实践
-
镜像安全:
- 定期扫描漏洞(使用docker scan)
- 使用最小化基础镜像
- 避免在镜像中存储敏感信息
-
网络隔离:
- 为不同服务分配独立网络
- 限制不必要的端口暴露
- 使用内部DNS解析服务
-
秘密管理:
yaml复制services: backend: secrets: - db_password secrets: db_password: file: ./secrets/db_password.txt -
更新策略:
- 定期更新基础镜像
- 使用固定版本标签而非latest
- 建立镜像更新流水线
9. 成本优化方案
-
镜像大小优化:
- 使用distroless镜像
- 删除不必要的依赖
- 压缩静态资源
-
资源利用率提升:
- 合理设置CPU/内存限制
- 使用自动扩缩容
- 优化JVM参数
-
存储优化:
- 使用volume生命周期管理
- 定期清理无用镜像
- 共享公共基础层
10. 本地开发调优
10.1 开发模式配置
使用docker-compose.override.yml:
yaml复制services:
backend:
volumes:
- ./myapp-backend:/app
environment:
- SPRING_PROFILES_ACTIVE=dev
command: ./mvnw spring-boot:run
frontend:
volumes:
- ./myapp-frontend:/app
command: npm run serve
10.2 热重载配置
Spring Boot DevTools配置:
properties复制spring.devtools.remote.secret=mysecret
Vue热重载:
javascript复制module.exports = {
devServer: {
watchOptions: {
poll: true
}
}
}
10.3 调试技巧
-
后端远程调试:
yaml复制environment: - JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 ports: - "5005:5005" -
前端source map配置:
javascript复制configureWebpack: { devtool: 'source-map' } -
容器内调试:
bash复制docker exec -it app-backend bash