发布于 2026-01-06 0 阅读
0

使用 GitHub Actions 自动构建 Docker 镜像 DEV 的全球展示与讲述挑战赛,由 Mux 呈现:展示你的项目!

使用 GitHub Actions 自动构建 Docker 镜像

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

目录

介绍

当我发布新版本的 Web 应用程序时,我遵循了以下流程,这听起来可能对您来说并不陌生:

  1. 我已将所有内容合并到主分支。
  2. 通过 SSH 连接到部署服务器
  3. git fetch
  4. git checkout
  5. git pull
  6. 构建 Docker 镜像(这非常耗时,而且一旦 Web 应用程序足够大,就会失败)
  7. 这样我就需要在我的电脑或其他特定服务器上构建镜像,以避免生产服务器崩溃。
  8. 将其推送到注册表
  9. 返回服务器并从注册表中提取数据。
  10. 意识到你没有更新环境变量
  11. 啊啊啊啊啊啊啊!!!
  12. 翻转桌子 GIF

我现在是这样做的:

  1. 推送一个新的语义化版本控制(semver)发布标签。例如,1.0.1从我喜欢的任何分支推送。
  2. 就是这样!

这与完美的 Git 策略完美契合。

快乐程序员


设置自托管运行程序

如果您已经了解 GitHub Actions 的所有功能,只想了解如何构建 Docker 镜像,请继续阅读“GitHub Actions 构建 Docker 镜像”部分。

定义:运行器是一个实例,它可以在你的 GitHub Action 中运行任何你想要执行的操作。从打印输出Hello World到构建和部署应用,甚至帮你煮咖啡(真的!),它都能做到。你可以把它想象成一个用户,它可以在远程服务器(Linux、Windows 等)上运行你指定的任何操作。

GitHub 为您提供 2 个选项:

  • 每月可免费使用他们的跑步机最多 X 分钟,之后再付费。
  • 搭建一个自托管的运行环境并免费使用。

如果你选择第一个选项,请跳过此部分;否则,请继续阅读。

由于我已经有了家庭实验室,而且搭建运行环境也很容易,所以自托管是省钱的好办法。你也可以用旧电脑,甚至是闲置的树莓派来搭建运行环境。

如果您想了解更多关于自托管运行器的信息,请查看GitHub 的文档

以下是搭建自托管运行环境所需的内容:

  1. 选择你想要运行的操作系统。我个人比较喜欢Ubuntu,它几乎可以满足我的所有需求,所以我选择了Linux系统。
  2. 请确保运行器中已安装所有必要的软件包。就我的使用场景而言,我需要先安装 Docker。
  3. 前往您的 GitHub 代码库,然后点击“设置”。GitHub 仓库设置图标
  4. 在左侧面板中,点击“操作”,然后点击“跑者” 。 GitHub Actions 位于侧边菜单中
  5. 选择新的自托管 Runner 新的自托管跑步按钮
  6. 选择您要使用的操作系统和架构操作系统运行选项
  7. 请按照您所选内容下方显示的终端命令完成运行器的设置。由于 GitHub 会不时更新这些命令,因此我不想在此处发布它们,请直接按照 GitHub 上的说明操作即可。
  8. 在 Linux 机器上完成运行程序的设置后,您应该可以在之前的运行程序页面中看到它,就可以使用它了!跑者闲置卡

GitHub Action 的结构

GitHub 操作定义在.yml文件中。它们本质上是一组指令,告诉运行器该做什么。

它们存在.github/workflows/于您的存储库中,一旦您将它们推送到您的主分支,它们就会生效并正常工作

你可以直接使用 GitHub 的网页界面或你喜欢的代码编辑器编写代码,然后将其推送到你的主分支。

如果你使用 VSCode,它有一个 GitHub Actions 扩展程序,可以非常方便地编辑工作流并查看正在运行的程序。

一个简单的 GitHub action 由 4 个主要部分组成:

1.name

很简单,这只是你想给这个操作起的名字,以便以后跟踪它。

name: My GitHub action name
Enter fullscreen mode Exit fullscreen mode

2.on

这就是你想要触发操作的条件。最常见的情况是,当代码推送到特定分支或发起拉取请求时,触发某个操作。但触发条件还有很多。

您可以在这里查看所有触发器的文档:

https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows

以下是一个示例代码:

  • 能够手动触发 GitHub 操作。有关如何从 GitHub Web 界面触发此操作的更多信息,请参阅“手动运行工作流”。
  • 当有推送到my-branch-nameandmy-other-branch-name分支时触发该操作。
