当前位置: 首页 > news >正文

Docker 多服务镜像构建完整教程

本文将手把手教你如何使用 Docker 多阶段构建技术,将一个 Spring Boot 多模块项目构建成三个独立的服务镜像。适合 Java 全栈开发者学习。

📋 目录

  • 项目背景
  • 技术架构
  • 准备工作
  • Dockerfile 详解
  • .dockerignore 配置
  • 构建镜像
  • 运行容器
  • 生产部署
  • 常见问题

项目背景

我们有一个基于若依框架的 Spring Boot 多模块项目,包含三个服务:

  1. ayy-server:核心业务服务(端口 48087)
  2. ayy-snailjob-server:分布式任务调度服务(端口 9090)
  3. ayy-monitor-admin:监控管理服务(端口 8800, 17888)

项目结构如下:

project-root/
├── pom.xml                          # 父 POM
├── ruoyi-admin/                     # 主服务模块
│   ├── pom.xml
│   └── src/
├── ruoyi-extend/
│   ├── ruoyi-monitor-admin/         # 监控服务模块
│   │   ├── pom.xml
│   │   └── src/
│   └── ruoyi-snailjob-server/       # 任务调度服务模块
│       ├── pom.xml
│       └── src/
├── Dockerfile                        # 多阶段构建文件
└── .dockerignore                     # Docker 忽略文件

技术架构

核心技术栈

  • Java 17:运行环境
  • Maven 3.9.6:项目构建工具
  • Spring Boot:应用框架
  • Docker Multi-stage Build:多阶段构建
  • Alpine Linux:精简基础镜像

为什么使用多阶段构建?

传统方式需要:

  1. 本地编译 → 生成 JAR
  2. 编写 Dockerfile → 复制 JAR
  3. 构建镜像

多阶段构建的优势

一个 Dockerfile 完成所有事情
构建环境与运行环境分离(builder 阶段用完即弃)
最终镜像体积小(只包含 JRE + JAR)
利用 Docker 缓存加速构建
一次构建多个镜像


准备工作

1. 安装 Docker

# macOS
brew install docker# Ubuntu/Debian
sudo apt-get update
sudo apt-get install docker.io# 验证安装
docker --version

2. 启用 BuildKit(推荐)

BuildKit 是 Docker 的新一代构建引擎,支持并行构建和高级缓存。

# 临时启用
export DOCKER_BUILDKIT=1# 永久启用(添加到 ~/.bashrc 或 ~/.zshrc)
echo 'export DOCKER_BUILDKIT=1' >> ~/.bashrc
source ~/.bashrc

3. 项目准备

确保项目根目录有以下文件:

  • pom.xml(父 POM)
  • Dockerfile
  • .dockerignore

Dockerfile 详解

我们的 Dockerfile 分为 4 个阶段:1 个构建阶段 + 3 个运行阶段。

第一阶段:构建阶段(builder)

# -------------------------------
# 构建阶段:使用 Maven 构建产物
# -------------------------------
FROM maven:3.9.6-eclipse-temurin-17 AS builderWORKDIR /build# 先复制 pom 文件,利用 Docker 层缓存
COPY pom.xml .
COPY ruoyi-admin/pom.xml ./ruoyi-admin/
COPY ruoyi-extend/ruoyi-monitor-admin/pom.xml ./ruoyi-extend/ruoyi-monitor-admin/
COPY ruoyi-extend/ruoyi-snailjob-server/pom.xml ./ruoyi-extend/ruoyi-snailjob-server/# 下载依赖(利用缓存层)
RUN --mount=type=cache,target=/root/.m2 \mvn dependency:go-offline -B || true# 复制源码
COPY . .# 构建(跳过测试)
RUN --mount=type=cache,target=/root/.m2 \mvn -B clean package -DskipTests

关键点解析

  1. 分层复制 POM:先复制 POM 文件再复制源码

    • 依赖不变时,Docker 会使用缓存,避免重复下载
  2. Maven 缓存挂载--mount=type=cache,target=/root/.m2

    • Maven 本地仓库会被缓存,大幅加速后续构建
  3. 跳过测试-DskipTests

    • 构建镜像时跳过单元测试,节省时间

