前言
每当在本地 docker build 和 docker push 时,你是否想过:要是代码提交后,镜像能自动构建、自动推送,该多好?GitHub Actions 让这一切变为现实——只要写好 .yml 配置文件,每次 git push 都能自动化完成打包与部署。
本文将从零开始,教你配置一套完整的 GitHub Actions 流水线:从 Maven 编译、单元测试,到 Docker 多阶段构建,再到镜像推送到 Docker Hub 或 GitHub 私有仓库。包含完整的 YAML 配置、缓存策略和安全性最佳实践。
本文属于 MACS Dev Hub“现代架构与编码解决方案”系列。前文已介绍 WSL2+Docker 开发环境搭建 和 Spring AI+Ollama 本地生成 SQL,建议结合阅读。
一、核心 YAML 配置解析
1.1 GitHub Actions 架构原理
GitHub Actions 的本质是事件驱动的无服务器执行平台。其核心组件包括:
- Workflow(工作流):存放在
.github/workflows/目录下的 YAML 文件,定义了完整的 CI/CD 流程。 - Event(事件):触发工作流的 Git 行为,如
push、pull_request、release等。 - Job(任务):工作流中的一个执行单元,包含多个 Step。
- Step(步骤):具体的执行动作,可以是 Shell 命令或预置 Action。