on:
  # Trigger the action manually from the UI
  workflow_dispatch:
  # Trigger the action when pushing to certain branches
  push:
    branches:
      - 'my-branch-name'
      - 'my-other-branch-name'
Enter fullscreen mode Exit fullscreen mode

3.env

您可以在此处为特定操作设置环境变量和密钥。这可以与 GitHub 网站上的仓库变量和密钥功能结合使用。

如果你在多个步骤或作业中使用某个东西,最好在这里进行设置,这样你只需要更改一行代码即可。

env:
  DOCKER_IMAGE_NAME: my-image
Enter fullscreen mode Exit fullscreen mode

4.jobs

这些是您要执行的各个步骤。每个作业都包含一系列顺序步骤,并且每个作业都可以异步运行。您还可以创建依赖关系,以便某个作业只有在前一个作业完成后才会运行。

工作和步骤之间的区别

  • 作业是独立的、异步的任务。这意味着,如果您有多个可以异步(同时)执行的任务(例如:部署应用程序和上传新文档),您可以将它们放在不同的作业中。如果您有多个运行器,则可以同时执行多个作业。
  • 步骤是指同步执行的操作。如果您有需要按顺序执行的任务(例如:构建 Docker 镜像并将其推送到 Docker 镜像仓库),请将它们设置为步骤而不是作业。

示例代码:

jobs:
  build_docker_images:
    # Job name that shows in the GitHub UI
    name: Build Docker Images
    # Runner to use
    runs-on: self-hosted

    steps:
    - name: Checkout
      uses: actions/checkout@v3

   ...
Enter fullscreen mode Exit fullscreen mode

您可以在单个操作文件中设置任意数量的作业和步骤。


GitHub Action 构建 Docker 镜像

在本节中,我将向您展示如何从 A 构建 Docker 镜像Dockerfile并将其推送到 Docker Hub 或您的私有 Docker 镜像仓库。所有这一切都只需创建一个版本标签即可完成。

流程概述及要求

首先,如果您使用的是自托管运行器,请检查它是否正在运行,并且是否在您想要部署此功能的存储库中可用。同时,请确保您了解GitHub action 的结构

以下是具体要求:

当我推送版本标签时,我想获取版本名称(例如1.0.1:),然后构建 Docker 镜像并使用该版本号以及latest标签(例如:my-image:1.0.1my-image:latest)对其进行标记。

之后,我想把镜像推送到我自托管的私有 Docker Registry,并从运行器中删除所有数据。不过,你也可以这样做,将 Docker 镜像推送到 DockerHub。

我还想存储构建缓存,以便将来构建镜像时速度更快。

以下是流程概述:

  1. 手动触发操作,或通过推送版本标签触发操作。
  2. 使用 Git 检出该特定标签的代码
  3. 从标签中获取版本号
  4. 构建 Docker 镜像
  5. 镜像构建完成后,用版本号和我选择的 Docker 镜像仓库地址标记它。
  6. 将镜像推送到注册表

1. 环境变量和密钥

环境变量

为了方便日后需要更改注册表 URL 或镜像名称,我设置了以下环境变量:

# Workflow environment variables
env:
  DOCKER_IMAGE_NAME: my-image
  DOCKER_REGISTRY_URL: myregistry.domain.com
Enter fullscreen mode Exit fullscreen mode

秘密

我还想在我的 reo 中创建这些 GitHub Action Secret,以便能够访问 Docker 镜像仓库。我喜欢在工作流文件中添加注释,这样如果我移动了仓库或其他什么操作,就不会忘记了。

看在上帝的份上,请不要把这些内容放到你的工作流程文件中。

# Required actions secrets:
# - DOCKER_USERNAME: Username for docker registry login
# - DOCKER_PASSWORD: Password for docker registry login
Enter fullscreen mode Exit fullscreen mode

2. 触发器

我希望不仅在推送版本标签时触发该操作,而且手动操作也能触发该操作。

name: Build release Docker image

on:
  # Trigger the action manually from the UI
  workflow_dispatch:
  # Trigger the action when a version tag is pushed
  push:
    tags:
      - '[0-9]+.[0-9]+.[0-9]+' # Push events to matching numeric semver tags, i.e., 1.0.0, 20.15.10
Enter fullscreen mode Exit fullscreen mode

4. 作业设置

我只需要一份工作,因为我的所有步骤都需要按顺序进行。

jobs:
  build_docker_images:
    # Job name that shows in the GitHub Website:
    name: Build Docker Images
    # Runner to use:
    runs-on: self-hosted

    # Begin the steps
    steps:
      - step1
      - step2
      - ...
