欢迎光临
我们一直在努力

【DevOps实战】使用 GitHub Actions 自动构建镜像并双推至 Docker Hub 和 GHCR

在现代软件开发中,CI/CD(持续集成/持续部署) 已经成为标配。对于容器化项目来说,最爽的体验莫过于:代码一提交,镜像自动打好并推送到仓库,随时可以拉取部署。

本文将以一个前后端分离项目(Go + Vue)为例,详细介绍如何使用 GitHub Actions 搭建一套自动化的 Docker 构建流水线,并实现 “一次构建,双重推送” ——同时推送到 GitHub Container Registry (ghcr.io) 和 Docker Hub。

🚀 为什么要做双重推送?

  • GitHub Container Registry (GHCR):
    • 优势:与 GitHub 源码仓库无缝集成,拉取速度快,权限管理方便(使用 GitHub Token 即可)。
    • 场景:适合内部开发、CI 流程中间产物。
  • Docker Hub:
    • 优势:全球最大的容器镜像库,也是默认的 Docker 拉取源。
    • 场景:适合对外发布正式版本,用户 docker pull 时不需要输入长长的域名。
  • 🛠️ 准备工作

    在开始编写流水线之前,我们需要准备好 Dockerfile 并配置好安全凭证。

    1. 准备 Dockerfile(多阶段构建)

    为了减小镜像体积,强烈建议使用多阶段构建 (Multi-stage Build)。以下是一个典型的 Go + Vue 项目的 Dockerfile 示例:

    # Stage 1: 构建前端
    FROM node:20-alpine AS frontend-builder
    WORKDIR /web
    COPY frontend/package.json ./
    RUN npm install
    COPY frontend/ .
    RUN npm run build

    # Stage 2: 构建后端
    FROM golang:1.24-alpine AS backend-builder
    WORKDIR /server
    COPY backend/go.mod backend/go.sum ./
    RUN go mod download
    COPY backend/ .
    # 编译为静态二进制文件
    RUN CGO\\_ENABLED=1 GOOS=linux go build -ldflags="-s -w" -o app-server main.go

    # Stage 3: 最终运行时 (极简 Alpine)
    FROM alpine:latest
    WORKDIR /app
    # 复制后端二进制
    COPY –from=backend-builder /server/app-server .
    # 复制前端静态资源
    COPY –from=frontend-builder /web/dist ./dist
    # 暴露端口
    EXPOSE 3000
    CMD ["./app-server"]

    2. 配置 Docker Hub Access Token

    ⚠️ 警告:千万不要在 CI/CD 中直接使用你的 Docker Hub 登录密码!

  • 登录 Docker Hub。
  • 点击头像 -> Account Settings -> Security -> New Access Token。
  • 设置描述(如 “GitHub Actions”),权限选 “Read & Write”,生成并复制 Token。
  • 3. 配置 GitHub Secrets

    为了让 GitHub Actions 能登录你的 Docker Hub,需要将用户名和 Token 存入仓库密钥。

  • 进入 GitHub 项目仓库 -> Settings -> Secrets and variables -> Actions。
  • 点击 New repository secret,添加以下两个变量:
    • DOCKERHUB_USERNAME: 你的 Docker Hub 用户名
    • DOCKERHUB_TOKEN: 刚才复制的 Token
  • ⚙️ 编写 GitHub Actions Workflow

    在项目根目录下创建文件:.github/workflows/docker-publish.yml。

    这个 Workflow 实现了以下核心逻辑:

  • 触发机制:代码推送到 main 分支或打上 v* 标签(如 v1.0.0)时触发。
  • 权限设置:允许 Action 写入 GitHub Packages。
  • 多源登录:同时登录 GHCR 和 Docker Hub。
  • 智能 Tag:自动根据 Git 分支名或 Tag 名生成 Docker Tag(例如自动生成 latest)。
  • name: Build and Publish Docker Image

    on:
    push:
    branches: [ "main" ] # 推送到 main 分支时触发
    tags: [ 'v*.*.*' ] # 推送 v1.0.0 格式 tag 时触发
    pull\\_request:
    branches: [ "main" ] # PR 时只构建不推送

    env:
    # GitHub Container Registry 配置
    REGISTRY_GHCR: ghcr.io
    IMAGE_NAME_GHCR: ${{ github.repository }}
    # Docker Hub 配置 (格式:用户名/项目名)
    IMAGE_NAME_DOCKERHUB: ${{ secrets.DOCKERHUB_USERNAME }}/nanodoc

    jobs:
    build-and-push:
    runs-on: ubuntulatest
    permissions:
    contents: read
    packages: write # 允许写入 GitHub Packages

    steps:
    # 1. 检出代码
    name: Checkout repository
    uses: actions/checkout@v4

    # 2. 设置 Docker 构建环境
    name: Set up Docker Buildx
    uses: docker/setupbuildxaction@v3

    # 3. 登录 GitHub Container Registry
    name: Log into ghcr.io
    if: github.event_name != 'pull_request'
    uses: docker/loginaction@v3
    with:
    registry: ${{ env.REGISTRY_GHCR }}
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }} # GitHub 自带 Token

    # 4. 登录 Docker Hub (使用 Secrets)
    name: Log into Docker Hub
    if: github.event_name != 'pull_request'
    uses: docker/loginaction@v3
    with:
    username: ${{ secrets.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}

    # 5. 提取元数据 (自动生成 Tags)
    # 这步非常关键,它会同时为两个 Registry 生成对应的 tags
    name: Extract Docker metadata
    id: meta
    uses: docker/metadataaction@v5
    with:
    images: |
    ${{ env.REGISTRY_GHCR }}/${{ env.IMAGE_NAME_GHCR }}
    ${{ env.IMAGE_NAME_DOCKERHUB }}

    tags: |
    type=semver,pattern={{version}}
    type=ref,event=branch
    type=raw,value=latest,enable={{is_default_branch}}

    # 6. 构建并推送
    name: Build and push Docker image
    id: buildandpush
    uses: docker/buildpushaction@v5
    with:
    context: .
    file: ./Dockerfile
    push: ${{ github.event_name != 'pull_request' }}
    tags: ${{ steps.meta.outputs.tags }}
    labels: ${{ steps.meta.outputs.labels }}
    cache-from: type=gha # 使用 GitHub Actions 缓存加速
    cache-to: type=gha,mode=max

    ✅ 验证与使用

    配置完成后,当你下一次推送代码时,Action 就会自动运行。

    场景一:日常开发推送

    当你执行 git push origin main 时,Action 会构建并推送:

    • ghcr.io/yourname/nanodoc:main
    • yourname/nanodoc:main

    场景二:发布版本

    当你打上 Tag 并推送时:

    git tag v1.0.0
    git push origin v1.0.0

    Action 会构建并推送以下 Tag,非常适合生产环境使用:

    • ghcr.io/yourname/nanodoc:v1.0.0
    • ghcr.io/yourname/nanodoc:latest
    • yourname/nanodoc:v1.0.0
    • yourname/nanodoc:latest

    用户如何拉取?

    用户现在可以自由选择源:

    # 从 Docker Hub 拉取 (默认,短路径)
    docker pull yourname/nanodoc:latest

    # 从 GitHub Packages 拉取
    docker pull ghcr.io/yourname/nanodoc:latest

    📝 总结

    通过这套配置,我们实现了一个专业的开源项目发布流程:

  • 安全性:不暴露密码,使用 Token。
  • 自动化:完全由 Git 操作触发,无需人工干预。
  • 多源分发:同时覆盖了 GitHub 生态用户和 Docker Hub 大众用户。
  • 高效:利用 Docker Layer 缓存和 GitHub Actions 缓存,构建速度飞快。
  • 希望这篇实战教程能帮到正在折腾 CI/CD 的你!🚀

    赞(0)
    未经允许不得转载:171主机测评 » 【DevOps实战】使用 GitHub Actions 自动构建镜像并双推至 Docker Hub 和 GHCR
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址