跳至主要内容

使用 GitHub 操作发布和安装包

您可以在 GitHub 操作中配置工作流,以从 GitHub 包自动发布或安装包。

谁可以使用此功能?

GitHub 包适用于 GitHub 免费版、GitHub Pro 版、GitHub 免费版(适用于组织)、GitHub Team、GitHub Enterprise Cloud 和 GitHub Enterprise Server 3.0 或更高版本。


GitHub 包不适用于使用旧版按存储库付费计划的帐户所拥有的私有存储库。此外,使用旧版按存储库付费计划的帐户无法访问支持细粒度权限的注册表,因为这些帐户按存储库计费。有关支持细粒度权限的注册表列表,请参阅“关于 GitHub 包的权限”。有关更多信息,请参阅“GitHub 的计划”。

关于 GitHub 操作中的 GitHub 包

GitHub 操作可帮助您在存储代码并协作处理请求和问题同一位置自动执行软件开发工作流。您可以编写称为操作的单个任务,并将其组合起来创建自定义工作流。使用 GitHub 操作,您可以在存储库中直接构建端到端的持续集成 (CI) 和持续部署 (CD) 功能。有关更多信息,请参阅“了解 GitHub 操作”。

您可以通过在工作流中发布或安装包来扩展存储库的 CI 和 CD 功能。

使用细粒度权限对包注册进行身份验证

某些 GitHub 包注册支持细粒度权限。这意味着你可以选择允许将包限定为用户或组织,或将其链接到存储库。有关支持细粒度权限的注册列表,请参阅“关于 GitHub 包的权限”。

对于支持细粒度权限的注册,如果你的 GitHub Actions 工作流使用个人访问令牌对注册进行身份验证,我们强烈建议你更新工作流以使用 GITHUB_TOKEN。有关更新使用个人访问令牌对注册进行身份验证的工作流的指南,请参阅“使用 GitHub Actions 发布和安装包”。

注意:GitHub Actions 工作流使用 REST API 删除和恢复包的能力目前处于公开测试阶段,可能会发生变化。

如果令牌对包具有 admin 权限,则可以在 GitHub Actions 工作流中使用 GITHUB_TOKEN 使用 REST API 删除或恢复包。使用工作流发布包的存储库以及你已明确连接到包的存储库将自动获得对存储库中包的 admin 权限。

有关 GITHUB_TOKEN 的更多信息,请参阅“自动令牌身份验证”。有关在操作中使用注册时的最佳做法的更多信息,请参阅“GitHub Actions 的安全强化”。

使用存储库范围权限对包注册进行身份验证

某些 GitHub 包注册仅支持存储库范围权限,不支持细粒度权限。有关这些注册的列表,请参阅“关于 GitHub 包的权限”。

如果您希望工作流访问不支持细粒度权限的 GitHub Packages 注册表,那么我们建议使用 GitHub 在您启用 GitHub Actions 时为您的存储库自动创建的 `GITHUB_TOKEN`。您应该在工作流文件中设置此访问令牌的权限,以授予对 `contents` 范围的读取访问权限和对 `packages` 范围的写入访问权限。对于 fork,`GITHUB_TOKEN` 被授予对父存储库的读取访问权限。有关详细信息,请参阅“自动令牌身份验证”。

您可以使用 `${{ secrets.GITHUB_TOKEN }}` 上下文在工作流文件中引用 `GITHUB_TOKEN`。有关详细信息,请参阅“自动令牌身份验证”。

关于权限和包访问权限

面向用户或组织的包

支持细粒度权限的注册表允许用户在组织级别创建和管理包作为独立资源。包可以面向组织或个人帐户,您可以自定义对每个包的访问权限,与存储库权限分开。

所有访问支持细粒度权限的注册表的工作流都应使用 `GITHUB_TOKEN`,而不是个人访问令牌。有关安全最佳实践的详细信息,请参阅“GitHub Actions 的安全强化”。

面向存储库的包

当您启用 GitHub Actions 时,GitHub 会在您的存储库上安装一个 GitHub 应用。`GITHUB_TOKEN` 密钥是 GitHub 应用安装访问令牌。您可以使用安装访问令牌代表安装在您的存储库上的 GitHub 应用进行身份验证。令牌的权限仅限于包含您的工作流的存储库。有关详细信息,请参阅“自动令牌身份验证”。

GitHub Packages 允许您通过 GitHub Actions 工作流可用的 `GITHUB_TOKEN` 推送和拉取包。

通过工作流修改的包的默认权限和访问设置

对于支持细粒度权限的注册表中的包,当您通过工作流创建、安装、修改或删除包时,会使用一些默认权限和访问设置来确保管理员有权访问工作流。您还可以调整这些访问设置。有关支持细粒度权限的注册表列表,请参阅“GitHub Packages 的权限”。

