# 发布 Docker 映像

本教程介绍如何将 Docker 映像发布到注册表，例如Docker Hub或 GitHub Packages，作为持续集成（CI）工作流的一部分。

## 简介

本指南介绍如何创建执行 Docker 生成的工作流，然后将 Docker 映像发布到 Docker Hub 或 GitHub Packages。 通过单个工作流程，您可以将映像发布到单一注册表或多个注册表。

> \[!NOTE]
> 如果要推送到另一个第三方 Docker 注册表，[发布映像到 GitHub Packages](#publishing-images-to-github-packages) 部分中的示例可以用作很好的模板。

## 先决条件

建议基本了解工作流程配置选项和如何创建工作流程文件。 有关详细信息，请参阅“[撰写工作流程](/zh/enterprise-server@3.22/actions/how-tos/write-workflows)”。

您可能还发现基本了解以下内容是有帮助的：

* [在 GitHub Actions 中使用机密](/zh/enterprise-server@3.22/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets)
* [在工作流中使用 GITHUB\_TOKEN 进行身份验证](/zh/enterprise-server@3.22/actions/tutorials/authenticate-with-github_token)
* [使用 Docker 注册表](/zh/enterprise-server@3.22/packages/working-with-a-github-packages-registry/working-with-the-docker-registry)

## 关于映像配置

本指南假定你对存储库中 GitHub 存储的 Docker 映像有完整的定义。 例如，存储库必须包含一个 Dockerfile，以及执行 Docker 构建以创建映像所需的任何其他文件。

可以使用预定义的注释键向容器映像添加元数据，包括说明、许可证和源存储库。 有关详细信息，请参阅 [使用容器注册表](/zh/enterprise-server@3.22/packages/working-with-a-github-packages-registry/working-with-the-container-registry#labelling-container-images)。

在本指南中，我们将使用 Docker `build-push-action` 操作来构建 Docker 映像并将其推送到一个或多个 Docker 注册表。 有关详细信息，请参阅 [`build-push-action`](https://github.com/marketplace/actions/build-and-push-docker-images)。

> \[!NOTE]
> 在 GitHub Actions 上的 GitHub Enterprise Server 可能对 GitHub.com 或 GitHub Marketplace 上的操作具有有限的访问权限。 有关详细信息，请参阅 [从 GitHub.com 管理对操作的访问](/zh/enterprise-server@3.22/admin/managing-github-actions-for-your-enterprise/managing-access-to-actions-from-githubcom) 并联系 GitHub Enterprise 站点管理员。

## 将映像发布到Docker Hub

> \[!NOTE]
> Docker Hub 通常会对推送和拉取操作设置速率限制，这将影响自托管运行程序上的作业。 不过，根据 GitHub 和 Docker 之间的协议，GitHub 托管的运行程序不受这些限制的约束。

每次在GitHub上创建新版本发布时，都可以触发工作流来发布镜像。 以下示例中的工作流在 `release` 事件以 `published` 活动类型触发时运行。

在下面的示例工作流中，我们使用 Docker `login-action` 和 `build-push-action` 操作生成 Docker 映像，如果生成成功，请将生成的映像推送到Docker Hub。

若要推送到Docker Hub，需要创建Docker Hub帐户，并创建Docker Hub存储库。 有关详细信息，请参阅 Docker 文档中的 [将 Docker 容器映像推送到 Docker Hub](https://docs.docker.com/docker-hub/quickstart/#step-3-build-and-push-an-image-to-docker-hub)。

Docker Hub所需的 `login-action` 选项包括：

* `username` 和 `password`：这是Docker Hub用户名和密码。 建议将Docker Hub用户名和密码存储为机密，以便不会在工作流文件中公开它们。 有关详细信息，请参阅“[在 GitHub Actions 中使用机密](/zh/enterprise-server@3.22/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets)”。

Docker Hub所需的 `metadata-action` 选项为：

* `images`：要生成/推送到Docker Hub的 Docker 映像的命名空间和名称。

Docker Hub所需的 `build-push-action` 选项包括：

* `tags`：你的新映像的标签，格式为 `DOCKER-HUB-NAMESPACE/DOCKER-HUB-REPOSITORY:VERSION`。 您可以如下所示设置单个标记，或在列表中指定多个标记。
* `push`：如果设置为 `true`，则映像将推送到注册表（如果成功构建）。

```yaml copy
# 此工作流使用未经 GitHub 认证的操作。
# 它们由第三方提供，并受
# 单独的服务条款、隐私政策和支持
# 文档。

# GitHub 建议将操作固定到提交 SHA。
# 若要获取较新版本，需要更新 SHA。
# 还可以引用标记或分支，但该操作可能会更改而不发出警告。

name: Publish Docker image

on:
  release:
    types: [published]

jobs:
  push_to_registry:
    name: Push Docker image to Docker Hub
    runs-on: [self-hosted]
    permissions:
      packages: write
      contents: read
      
      
    steps:
      - name: Check out the repo
        uses: actions/checkout@v6

      - name: Log in to Docker Hub
        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
        with:
          images: my-docker-hub-namespace/my-docker-hub-repository

      - name: Build and push Docker image
        id: push
        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

```

上述工作流检出GitHub 存储库，使用 `login-action` 登录到注册表，然后使用 `build-push-action` 动作：基于您的存储库的`Dockerfile` 构建Docker镜像；将镜像推送到 Docker Hub，并将标签应用于镜像。

## 将图像发布到 GitHub Packages

> \[!NOTE] Container registry 的 公开预览 目前为GitHub Enterprise Server，可能会有改动。

必须启用 GitHub Packages 和子域隔离才能使用 Container registry。 有关详细信息，请参阅“[使用容器注册表](/zh/enterprise-server@3.22/packages/working-with-a-github-packages-registry/working-with-the-container-registry)”。

每次在GitHub上创建新版本发布时，都可以触发工作流来发布镜像。 以下示例中的工作流在将更改被推送到 `release` 分支时运行。

在下面的示例工作流中，我们使用 Docker `login-action``build-push-action`操作生成 Docker 映像，如果生成成功，请将生成映像推送到。GitHub Packages

`login-action`所需的GitHub Packages选项包括：

* `registry`：必须设置为 `containers.HOSTNAME`.
* `username`：可以使用 `${{ github.actor }}` 上下文自动使用触发工作流运行的用户的用户名。 有关详细信息，请参阅“[上下文参考](/zh/enterprise-server@3.22/actions/reference/workflows-and-actions/contexts#github-context)”。
* `password`：可以使用自动生成 `GITHUB_TOKEN` 的密码机密。 有关详细信息，请参阅“[在工作流中使用 GITHUB\_TOKEN 进行身份验证](/zh/enterprise-server@3.22/actions/tutorials/authenticate-with-github_token)”。

`build-push-action`所需的GitHub Packages选项包括：

* `push`：如果设置为 `true`，并且生成成功，则将映像推送到注册表。
* `tags`：必须采用格式 `containers.HOSTNAME/OWNER/REPOSITORY/IMAGE_NAME:VERSION` 设置。

  例如，对于一个命名为`octo-image`的映像，存储在GitHub Enterprise Server，路径为`https://HOSTNAME/octo-org/octo-repo`，该`tags`选项应设置为`containers.HOSTNAME/octo-org/octo-repo/octo-image:latest`。 可以按如下所示设置单个标记，或在列表中指定多个标记。

> \[!NOTE]
>
> * 此工作流使用未通过 GitHub 认证的操作。 这些操作由第三方提供，并受单独的服务条款、隐私政策和支持文档的管辖。
> * GitHub 建议将操作固定到提交 SHA。 若要获取较新版本，需要更新 SHA。 还可以引用标记或分支，但该操作可能会更改而不发出警告。

```yaml annotate copy
#
name: Create and publish a Docker image

# Configures this workflow to run every time a change is pushed to the branch called `release`.
on:
  push:
    branches: ['release']

# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
  REGISTRY: containers.HOSTNAME
  IMAGE_NAME: ${{ github.repository }}

# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
jobs:
  build-and-push-image:
    runs-on: [self-hosted]
    # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
    permissions:
      contents: read
      packages: write
      
      
      #
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
      # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
      - name: Log in to the Container registry
        uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
      # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage) in the README of the `docker/build-push-action` repository.
      # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
      - name: Build and push Docker image
        id: push
        uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
      
```

上述工作流程通过推送到“发行版”分支触发。 它签出GitHub存储库，并使用 `login-action` 登录到 Container registry。 然后，它将提取 Docker 映像的标签和标记。 最后，它使用 `build-push-action` 操作生成映像并将其发布到 Container registry。

## 将图像发布到 Docker Hub 和 GitHub Packages

> \[!NOTE] Container registry 的 公开预览 目前为GitHub Enterprise Server，可能会有改动。

必须启用 GitHub Packages 和子域隔离才能使用 Container registry。 有关详细信息，请参阅“[使用容器注册表](/zh/enterprise-server@3.22/packages/working-with-a-github-packages-registry/working-with-the-container-registry)”。

在单个工作流中，你可以通过对每个注册表使用 `login-action` 和 `build-push-action` 操作将 Docker 映像发布到多个注册表。

以下示例工作流使用前面各节（[发布映像到 Docker Hub](#publishing-images-to-docker-hub) 和 [将映像发布到 GitHub Packages](#publishing-images-to-github-packages)） 中的步骤来创建推送到这两个注册表的单个工作流。

```yaml copy
# 此工作流使用未经 GitHub 认证的操作。
# 它们由第三方提供，并受
# 单独的服务条款、隐私政策和支持
# 文档。

# GitHub 建议将操作固定到提交 SHA。
# 若要获取较新版本，需要更新 SHA。
# 还可以引用标记或分支，但该操作可能会更改而不发出警告。

name: Publish Docker image

on:
  release:
    types: [published]

jobs:
  push_to_registries:
    name: Push Docker image to multiple registries
    runs-on: [self-hosted]
    permissions:
      packages: write
      contents: read
    steps:
      - name: Check out the repo
        uses: actions/checkout@v6

      - name: Log in to Docker Hub
        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Log in to the Container registry
        uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
        with:
          registry: containers.HOSTNAME
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
        with:
          images: |
            my-docker-hub-namespace/my-docker-hub-repository
            containers.HOSTNAME/${{ github.repository }}

      - name: Build and push Docker images
        id: push
        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
```

上述工作流签出 GitHub 存储库，使用 `login-action` 两次登录到两个注册表，并使用 `metadata-action` 操作生成标记和标签。
然后，`build-push-action` 操作生成 Docker 映像并将 Docker 映像推送到 Docker Hub 和 Container registry。

## 动手练习

练习发布 Docker 映像，使用[发布 Docker 映像](https://github.com/skills/publish-docker-images)GitHub Skills这个练习。

在本练习中，你将了解如何：

* 请使用 GitHub Packages 认证到 `GITHUB_TOKEN`.
* 生成容器映像并将其发布到 Container registry （`ghcr.io`）。
* 使用官方 Docker 操作，例如 `docker/login-action`， `docker/build-push-action`和 `docker/setup-buildx-action`。
* 根据分支、拉取请求和发布自动生成 `docker/metadata-action` 标记。
* 使用适当的容器版本控制创建功能、拉取请求和发布。