Enter fullscreen mode Exit fullscreen mode

4.1 从 GitHub 获取代码

GitHub 和 Docker 等许多其他服务都提供了现成的步骤。在本例中,我们将使用actions/checkout@v3GitHub 提供的步骤,该步骤会从代码仓库中获取代码。

# Checkout the code
- name: Checkout code
  uses: actions/checkout@v4
  with:
    fetch-depth: 0 # Do not get extra git branches to save time
Enter fullscreen mode Exit fullscreen mode

4.2 设置 Docker 构建器

与 GitHub 类似,Docker 也提供了一系列现成的步骤,在本例中,其中包含一个构建器设置操作。

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3
Enter fullscreen mode Exit fullscreen mode

4.3 登录 Docker Registry

- name: Login to Docker Registry
  uses: docker/login-action@v3
  with:
    registry: ${{ env.DOCKER_REGISTRY }}
    username: ${{ secrets.DOCKER_USERNAME }}
    password: ${{ secrets.DOCKER_PASSWORD }}
Enter fullscreen mode Exit fullscreen mode

4.4 获取版本号

这里我只获取了标签名称(X.Y.Z)。由于我们将触发器限制为仅对数字语义版本标签触发,因此我们可以确信标签的格式是正确的:X.Y.Z

- name: Get the tag name
  id: get_version
  run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
Enter fullscreen mode Exit fullscreen mode

4.5 构建并推送 Docker 镜像

Docker 为此步骤提供了一个非常方便的即用型操作。

- name: Build and Push the Docker Image
  uses: docker/build-push-action@v6
  with:
    context: .
    file: ./Dockerfile
    push: true
    tags: |
      ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.get_version.outputs.VERSION }}
      ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:latest
    cache-from: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:buildcache
    cache-to: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:buildcache,mode=max
Enter fullscreen mode Exit fullscreen mode

由于这一步并不那么直接,让我解释一下:

  • context: .我们指示构建器使用仓库的根目录作为构建上下文。例如,如果您有一个包含后端和前端目录的单体仓库,这将非常有用。您可以为每个目录创建两个作业,并在它们的上下文中切换。
  • file: ./Dockerfile我们正在告诉构建器 Dockerfile 的位置
  • push: true我们也想推广这些图片。
  • 标签部分表明我们要推送此镜像的两个标签。例如,如果我们想推送到多个目录,这也很有用。这里我使用了在工作流程开始时定义的环境变量,并推送了版本标签和最新标签。
  • cache-from:这意味着我们从哪里获取构建缓存,以加快后续构建速度。在本例中,我们从注册表中获取。
  • cache-to:与此类似chache-from,我们指示构建缓存应该存储在哪里,在本例中是注册表。

用于发布 Docker 镜像的完整 GitHub Actions 模板

以下是完整的操作代码。您可以将其复制粘贴到您的 YML 文件中,并根据需要进行修改:

# This workflow will build a Docker image
# and push them to a private docker registry when a release tag (i.e.: 1.0.1)
# is pushed to the repository.
#
# It runs on a self hosted runner.
# You can change the runner to 'ubuntu-latest' if you want to use a GitHub hosted runner.
#
# Required actions secrets in the repository:
# - DOCKER_USERNAME: Username for docker registry login
# - DOCKER_PASSWORD: Password for docker registry login

# Script environment variables
env:
  DOCKER_IMAGE_NAME: my-image
  DOCKER_REGISTRY: myregistry.mydomain.com

name: Build and Push Docker Image

# Triggers
on:
  # Trigger the action manually from the UI
  workflow_dispatch:
  # Trigger the action when a version tag is pushed
  push:
    tags:
      - '[0-9]+.[0-9]+.[0-9]+' # Push events to matching numeric semver tags, i.e., 1.0.0, 20.15.10

jobs:
  build-and-push-landing-page:
    name: Build and Push Landing Page Docker Image
    runs-on: self-hosted

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.DOCKER_REGISTRY }}
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Get the tag name
        id: get_version
        run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT

      - name: Build and push Landing Page Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: |
            ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:${{ steps.get_version.outputs.VERSION }}
            ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:latest
          cache-from: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:buildcache
          cache-to: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE_NAME }}:buildcache,mode=max
Enter fullscreen mode Exit fullscreen mode

结论

通过这种设置,您现在可以自动获得可在您选择的镜像仓库中使用的 Docker 镜像。

我将在后续文章中介绍如何在 Docker 镜像构建完成并推送到镜像仓库后自动部署该镜像。

文章来源:https://dev.to/onticdani/automatically-build-docker-images-with-github-actions-3n8e