例如,如果工作流默认情况下使用 GITHUB_TOKEN 创建包,则

  • 包将继承运行工作流的存储库的可见性和权限模型。
  • 运行工作流的存储库管理员在包创建后将成为该包的管理员。

以下是如何为管理包的工作流设置默认权限的更多示例。

GitHub Actions 工作流任务默认权限和访问权限
下载现有- 如果包是公开的,则在任何存储库中运行的任何工作流都可以下载该包。
- 如果包是内部的,则在企业帐户拥有的任何存储库中运行的所有工作流都可以下载该包。对于企业拥有的组织,您可以读取企业中的任何存储库
- 如果包是私有的,则只有在被授予该包读取权限的存储库中运行的工作流才能下载该包。如果您授予公共存储库访问私有包的权限,则该存储库的分支可能能够访问私有包。
将新版本上传到现有包- 如果包是私有的、内部的或公开的,则只有在被授予该包写入权限的存储库中运行的工作流才能将新版本上传到该包。
删除包或包的版本- 如果包是私有的、内部的或公开的,则只有在被授予管理员权限的存储库中运行的工作流才能删除包的现有版本。

您还可以更细粒度地调整对包的访问权限或调整某些默认权限行为。有关更多信息,请参阅“配置包的访问控制和可见性”。

使用操作发布包

您可以使用 GitHub Actions 在持续集成 (CI) 流程中自动发布包。这种持续部署 (CD) 方法允许您在代码符合质量标准时自动创建新包版本。例如,您可以创建一个工作流,在开发人员将代码推送到特定分支时运行 CI 测试。如果测试通过,工作流可以将新包版本发布到 GitHub Packages。

配置步骤因软件包客户端而异。有关为 GitHub Actions 配置工作流的一般信息,请参阅“使用工作流”。

以下示例演示如何使用 GitHub Actions 构建应用,然后自动创建 Docker 镜像并将其发布到 GitHub Packages。相关设置在代码中进行了说明。有关工作流中每个元素的完整详细信息,请参阅“GitHub Actions 的工作流语法”。

在存储库中创建新的工作流文件(如 .github/workflows/deploy-image.yml),并添加以下 YAML。

注释

  • 此工作流使用未经 GitHub 认证的操作。它们由第三方提供,并受单独的服务条款、隐私政策和支持文档的约束。
  • GitHub 建议将操作固定到提交 SHA。要获取较新版本,您需要更新 SHA。您还可以引用标签或分支,但操作可能会在不发出警告的情况下更改。
YAML
name: Create and publish a Docker image
on:
  push:
    branches: ['release']

将此工作流配置为在每次将更改推送到名为 release 的分支时运行。

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

为工作流定义两个自定义环境变量。这些变量用于容器注册表域和此工作流构建的 Docker 镜像的名称。

jobs:
  build-and-push-image:
    runs-on: ubuntu-latest

此工作流中有一个作业。它配置为在最新版本的 Ubuntu 上运行。

    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write

设置授予此作业中的操作的 GITHUB_TOKEN 的权限。

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Log in to the Container registry
        uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

使用 docker/login-action 操作使用将发布软件包的帐户和密码登录到容器注册表注册表。发布后,软件包的范围将限定为此处定义的帐户。

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

此步骤使用 docker/metadata-action 提取将应用于指定镜像的标签和标记。id“meta”允许在此步骤的后续步骤中引用此步骤的输出。images 值为标签和标记提供基本名称。

      - 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 }}

此步骤使用 docker/build-push-action 操作基于存储库的 Dockerfile 构建镜像。如果构建成功,它会将镜像推送到 GitHub Packages。它使用 context 参数将构建的上下文定义为位于指定路径中的文件集合。有关更多信息,请参阅 docker/build-push-action 存储库的自述文件中的“用法”。它使用 tagslabels 参数使用“meta”步骤的输出标记和标记镜像。

      * name: Generate artifact attestation
        uses: actions/attest-build-provenance@v1
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
          subject-digest: ${{ steps.push.outputs.digest }}
          push-to-registry: true

此步骤将为镜像生成工件证明,该证明是关于镜像构建位置和方式的不可伪造的声明。它提高了使用该镜像的人员的供应链安全性。有关更多信息,请参阅“使用工件证明来建立构建的来源”。

#
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: ghcr.io
  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: ubuntu-latest
    # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write
      # 
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      # 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 }}
      
      # 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 "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)." 
      * name: Generate artifact attestation
        uses: actions/attest-build-provenance@v1
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
          subject-digest: ${{ steps.push.outputs.digest }}
          push-to-registry: true
      

每次将更改推送到存储库中名为 release 的分支时,此新工作流都会自动运行。您可以在“操作”选项卡中查看进度。

工作流完成后几分钟内,新包将在您的存储库中可见。要查找可用的包,请参阅“查看包”。