第二阶段:ayy-server 运行镜像

# -------------------------------
# 运行阶段:ayy-server
# -------------------------------
FROM eclipse-temurin:17-jre-alpine AS ayy-server# 创建非 root 用户
RUN addgroup -S adduser && adduser -S adduser -G adduserWORKDIR /app# 拷贝构建产物
COPY --from=builder --chown=adduser:adduser /build/ruoyi-admin/target/*.jar ./app.jar# 创建日志和配置目录
RUN mkdir -p /app/logs /app/config && \chown -R adduser:adduser /app# 时区设置
ENV TZ=Asia/Shanghai \JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Djava.security.egd=file:/dev/./urandom" \SPRING_PROFILES_ACTIVE=prod \SERVER_PORT=48087EXPOSE 48087USER adduser# 健康检查(可选)
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \CMD wget --no-verbose --tries=1 --spider http://localhost:${SERVER_PORT}/actuator/health || exit 1ENTRYPOINT ["sh", "-c", "exec java ${JAVA_OPTS} -Dspring.profiles.active=${SPRING_PROFILES_ACTIVE} -jar app.jar"]

关键点解析

  1. 使用 JRE 而非 JDK

    • eclipse-temurin:17-jre-alpine:精简镜像(~180MB)
    • Alpine Linux:基于 musl libc 的超轻量级发行版
  2. 安全性考虑

    • 创建非 root 用户运行应用
    • 使用 --chown 直接设置文件权限
  3. JVM 参数优化

    • -Xms512m -Xmx1024m:堆内存配置
    • -XX:+UseG1GC:使用 G1 垃圾回收器
    • -XX:MaxGCPauseMillis=200:最大停顿时间 200ms
  4. 健康检查

    • 需要应用开启 Spring Boot Actuator
    • 自动检测服务是否健康
  5. 灵活配置

    • 通过环境变量控制 JVM 参数和 Spring Profile
    • 运行时可通过 -e 参数覆盖

第三、四阶段:另外两个服务

结构与 ayy-server 类似,只是:

  • 复制的 JAR 路径不同
  • 暴露的端口不同

.dockerignore 配置

.dockerignore 文件告诉 Docker 哪些文件不需要复制到镜像中

# Maven 构建产物(避免复制本地编译的 target 目录)
target/
*/target/
**/target/
**/dependency-reduced-pom.xml# IDE 配置文件
.idea/
*.iml
.vscode/
.history/
.eclipse/
.settings/# Git 相关
.git/
.gitignore
.gitattributes# 日志文件
**/logs/
*.log# 临时文件
**/*.tmp
**/*.temp
**/*.swp
**/*.swo
**/*.bak
**/*.DS_Store
*~# Docker 相关(避免递归)
Dockerfile
docker-compose.yml
.dockerignore# 文档
README.md
docs/# CI/CD 配置
.github/
.gitlab-ci.yml
Jenkinsfile# 前端构建产物
**/node_modules/
**/dist/# 测试覆盖率
**/coverage/
**/.nyc_output/# 其他
.gitee/
.run/
.image/
script/

为什么需要 .dockerignore?

  1. 减少构建上下文大小:避免复制无用文件
  2. 加快构建速度:传输到 Docker daemon 的数据更少
  3. 避免缓存失效:无关文件变化不会触发重新构建

构建镜像

方式一:单独构建(适合开发测试)

1. 构建 ayy-server
docker build --target ayy-server -t ayy-server:latest .

命令解析

  • --target ayy-server:指定构建目标阶段
  • -t ayy-server:latest:镜像名称和标签
  • .:构建上下文(当前目录)
2. 构建 ayy-snailjob-server
docker build --target ayy-snailjob-server -t ayy-snailjob-server:latest .
3. 构建 ayy-monitor-admin
docker build --target ayy-monitor-admin -t ayy-monitor-admin:latest .

方式二:带版本号构建(适合生产发布)