流程图
1.2 完整工作流配置
以下是一个面向生产环境的完整配置文件 .github/workflows/docker-build.yml:
name: Java CI/CD with Docker
on:
push:
branches: [ main ]
paths-ignore:
- '**.md'
- '.gitignore'
pull_request:
branches: [ main ]
workflow_dispatch: # 支持手动触发
env:
REGISTRY: docker.io
IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/my-java-app
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # 用于 GHCR 推送
steps:
# 1. 检出代码
- name: Checkout code
uses: actions/checkout@v4
# 2. 设置 JDK 17 并启用 Maven 缓存
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven # 一键启用 Maven 依赖缓存
# 3. 运行单元测试
- name: Run tests
run: mvn clean test
# 4. 编译打包
- name: Build with Maven
run: mvn package -DskipTests
# 5. 登录 Docker Hub
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
# 6. 构建并推送 Docker 镜像
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ env.IMAGE_NAME }}:latest
${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
1.3 关键步骤详解
Step 1:检出代码(actions/checkout@v4)
- uses: actions/checkout@v4
将 GitHub 仓库代码拉取到 Runner 的工作目录中。@v4 是当前最新稳定版本。
Step 2:设置 JDK 17(actions/setup-java@v4)
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven # 自动缓存 ~/.m2/repository
cache: maven 是 setup-java v4 引入的内置缓存功能,相比旧版本需要单独配置 actions/cache 更简洁。它会自动缓存 Maven 依赖,将下载时间从分钟级降到秒级。
Step 3:运行测试与编译
- run: mvn clean test # 单元测试
- run: mvn package -DskipTests # 跳过测试加快构建
-DskipTests 跳过测试执行(但仍会编译测试代码),适合快速构建镜像的场景。生产环境建议保留测试阶段。
Step 4:登录镜像仓库(docker/login-action@v3)
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- Docker Hub 账号密码需存放在 GitHub Secrets 中(Settings → Secrets and variables → Actions)。
- 若使用 GitHub Container Registry,则将
username: ${{ github.actor }},password: ${{ secrets.GITHUB_TOKEN }},并添加registry: ghcr.io。
Step 5:构建并推送镜像(docker/build-push-action@v6)
- uses: docker/build-push-action@v6
with:
context: . # 构建上下文目录
push: true # 构建后立即推送
tags: | # 镜像标签
user/app:latest
user/app:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-push-action 是 GitHub Actions 生态中构建 Docker 镜像的终极工具,深度集成了 Docker Buildx,支持多平台构建、密钥管理和远程缓存等高级功能。
cache-from: type=gha 与 cache-to: type=gha 利用 GitHub Actions 的内置缓存来加速镜像层构建。mode=max 会缓存所有构建层,最大化命中率。
| 参数 | 说明 |
|---|---|
context | Docker 构建上下文目录 |
push | 是否推送镜像 |
tags | 镜像标签,支持多标签 |
cache-from | 从指定源读取缓存 |
cache-to | 保存缓存到指定源 |
二、Dockerfile 多阶段构建
为了让流水线真正高效,Dockerfile 的写法至关重要。推荐使用多阶段构建:用 JDK 编译,用 JRE 运行,显著减小最终镜像体积。
# 阶段 1:构建阶段(使用完整 JDK)
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
# 先复制依赖文件,利用 Docker 层缓存
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
RUN ./mvnw dependency:go-offline -B
# 再复制源代码并打包
COPY src src
RUN ./mvnw package -DskipTests
# 阶段 2:运行阶段(使用精简 JRE)
FROM eclipse-temurin:21-jre-alpine
# 创建非 root 用户运行应用
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
WORKDIR /app
# 从构建阶段复制 JAR 包
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
多阶段构建的两大优势:
- 最终镜像只包含 JRE 和 JAR 包,不含编译工具、源码等冗余文件,镜像体积可减小约 70%。
- 先复制
pom.xml并下载依赖,再复制源代码,能最大化利用 Docker 的层缓存——只要依赖不变,下载步骤不会重复执行。
三、缓存策略详解
3.1 Maven 依赖缓存
在 actions/setup-java@v4 中设置 cache: maven 即可自动处理:
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven
这会在 ~/.m2/repository 路径缓存 Maven 依赖,后续流水线命中缓存后,依赖下载步骤直接跳过。
3.2 Docker 层缓存
build-push-action 支持两种层缓存策略:
| 策略 | 适用场景 | 配置方式 |
|---|---|---|
| GitHub Actions 缓存(gha) | 同仓库、同分支的多次构建 | cache-from: type=gha |
| Registry 缓存 | 跨仓库或自托管 Runner | cache-from: type=registry,ref=user/app:cache |
3.3 判断缓存命中
actions/cache 提供了 cache-hit 输出,可用于条件判断:
- name: Cache Maven dependencies
id: cache-maven
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2-
- name: Install dependencies
if: steps.cache-maven.outputs.cache-hit != 'true'
run: mvn dependency:go-offline
3.4 各缓存策略对比
| 缓存类型 | 命中率 | 配置复杂度 | 关键参数 |
|---|---|---|---|
| Maven 依赖 | 高 | 低 | cache: maven |
| Docker 层 (gha) | 中 | 低 | type=gha |
| Docker 层 (registry) | 高 | 中 | type=registry,ref=镜像:缓存标签 |
四、安全实践
4.1 敏感信息管理
所有密码、Token 都应存放在 GitHub Secrets 中,严禁硬编码。访问路径:Settings → Secrets and variables → Actions。
Secrets 分为三个层级:
- 仓库级:仅当前仓库可用,适合 DOCKER_USERNAME 等通用凭证。
- 环境级:分环境(dev/prod)隔离,适合多环境密钥管理。
- 组织级:组织下多个仓库共享,适合团队统一管理。
4.2 OIDC 替代长期令牌
对于云平台(AWS/GCP/Azure),推荐使用 OpenID Connect(OIDC) 替代长期密码。OIDC 让 GitHub Actions 可以请求短期访问令牌,密码不会暴露在 Secrets 中,安全性更高。
4.3 最小权限原则
permissions:
contents: read # 只读代码
packages: write # 仅 GHCR 场景需要
id-token: write # OIDC 场景需要
不要滥用 permissions,只给予任务所需的最小权限。切勿在日志中打印或硬编码 Secrets。
4.4 Action 版本固定
使用 uses: actions/checkout@v4 而非 @main 或 @latest,避免第三方 Action 被篡改带来的供应链攻击风险。
五、进阶:推送至 GHCR
GitHub Container Registry(GHCR)是与 GitHub 仓库深度集成的镜像仓库,权限直接继承 GitHub 的团队管理模型。
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} # 自动注入的临时 Token
- name: Build and push to GHCR
uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
secrets.GITHUB_TOKEN 是 GitHub Actions 运行时自动注入的临时 Token,无需手动配置。github.repository 的格式为 owner/repo-name。
GHCR 与 Docker Hub 对比:
| 对比项 | GHCR | Docker Hub |
|---|---|---|
| 与代码仓库关联 | 极强 | 一般 |
| 权限继承 | GitHub 权限体系 | 独立 Docker Hub 权限 |
| Actions 集成 | 原生支持 | 需额外配置 |
六、完整 YAML 示例(生产级)
以下是融合了多阶段构建、缓存优化和安全实践的完整配置文件:
name: Production CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Run tests
run: mvn clean test
build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build JAR
run: mvn package -DskipTests
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=sha,format=long
type=raw,value=latest
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
七、常见问题
| 问题 | 原因 | 解决方法 |
|---|---|---|
permission denied while trying to connect to Docker daemon | Runner 无 Docker 权限 | 使用官方 Runner(已预装 Docker) |
| Maven 依赖一直重新下载 | cache: maven 未生效 | 确认 setup-java 版本为 v4,检查 pom.xml 哈希是否变化 |
| Docker 镜像未推送 | push: true 漏配或登录失败 | 检查登录步骤是否成功,确认 Secrets 正确 |
denied: requested access to the resource is denied | Token 权限不足 | 检查 Token 是否包含 write:packages 权限 |
| 构建时间过长 | 缓存未命中 | 检查 pom.xml 和 Dockerfile 层顺序优化 |
八、总结
本文从零开始配置了一套完整的 GitHub Actions 流水线,涵盖了以下核心要点:
- 核心 YAML 配置:checkout、setup-java、Maven 构建、Docker 登录与推送
- 多阶段 Dockerfile:构建阶段用 JDK,运行阶段用 JRE,镜像体积减小约 70%
- 缓存策略:Maven 依赖缓存 + Docker 层缓存,构建时间从数分钟降至秒级
- 安全实践:Secrets 管理、最小权限原则、Action 版本固定
- 镜像仓库:Docker Hub 与 GHCR 两种方案对比
GitHub Actions 的免费配额(每月 2000 分钟构建时间)足以支撑中小项目的日常需求。将这套流水线配置好,你就能真正享受 “代码提交,镜像自动就绪” 的现代化开发体验。
本文全部代码示例已在 Windows 11 + WSL2 环境下验证。若配置中遇到问题,欢迎访问 MACS Dev Hub 留言交流。后续文章将深入探讨 Java 应用接入 Prometheus + Grafana 监控,敬请期待。
GitHub Actions Java Docker镜像构建、Maven GitHub Actions缓存配置、Spring Boot GitHub CI/CD流水线、Docker多阶段构建最佳实践、build-push-action v6 使用教程、GitHub Container Registry 配置指南、Java项目自动打包推送Docker Hub 2026