使用操作安装包

您可以使用 GitHub Actions 在 CI 流程中安装包。例如,您可以配置工作流,以便在开发人员将代码推送到请求合并时,工作流通过下载和安装 GitHub Packages 托管的包来解决依赖项。然后,工作流可以运行需要这些依赖项的 CI 测试。

当您使用 GITHUB_TOKEN 时,通过 GitHub Actions 安装 GitHub Packages 托管的包需要最少的配置或其他身份验证。当操作安装包时,数据传输也是免费的。有关更多信息,请参阅“关于 GitHub Packages 的计费”。

配置步骤因软件包客户端而异。有关为 GitHub Actions 配置工作流的一般信息,请参阅“使用工作流”。

升级使用个人访问令牌访问注册表的工作流

GitHub Packages 支持 GITHUB_TOKEN,以便在您的工作流中进行简单而安全的身份验证。如果您使用的是支持精细权限的注册表,并且您的工作流使用个人访问令牌对注册表进行身份验证,那么我们强烈建议您更新工作流以使用 GITHUB_TOKEN

有关 GITHUB_TOKEN 的更多信息,请参阅“自动令牌身份验证”。

使用 GITHUB_TOKEN(而不是具有 repo 范围的个人访问令牌(经典)),可以提高存储库的安全性,因为您无需使用长期个人访问令牌,而该令牌会提供对运行工作流的存储库的不必要的访问权限。有关安全最佳实践的更多信息,请参阅“GitHub Actions 的安全强化”。

  1. 导航到程序包着陆页。

  2. 为了确保程序包有权访问工作流,您必须将存储工作流的存储库添加到程序包。在“管理操作访问权限”下,单击添加存储库并搜索您要添加的存储库。

    Screenshot of the "Manage Actions access" section of the package settings page. The "Add repository" button is highlighted with an orange outline.

    注意:通过使用程序包设置中的“管理操作访问权限”下的添加存储库按钮将存储库添加到程序包与将程序包连接到存储库不同。有关更多信息,请参阅“配置程序包的访问控制和可见性”和“将存储库连接到程序包”。

  3. 您还可以使用角色下拉菜单选择您希望存储库对程序包拥有的默认访问级别。

  4. 打开工作流文件。在您登录注册表的行上,用 ${{ secrets.GITHUB_TOKEN }} 替换您的个人访问令牌。

例如,此工作流将 Docker 映像发布到容器注册表,并使用 ${{ secrets.GITHUB_TOKEN }} 进行身份验证。有关更多信息,请参阅 Docker 文档中的“设置自动构建”。

YAML
name: Demo Push
on:
  push:
    branches:
      - main
      - seed
    tags:
      - v*
  pull_request:

此工作流在发生以下任何情况时运行

  • 推送至名为 mainseed 的分支
  • 创建以“v”开头的标签
  • 创建或更新拉取请求
env:
  IMAGE_NAME: ghtoken_product_demo

这会创建一个名为 IMAGE_NAME 的环境变量,其值为 ghtoken_product_demo

jobs:
  push:
    runs-on: ubuntu-latest
    permissions:
      packages: write
      contents: read

这会将映像推送到 GitHub 程序包。

    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"
      - name: Log in to registry
        run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
      - name: Push image
        run: |
          IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
          IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')

这会将所有大写字符转换为小写。

          VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')

这会从版本中删除 git ref 前缀。

          [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')

这会从标签名称中删除“v”前缀。

          [ "$VERSION" == "main" ] && VERSION=latest
          echo IMAGE_ID=$IMAGE_ID
          echo VERSION=$VERSION
          docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
          docker push $IMAGE_ID:$VERSION

这会使用 Docker latest 标签约定。

#
name: Demo Push

# This workflow runs when any of the following occur:
# - A push is made to a branch called `main` or `seed`
# - A tag starting with "v" is created
# - A pull request is created or updated
on:
  push:
    branches:
      - main
      - seed
    tags:
      - v*
  pull_request:
  # This creates an environment variable called `IMAGE_NAME ` with the value `ghtoken_product_demo`.
env:
  IMAGE_NAME: ghtoken_product_demo
#
jobs:
  # This pushes the image to GitHub Packages.
  push:
    runs-on: ubuntu-latest
    permissions:
      packages: write
      contents: read
      #
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"

      - name: Log in to registry
        run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
        #
      - name: Push image
        run: |
          IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME

          # This changes all uppercase characters to lowercase.
          IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
          # This strips the git ref prefix from the version.
          VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
          # This strips the "v" prefix from the tag name.
          [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
          # This uses the Docker `latest` tag convention.
          [ "$VERSION" == "main" ] && VERSION=latest
          echo IMAGE_ID=$IMAGE_ID
          echo VERSION=$VERSION
          docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
          docker push $IMAGE_ID:$VERSION