{"meta":{"title":"发布 Docker 映像","intro":"本教程介绍如何将 Docker 映像发布到注册表，例如Docker Hub或 GitHub Packages，作为持续集成（CI）工作流的一部分。","product":"GitHub Actions","breadcrumbs":[{"href":"/zh/actions","title":"GitHub Actions"},{"href":"/zh/actions/tutorials","title":"教程"},{"href":"/zh/actions/tutorials/publish-packages","title":"发布软件包"},{"href":"/zh/actions/tutorials/publish-packages/publish-docker-images","title":"发布 Docker 映像"}],"documentType":"article"},"body":"# 发布 Docker 映像\n\n本教程介绍如何将 Docker 映像发布到注册表，例如Docker Hub或 GitHub Packages，作为持续集成（CI）工作流的一部分。\n\n## 简介\n\n本指南介绍如何创建执行 Docker 生成的工作流，然后将 Docker 映像发布到 Docker Hub 或 GitHub Packages。 通过单个工作流程，您可以将映像发布到单一注册表或多个注册表。\n\n> \\[!NOTE]\n> 如果要推送到另一个第三方 Docker 注册表，[发布映像到 GitHub Packages](#publishing-images-to-github-packages) 部分中的示例可以用作很好的模板。\n\n## 先决条件\n\n建议基本了解工作流程配置选项和如何创建工作流程文件。 有关详细信息，请参阅“[撰写工作流程](/zh/actions/how-tos/write-workflows)”。\n\n您可能还发现基本了解以下内容是有帮助的：\n\n* [在 GitHub Actions 中使用机密](/zh/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets)\n* [在工作流中使用 GITHUB\\_TOKEN 进行身份验证](/zh/actions/tutorials/authenticate-with-github_token)\n* [使用容器注册表](/zh/packages/working-with-a-github-packages-registry/working-with-the-container-registry)\n\n## 关于映像配置\n\n本指南假定你对存储库中 GitHub 存储的 Docker 映像有完整的定义。 例如，存储库必须包含一个 Dockerfile，以及执行 Docker 构建以创建映像所需的任何其他文件。\n\n可以使用预定义的注释键向容器映像添加元数据，包括说明、许可证和源存储库。 有关详细信息，请参阅 [使用容器注册表](/zh/packages/working-with-a-github-packages-registry/working-with-the-container-registry#labelling-container-images)。\n\n在本指南中，我们将使用 Docker `build-push-action` 操作来构建 Docker 映像并将其推送到一个或多个 Docker 注册表。 有关详细信息，请参阅 [`build-push-action`](https://github.com/marketplace/actions/build-and-push-docker-images)。\n\n## 将映像发布到Docker Hub\n\n> \\[!NOTE]\n> Docker Hub 通常会对推送和拉取操作设置速率限制，这将影响自托管运行程序上的作业。 不过，根据 GitHub 和 Docker 之间的协议，GitHub 托管的运行程序不受这些限制的约束。\n\n每次在GitHub上创建新版本发布时，都可以触发工作流来发布镜像。 以下示例中的工作流在 `release` 事件以 `published` 活动类型触发时运行。\n\n在下面的示例工作流中，我们使用 Docker `login-action` 和 `build-push-action` 操作生成 Docker 映像，如果生成成功，请将生成的映像推送到Docker Hub。\n\n若要推送到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)。\n\nDocker Hub所需的 `login-action` 选项包括：\n\n* `username` 和 `password`：这是Docker Hub用户名和密码。 建议将Docker Hub用户名和密码存储为机密，以便不会在工作流文件中公开它们。 有关详细信息，请参阅“[在 GitHub Actions 中使用机密](/zh/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets)”。\n\nDocker Hub所需的 `metadata-action` 选项为：\n\n* `images`：要生成/推送到Docker Hub的 Docker 映像的命名空间和名称。\n\nDocker Hub所需的 `build-push-action` 选项包括：\n\n* `tags`：你的新映像的标签，格式为 `DOCKER-HUB-NAMESPACE/DOCKER-HUB-REPOSITORY:VERSION`。 您可以如下所示设置单个标记，或在列表中指定多个标记。\n* `push`：如果设置为 `true`，则映像将推送到注册表（如果成功构建）。\n\n```yaml copy\n# 此工作流使用未经 GitHub 认证的操作。\n# 它们由第三方提供，并受\n# 单独的服务条款、隐私政策和支持\n# 文档。\n\n# GitHub 建议将操作固定到提交 SHA。\n# 若要获取较新版本，需要更新 SHA。\n# 还可以引用标记或分支，但该操作可能会更改而不发出警告。\n\nname: Publish Docker image\n\non:\n  release:\n    types: [published]\n\njobs:\n  push_to_registry:\n    name: Push Docker image to Docker Hub\n    runs-on: ubuntu-latest\n    permissions:\n      packages: write\n      contents: read\n      attestations: write\n      id-token: write\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v6\n\n      - name: Log in to Docker Hub\n        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_PASSWORD }}\n\n      - name: Extract metadata (tags, labels) for Docker\n        id: meta\n        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7\n        with:\n          images: my-docker-hub-namespace/my-docker-hub-repository\n\n      - name: Build and push Docker image\n        id: push\n        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671\n        with:\n          context: .\n          file: ./Dockerfile\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}\n\n      - name: Generate artifact attestation\n        uses: actions/attest@v4\n        with:\n          subject-name: index.docker.io/my-docker-hub-namespace/my-docker-hub-repository\n          subject-digest: ${{ steps.push.outputs.digest }}\n          push-to-registry: true\n```\n\n上述工作流检出GitHub 存储库，使用 `login-action` 登录到注册表，然后使用 `build-push-action` 动作：基于您的存储库的`Dockerfile` 构建Docker镜像；将镜像推送到 Docker Hub，并将标签应用于镜像。\n\n在最后一步，会为该映像生成制品证明，从而提升供应链安全性。 有关详细信息，请参阅“[使用项目证明确立生成的来源](/zh/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations)”。\n\n## 将图像发布到 GitHub Packages\n\n每次在GitHub上创建新版本发布时，都可以触发工作流来发布镜像。 以下示例中的工作流在将更改被推送到 `release` 分支时运行。\n\n在下面的示例工作流中，我们使用 Docker `login-action``metadata-action`和`build-push-action`操作生成 Docker 映像，如果生成成功，请将生成映像推送到。GitHub Packages\n\n`login-action`所需的GitHub Packages选项包括：\n\n* `registry`：必须设置为 `ghcr.io`.\n* `username`：可以使用 `${{ github.actor }}` 上下文自动使用触发工作流运行的用户的用户名。 有关详细信息，请参阅“[上下文参考](/zh/actions/reference/workflows-and-actions/contexts#github-context)”。\n* `password`：可以使用自动生成 `GITHUB_TOKEN` 的密码机密。 有关详细信息，请参阅“[在工作流中使用 GITHUB\\_TOKEN 进行身份验证](/zh/actions/tutorials/authenticate-with-github_token)”。\n\n所需`metadata-action`GitHub Packages选项为：\n\n* `images`：正在构建的 Docker 映像的命名空间和名称。\n\n`build-push-action`所需的GitHub Packages选项包括：\n\n* `context`：将生成上下文定义为位于指定路径中的文件集。\n* `push`：如果设置为 `true`，并且生成成功，则将映像推送到注册表。\n* `tags` 和 `labels`：这些由 `metadata-action` 的输出填充。\n\n> \\[!NOTE]\n>\n> * 此工作流使用未通过 GitHub 认证的操作。 这些操作由第三方提供，并受单独的服务条款、隐私政策和支持文档的管辖。\n> * GitHub 建议将操作固定到提交 SHA。 若要获取较新版本，需要更新 SHA。 还可以引用标记或分支，但该操作可能会更改而不发出警告。\n\n```yaml annotate copy\n#\nname: Create and publish a Docker image\n\n# Configures this workflow to run every time a change is pushed to the branch called `release`.\non:\n  push:\n    branches: ['release']\n\n# 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.\nenv:\n  REGISTRY: ghcr.io\n  IMAGE_NAME: ${{ github.repository }}\n\n# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.\njobs:\n  build-and-push-image:\n    runs-on: ubuntu-latest\n    # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.\n    permissions:\n      contents: read\n      packages: write\n      attestations: write\n      id-token: write\n      #\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n      # 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.\n      - name: Log in to the Container registry\n        uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n        with:\n          registry: ${{ env.REGISTRY }}\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n      # 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.\n      - name: Extract metadata (tags, labels) for Docker\n        id: meta\n        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7\n        with:\n          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\n      # 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.\n      # 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.\n      # It uses the `tags` and `labels` parameters to tag and label the image with the output from the \"meta\" step.\n      - name: Build and push Docker image\n        id: push\n        uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4\n        with:\n          context: .\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}\n      \n      # This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see [Using artifact attestations to establish provenance for builds](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds).\n      - name: Generate artifact attestation\n        uses: actions/attest@v4\n        with:\n          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}\n          subject-digest: ${{ steps.push.outputs.digest }}\n          push-to-registry: true\n      \n```\n\n上述工作流程通过推送到“发行版”分支触发。 它签出GitHub存储库，并使用 `login-action` 登录到 Container registry。 然后，它将提取 Docker 映像的标签和标记。 最后，它使用 `build-push-action` 操作生成映像并将其发布到 Container registry。\n\n## 将图像发布到 Docker Hub 和 GitHub Packages\n\n在单个工作流中，你可以通过对每个注册表使用 `login-action` 和 `build-push-action` 操作将 Docker 映像发布到多个注册表。\n\n以下示例工作流使用前面各节（[发布映像到 Docker Hub](#publishing-images-to-docker-hub) 和 [将映像发布到 GitHub Packages](#publishing-images-to-github-packages)） 中的步骤来创建推送到这两个注册表的单个工作流。\n\n```yaml copy\n# 此工作流使用未经 GitHub 认证的操作。\n# 它们由第三方提供，并受\n# 单独的服务条款、隐私政策和支持\n# 文档。\n\n# GitHub 建议将操作固定到提交 SHA。\n# 若要获取较新版本，需要更新 SHA。\n# 还可以引用标记或分支，但该操作可能会更改而不发出警告。\n\nname: Publish Docker image\n\non:\n  release:\n    types: [published]\n\njobs:\n  push_to_registries:\n    name: Push Docker image to multiple registries\n    runs-on: ubuntu-latest\n    permissions:\n      packages: write\n      contents: read\n    steps:\n      - name: Check out the repo\n        uses: actions/checkout@v6\n\n      - name: Log in to Docker Hub\n        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a\n        with:\n          username: ${{ secrets.DOCKER_USERNAME }}\n          password: ${{ secrets.DOCKER_PASSWORD }}\n\n      - name: Log in to the Container registry\n        uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Extract metadata (tags, labels) for Docker\n        id: meta\n        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7\n        with:\n          images: |\n            my-docker-hub-namespace/my-docker-hub-repository\n            ghcr.io/${{ github.repository }}\n\n      - name: Build and push Docker images\n        id: push\n        uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671\n        with:\n          context: .\n          push: true\n          tags: ${{ steps.meta.outputs.tags }}\n          labels: ${{ steps.meta.outputs.labels }}\n```\n\n上述工作流签出 GitHub 存储库，使用 `login-action` 两次登录到两个注册表，并使用 `metadata-action` 操作生成标记和标签。\n然后，`build-push-action` 操作生成 Docker 映像并将 Docker 映像推送到 Docker Hub 和 Container registry。\n\n> \\[!NOTE]\n> 推送到多个注册表时：\n>\n> * 映像摘要在注册表之间可能有所不同，使证明验证变得困难。\n> * 要保持一致的摘要并允许单个证明验证所有副本，请先推送到一个注册表，然后使用 [`crane copy`](https://github.com/google/go-containerregistry/blob/main/cmd/crane/doc/crane_copy.md) 之类的工具将映像复制到其他位置。\n> * 如果选择单独生成并推送到每个注册表，则必须为每个注册表生成不同的证明，以确保项目保持可验证状态。\n\n## 动手练习\n\n练习发布 Docker 映像，使用[发布 Docker 映像](https://github.com/skills/publish-docker-images)GitHub Skills这个练习。\n\n在本练习中，你将了解如何：\n\n* 请使用 GitHub Packages 认证到 `GITHUB_TOKEN`.\n* 生成容器映像并将其发布到 Container registry （`ghcr.io`）。\n* 使用官方 Docker 操作，例如 `docker/login-action`， `docker/build-push-action`和 `docker/setup-buildx-action`。\n* 根据分支、拉取请求和发布自动生成 `docker/metadata-action` 标记。\n* 使用适当的容器版本控制创建功能、拉取请求和发布。"}