Docker 容器化部署 Spring Boot 应用的完整实践

前言

在当今云原生时代,容器化技术已经成为应用部署的标准方式之一。Docker 作为最流行的容器化平台,为开发者提供了轻量级、可移植的运行环境。本文将详细介绍如何使用 Docker 容器化部署 Spring Boot 应用,涵盖从项目准备到生产环境部署的完整流程。

一、准备工作

1.1 环境要求

在开始之前,请确保你的开发环境满足以下要求:

  • JDK 8 或更高版本(推荐 JDK 17)
  • Maven 3.6+ 或 Gradle 7.x 构建工具
  • Docker 环境(Docker Desktop 或 Docker Engine 20.10+)
  • 一个简单的 Spring Boot 2.7+ 应用(如果没有,可以使用 Spring Initializr 创建示例应用)

1.2 Spring Boot 应用准备

确保你的 Spring Boot 应用能够正常构建和运行。一个典型的 Spring Boot 项目结构如下:

spring-boot-docker-demo/
├── src/
│   ├── main/
│   │   ├── java/        # 应用源代码
│   │   └── resources/   # 配置文件
│   └── test/           # 测试代码
├── pom.xml             # Maven 配置文件
├── Dockerfile          # Docker 构建文件
└── .dockerignore       # Docker 忽略文件

二、创建 Dockerfile

Dockerfile 是构建 Docker 镜像的蓝图。在项目根目录下创建一个名为 Dockerfile 的文件(无扩展名),内容如下:

# 第一阶段:构建应用
FROM openjdk:17-jdk-slim as builder

# 设置工作目录
WORKDIR /app

# 复制构建文件和源代码
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src

# 构建应用(跳过测试以加快构建速度)
RUN ./mvnw clean package -DskipTests

# 第二阶段:运行应用
FROM openjdk:17-jre-slim

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 创建非root用户运行应用
RUN groupadd -r spring && useradd -r -g spring spring
USER spring

# 设置工作目录
WORKDIR /app

# 从构建阶段复制生成的 jar 文件
COPY --from=builder /app/target/*.jar app.jar

# 暴露应用端口
EXPOSE 8080

# 设置JVM参数(可根据需要调整)
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"

# 设置启动命令
ENTRYPOINT exec java ${JAVA_OPTS} -jar app.jar

这个 Dockerfile 使用了多阶段构建,可以显著减小最终镜像的大小,并遵循了安全最佳实践。

三、构建 Docker 镜像

在包含 Dockerfile 的目录下,运行以下命令构建镜像:

docker build -t spring-boot-app:1.0.0 .

参数说明:

  • -t:指定镜像名称和标签(格式:name:tag)
  • 1.0.0:建议使用语义化版本号
  • .:表示当前目录是构建上下文

四、运行 Docker 容器

构建完成后,可以使用以下命令运行容器:

docker run -d --name my-spring-app \
  -p 8080:8080 \
  -e "SPRING_PROFILES_ACTIVE=prod" \
  --memory=512m \
  --cpus=1 \
  spring-boot-app:1.0.0

参数说明:

  • -d:后台运行容器
  • --name:指定容器名称
  • -p 8080:8080:端口映射(主机端口:容器端口)
  • -e:设置环境变量
  • --memory:限制内存使用
  • --cpus:限制CPU使用

五、优化 Docker 镜像

5.1 使用 .dockerignore 文件

在项目根目录创建 .dockerignore 文件,排除不必要的文件:

.git
.gitignore
target
*.iml
.idea
*.md
*.log
.DS_Store
/docker
/bin

5.2 使用 Alpine 基础镜像

为了进一步减小镜像大小,可以使用 Alpine Linux 基础镜像:

FROM openjdk:17-jdk-alpine as builder
...
FROM openjdk:17-jre-alpine
...

5.3 分层构建优化

优化 Dockerfile 以提高构建缓存利用率:

# 只复制POM文件先下载依赖(利用Docker缓存层)
COPY pom.xml .
RUN ./mvnw dependency:go-offline

# 然后复制源代码
COPY src src

六、使用 Docker Compose 管理服务

对于需要多个服务的应用(如需要数据库),可以使用 Docker Compose。创建 docker-compose.yml 文件:

version: '3.8'

services:
  app:
    image: spring-boot-app:1.0.0
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
      - SPRING_DATASOURCE_USERNAME=postgres
      - SPRING_DATASOURCE_PASSWORD=example
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3

  db:
    image: postgres:13-alpine
    environment:
      POSTGRES_PASSWORD: example
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

启动服务:

docker-compose up -d --build

七、生产环境部署建议

7.1 安全最佳实践

  1. 使用非root用户运行容器
  2. 定期更新基础镜像以获取安全补丁
  3. 扫描镜像中的漏洞:
    docker scan spring-boot-app:1.0.0
    

7.2 日志管理

配置日志驱动和日志轮转:

docker run -d \
  --log-driver=json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  spring-boot-app:1.0.0

7.3 监控和指标

集成Spring Boot Actuator和Prometheus监控:

# 暴露监控端点
EXPOSE 8080 9090
# docker-compose.yml 中添加
monitoring:
  image: prom/prometheus
  ports:
    - "9090:9090"
  volumes:
    - ./prometheus.yml:/etc/prometheus/prometheus.yml

八、持续集成/持续部署 (CI/CD)

可以将 Docker 构建集成到 CI/CD 流程中。以下是一个完整的 GitHub Actions 示例:

name: Build, Test and Deploy

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  IMAGE_NAME: spring-boot-app
  LATEST_TAG: latest
  VERSION_TAG: ${{ github.sha }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
          
      - name: Build with Maven
        run: mvn -B verify --file pom.xml
        
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_HUB_USERNAME }}
          password: ${{ secrets.DOCKER_HUB_TOKEN }}
          
      - name: Build and push
        uses: docker/build-push-action@v3
        with:
          context: .
          push: ${{ github.event_name == 'push' }}
          tags: |
            ${{ secrets.DOCKER_HUB_USERNAME }}/$IMAGE_NAME:$VERSION_TAG
            ${{ secrets.DOCKER_HUB_USERNAME }}/$IMAGE_NAME:$LATEST_TAG
          cache-from: type=gha
          cache-to: type=gha,mode=max
          
      - name: Deploy to Production
        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        run: |
          ssh ${{ secrets.SSH_HOST }} "docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/$IMAGE_NAME:$VERSION_TAG"
          ssh ${{ secrets.SSH_HOST }} "docker-compose -f /path/to/docker-compose.yml up -d"

结语

通过本文的介绍,你应该已经掌握了使用 Docker 容器化部署 Spring Boot 应用的完整流程。从基础的 Dockerfile 编写到生产环境的最佳实践,容器化技术为 Spring Boot 应用提供了更加灵活、高效的部署方式。在实际项目中,可以根据具体需求进一步优化和调整这些配置,并结合 Kubernetes 等编排工具实现更强大的部署方案。
- -

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