# 定义版本号
VERSION=1.0.0# 构建三个镜像(同时打 VERSION 和 latest 标签)
docker build --target ayy-server -t ayy-server:${VERSION} -t ayy-server:latest .
docker build --target ayy-snailjob-server -t ayy-snailjob-server:${VERSION} -t ayy-snailjob-server:latest .
docker build --target ayy-monitor-admin -t ayy-monitor-admin:${VERSION} -t ayy-monitor-admin:latest .

方式三:使用脚本批量构建

创建 build.sh

#!/bin/bash
set -eVERSION=${1:-latest}echo "开始构建镜像,版本: ${VERSION}"# 启用 BuildKit
export DOCKER_BUILDKIT=1# 构建 ayy-server
echo "构建 ayy-server..."
docker build --target ayy-server -t ayy-server:${VERSION} -t ayy-server:latest .# 构建 ayy-snailjob-server
echo "构建 ayy-snailjob-server..."
docker build --target ayy-snailjob-server -t ayy-snailjob-server:${VERSION} -t ayy-snailjob-server:latest .# 构建 ayy-monitor-admin
echo "构建 ayy-monitor-admin..."
docker build --target ayy-monitor-admin -t ayy-monitor-admin:${VERSION} -t ayy-monitor-admin:latest .echo "✓ 所有镜像构建完成!"# 显示镜像列表
docker images | grep -E "ayy-server|ayy-snailjob-server|ayy-monitor-admin"

使用方法:

# 赋予执行权限
chmod +x build.sh# 构建 latest 版本
./build.sh# 构建指定版本
./build.sh 1.0.0

验证构建结果

# 查看构建的镜像
docker images | grep ayy# 输出示例:
# ayy-server              latest    abc123def456   2 minutes ago   350MB
# ayy-snailjob-server     latest    def456ghi789   3 minutes ago   340MB
# ayy-monitor-admin       latest    ghi789jkl012   4 minutes ago   345MB

运行容器

基础运行

1. 运行 ayy-server
docker run -d \--name ayy-server \-p 48087:48087 \ayy-server:latest

参数说明

  • -d:后台运行
  • --name ayy-server:容器名称
  • -p 48087:48087:端口映射(宿主机:容器)
2. 运行 ayy-snailjob-server
docker run -d \--name ayy-snailjob-server \-p 9090:9090 \ayy-snailjob-server:latest
3. 运行 ayy-monitor-admin
docker run -d \--name ayy-monitor-admin \-p 8800:8800 \-p 17888:17888 \ayy-monitor-admin:latest

高级运行(带配置)

docker run -d \--name ayy-server \-p 48087:48087 \-e SPRING_PROFILES_ACTIVE=prod \-e JAVA_OPTS="-Xms1g -Xmx2g" \-e SPRING_DATASOURCE_URL="jdbc:mysql://192.168.1.100:3306/ayy?useUnicode=true&characterEncoding=utf8" \-e SPRING_DATASOURCE_USERNAME=root \-e SPRING_DATASOURCE_PASSWORD=password \-e SPRING_REDIS_HOST=192.168.1.100 \-e SPRING_REDIS_PORT=6379 \-v /data/logs/ayy-server:/app/logs \-v /data/config/ayy-server:/app/config:ro \--restart unless-stopped \ayy-server:latest

高级参数说明

  • -e:环境变量注入

    • SPRING_PROFILES_ACTIVE:Spring 环境配置
    • JAVA_OPTS:JVM 参数
    • SPRING_DATASOURCE_*:数据库配置
    • SPRING_REDIS_*:Redis 配置
  • -v:数据卷挂载

    • /data/logs/ayy-server:/app/logs:日志持久化
    • /data/config/ayy-server:/app/config:ro:配置文件(只读)
  • --restart unless-stopped:自动重启策略

查看容器状态

# 查看运行中的容器
docker ps# 查看容器日志
docker logs -f ayy-server# 查看容器资源使用情况
docker stats ayy-server# 进入容器(调试用)
docker exec -it ayy-server sh

停止和清理

# 停止容器
docker stop ayy-server ayy-snailjob-server ayy-monitor-admin# 删除容器
docker rm ayy-server ayy-snailjob-server ayy-monitor-admin# 删除镜像
docker rmi ayy-server:latest ayy-snailjob-server:latest ayy-monitor-admin:latest

生产部署

使用 Docker Compose(推荐)

创建 docker-compose.yml

services:mysql:image: mysql:8.0container_name: ayy-mysqlenvironment:MYSQL_ROOT_PASSWORD: your_passwordMYSQL_DATABASE: ayyTZ: Asia/Shanghaiports:- "3306:3306"volumes:- mysql-data:/var/lib/mysqlnetworks:- ayy-networkrestart: unless-stoppedredis:image: redis:7-alpinecontainer_name: ayy-redisports:- "6379:6379"volumes:- redis-data:/datanetworks:- ayy-networkrestart: unless-stoppedcommand: redis-server --appendonly yesayy-server:image: ayy-server:latestcontainer_name: ayy-serverports:- "48087:48087"environment:SPRING_PROFILES_ACTIVE: prodJAVA_OPTS: "-Xms1g -Xmx2g"SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/ayy?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/ShanghaiSPRING_DATASOURCE_USERNAME: rootSPRING_DATASOURCE_PASSWORD: your_passwordSPRING_REDIS_HOST: redisSPRING_REDIS_PORT: 6379volumes:- ./logs/ayy-server:/app/logsnetworks:- ayy-networkdepends_on:- mysql- redisrestart: unless-stoppedayy-snailjob-server:image: ayy-snailjob-server:latestcontainer_name: ayy-snailjob-serverports:- "9090:9090"environment:SPRING_PROFILES_ACTIVE: prodJAVA_OPTS: "-Xms512m -Xmx1g"volumes:- ./logs/ayy-snailjob-server:/app/logsnetworks:- ayy-networkdepends_on:- mysql- redisrestart: unless-stoppedayy-monitor-admin:image: ayy-monitor-admin:latestcontainer_name: ayy-monitor-adminports:- "8800:8800"- "17888:17888"environment:SPRING_PROFILES_ACTIVE: prodJAVA_OPTS: "-Xms512m -Xmx1g"volumes:- ./logs/ayy-monitor-admin:/app/logsnetworks:- ayy-networkdepends_on:- mysqlrestart: unless-stoppednetworks:ayy-network:driver: bridgevolumes:mysql-data:redis-data:

使用方法

# 启动所有服务
docker-compose up -d# 查看服务状态
docker-compose ps# 查看日志
docker-compose logs -f ayy-server# 停止所有服务
docker-compose down# 停止并删除数据卷
docker-compose down -v

推送到镜像仓库

# 登录镜像仓库(以阿里云为例)
docker login --username=your_username registry.cn-hangzhou.aliyuncs.com# 打标签
docker tag ayy-server:latest registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-server:1.0.0
docker tag ayy-snailjob-server:latest registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-snailjob-server:1.0.0
docker tag ayy-monitor-admin:latest registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-monitor-admin:1.0.0# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-server:1.0.0
docker push registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-snailjob-server:1.0.0
docker push registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-monitor-admin:1.0.0

生产服务器拉取运行

# 拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-server:1.0.0# 运行
docker run -d \--name ayy-server \-p 48087:48087 \-e SPRING_PROFILES_ACTIVE=prod \-v /data/logs:/app/logs \--restart unless-stopped \registry.cn-hangzhou.aliyuncs.com/your_namespace/ayy-server:1.0.0

常见问题

Q1: 构建很慢,如何优化?

A: 使用以下技巧:

  1. 启用 BuildKit
export DOCKER_BUILDKIT=1
  1. 使用国内 Maven 镜像

在项目根目录创建 .mvn/maven.config

-Dmaven.repo.local=/root/.m2/repository

在 Dockerfile 添加镜像配置:

RUN mkdir -p /root/.m2 && \echo '<settings><mirrors><mirror><id>aliyun</id><mirrorOf>*</mirrorOf><url>https://maven.aliyun.com/repository/public</url></mirror></mirrors></settings>' > /root/.m2/settings.xml
  1. 利用缓存

分层复制 POM 文件,依赖不变时会使用缓存。

Q2: 健康检查一直失败?

A: 检查以下几点:

  1. 确认应用已开启 Actuator

pom.xml 添加依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.yml 配置:

management:endpoints:web:exposure:include: healthendpoint:health:show-details: always
  1. 临时禁用健康检查

在 Dockerfile 中注释掉 HEALTHCHECK 行。

Q3: 镜像太大怎么办?

A: 优化建议:

  1. 已使用 Alpine 基础镜像(~180MB)
  2. 清理 Maven 缓存(仅在构建阶段)
  3. 移除不必要的依赖

查看镜像层大小:

docker history ayy-server:latest

Q4: 如何查看容器内的日志?

A: 三种方式:

# 方式 1: 查看容器标准输出
docker logs -f ayy-server# 方式 2: 挂载日志目录(推荐)
docker run -v /data/logs:/app/logs ...# 方式 3: 进入容器查看
docker exec -it ayy-server sh
cd /app/logs
tail -f application.log

Q5: 如何覆盖配置文件?

A: 使用数据卷挂载:

# 准备配置文件
mkdir -p /data/config/ayy-server
cp application-prod.yml /data/config/ayy-server/# 挂载配置目录
docker run -v /data/config/ayy-server:/app/config:ro ...

application.yml 中配置:

spring:config:additional-location: file:/app/config/

Q6: 如何回滚到旧版本?

A: 使用版本标签:

# 停止当前版本
docker stop ayy-server
docker rm ayy-server# 运行旧版本
docker run -d \--name ayy-server \-p 48087:48087 \ayy-server:1.0.0  # 指定旧版本

总结

本教程涵盖了 Docker 多阶段构建的完整流程:

Dockerfile 编写:多阶段构建、层缓存优化
.dockerignore 配置:减少构建上下文
镜像构建:单独构建、批量构建、版本管理
容器运行:基础运行、高级配置、日志管理
生产部署:Docker Compose、镜像仓库、自动化


参考资料

  • Docker 官方文档
  • Spring Boot Docker 最佳实践
  • Maven Docker 插件
http://www.dtcms.com/a/601113.html

相关文章:

  • Docker 启动 EMQX 5.x 并配置自签名证书
  • 网站招工费怎么做会计分录小小视频免费观看高清
  • C++重点知识梳理(上)
  • 长沙市建设局官方网站wordpress 显示文章标签
  • 基于用户评论分析挖掘的旅游景点推荐系统
  • 宣传旅游网站建设的重点是什么装修公司哪家好排名
  • 【C语言学习笔记】动态内存分配:malloc/free的正确打开方式
  • HOVER:用于人形机器人的多功能全身神经控制器
  • 学会给网页穿衣服——学习 CSS 语言
  • Android11-Launcher3 定制-去除副屏幕-可以滑动效果 - 篇二
  • 在 ubuntu怎么创建一个新用户,并且设置为默认自动登录用户,最简单
  • 字符串的陷阱与艺术——std::string全解析
  • 深信服云桌面有什么替代方案?
  • 网页制作与网站建设试卷及答案wordpress 默认文章形式
  • 企业为什么要建立自己的网站云南工程建设信息网站
  • Dubbo如何使用Nacos做注册中心的
  • 决策树悲观错误剪枝(PEP)详解:原理、实现与应用
  • 外卖项目 day01
  • 前端vue3 window.open 项目部署后页面404解决办法
  • pc网站 手机网站 微信网站 上海跨境电商官方网站建设
  • Windows 10 C语言编译器安装与配置
  • 网站后台进不去的原因挂机宝做php网站吗
  • Java I/O模型演进 — BIO、NIO与AIO的原理与实战
  • Flutter---泛型
  • 小米Java开发200道面试题及参考答案(上)
  • 【实战】如何优雅的在Win11/10系统下运行Rust编写的binwalk v3.1.1
  • 网站建设费可以计入管理费用吗手机网站开发利用流程
  • MySQL进阶学习笔记:从单表查询到多表关联的深度解析(万字详解)
  • docker一键部署PDF免费工具箱stirling-PDF
  • CI/CD工具Arbess,从安装到入门零基础教程