跳至主要内容

使用 GitHub Actions 发布和安装包

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

关于使用 GitHub Actions 的 GitHub Packages

GitHub Actions 帮助您在存放代码并在拉取请求和议题上协作的同一位置自动化软件开发工作流。您可以编写称为 actions 的单个任务,并将它们组合成自定义工作流。使用 GitHub Actions,您可以在仓库中直接构建端到端的持续集成(CI)和持续部署(CD)功能。欲了解更多信息,请参阅 编写工作流

您可以通过在工作流中发布或安装软件包,扩展仓库的 CI 和 CD 功能。

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

某些 GitHub Packages 注册表支持细粒度权限。这意味着您可以选择将软件包限定在用户或组织范围,或关联到特定仓库。有关支持细粒度权限的注册表列表,请参阅 关于 GitHub Packages 的权限

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

注意

GitHub Actions 工作流使用 REST API 删除和恢复软件包的功能目前处于公开预览阶段,可能会有变更。

您可以在 GitHub Actions 工作流中使用 GITHUB_TOKEN 删除或恢复软件包(通过 REST API),前提是该令牌对软件包拥有 admin 权限。使用工作流发布软件包的仓库,以及您已显式连接到软件包的仓库,都会自动获得该仓库中软件包的 admin 权限。

有关 GITHUB_TOKEN 的更多信息,请参阅 在工作流中使用 GITHUB_TOKEN 进行身份验证。有关在 Actions 中使用注册表的最佳实践,请参阅 安全使用参考

使用仓库范围权限对软件包注册表进行身份验证

部分 GitHub Packages 注册表仅支持仓库范围的权限,不支持细粒度权限。有关这些注册表的列表,请参阅 关于 GitHub Packages 的权限

如果您希望工作流访问不支持细粒度权限的 GitHub Packages 注册表,我们建议使用 GitHub 在您启用 GitHub Actions 时为仓库自动创建的 GITHUB_TOKEN。您应在工作流文件中为此访问令牌设置权限:授予 contents 范围的读取权限和 packages 范围的写入权限。对于分叉仓库,GITHUB_TOKEN 仅拥有对父仓库的读取权限。欲了解更多信息,请参阅 在工作流中使用 GITHUB_TOKEN 进行身份验证

您可以在工作流文件中使用 ${{ secrets.GITHUB_TOKEN }} 上下文来引用 GITHUB_TOKEN。欲了解更多信息,请参阅 在工作流中使用 GITHUB_TOKEN 进行身份验证

关于权限和软件包访问

针对用户或组织范围的包

支持细粒度权限的注册表允许用户在组织层面将软件包创建为独立资源并进行管理。软件包可以限定在组织或个人账户,您可以针对每个软件包单独自定义访问权限,而不受仓库权限的限制。

所有访问支持细粒度权限的注册表的工作流都应使用 GITHUB_TOKEN 而非个人访问令牌。有关安全最佳实践的更多信息,请参阅 安全使用参考

针对仓库范围的包

当您启用 GitHub Actions 时,GitHub 会在您的仓库上安装一个 GitHub App。GITHUB_TOKEN 密钥是该 GitHub App 安装的访问令牌。您可以使用此安装访问令牌代表已安装在仓库上的 GitHub App 进行身份验证。该令牌的权限仅限于包含工作流的仓库。欲了解更多信息,请参阅 在工作流中使用 GITHUB_TOKEN 进行身份验证

GitHub Packages 允许您通过 GitHub Actions 工作流中的 GITHUB_TOKEN 推送和拉取软件包。

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

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

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

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

以下是默认权限在管理软件包的工作流中如何运作的更多示例。

GitHub Actions 工作流任务默认权限和访问
下载已有的- 如果软件包是公开的,任何仓库中运行的工作流都可以下载该软件包。
- 如果软件包是内部的,则所有属于该企业账户拥有的仓库中运行的工作流都可以下载该软件包。对于企业拥有的组织,您可以读取企业中的任何仓库
- 如果软件包是私有的,仅有对该软件包拥有读取权限的仓库中运行的工作流才能下载该软件包。如果您授予公共仓库访问私有软件包的权限,该仓库的分叉可能也能访问这些私有软件包。
向已有软件包上传新版本- 如果软件包是私有、内部或公开的,只有对该软件包拥有写入权限的仓库中运行的工作流可以向软件包上传新版本。
删除软件包或软件包的版本- 如果软件包是私有、内部或公开的,只有对该仓库拥有管理员权限的工作流才能删除该软件包的现有版本。

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

使用 Action 发布软件包

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

配置步骤因软件包客户端而异。有关在 GitHub Actions 中配置工作流的一般信息,请参阅 编写工作流

以下示例演示如何使用 GitHub Actions 构建您的应用程序,然后自动创建 Docker 镜像并将其发布到 GitHub Packages。代码中解释了相关设置。有关工作流中每个元素的完整详情,请参阅 GitHub Actions 工作流语法

在您的仓库中创建一个新工作流文件(例如 .github/workflows/deploy-image.yml),并添加以下 YAML 内容。

注意

  • 此工作流使用的 actions 未经 GitHub 认证。它们由第三方提供,受其独立的服务条款、隐私政策和支持文档约束。
  • GitHub 建议将 actions 锁定到特定的提交 SHA。若需获取更新版本,必须更新 SHA。您也可以引用标签或分支,但该 action 可能在未提示的情况下发生变更。
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

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

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
      - 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 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 action 基于您仓库中的 Dockerfile 构建镜像。如果构建成功,它会将镜像推送到 GitHub Packages。它使用 context 参数将构建上下文定义为指定路径下的文件集合。更多信息请参阅 docker/build-push-action 仓库 README 中的 Usage。它使用 tagslabels 参数,以 “meta” 步骤的输出为镜像打标签和标识。

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

此步骤为镜像生成制品证明(artifact attestation),这是一份关于镜像构建位置和方式的不可伪造声明。它提升了使用该镜像的用户的供应链安全。欲了解更多信息,请参阅 使用制品证明来确立构建的来源

#
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@v5
      # 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 [Using artifact attestations to establish provenance for builds](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds).
      - name: Generate artifact attestation
        uses: actions/attest@v4
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
          subject-digest: ${{ steps.push.outputs.digest }}
          push-to-registry: true
      

此新工作流将在每次向仓库中名为 release 的分支推送更改时自动运行。您可以在 Actions 选项卡中查看进度。

工作流完成后几分钟内,新软件包将出现在您的仓库中。要查找可用的软件包,请参阅 查看软件包

使用 Action 安装软件包

您可以在 CI 流程中使用 GitHub Actions 安装软件包。例如,您可以配置工作流,使其在开发者向拉取请求推送代码时,通过下载和安装托管在 GitHub Packages 的软件包来解决依赖关系。随后,工作流可以运行需要这些依赖的 CI 测试。

通过 GitHub Actions 安装由 GitHub Packages 托管的软件包,在使用 GITHUB_TOKEN 时几乎无需额外配置或身份验证。当 action 安装软件包时,数据传输也是免费的。有关更多信息,请参阅 GitHub Packages 计费

配置步骤因软件包客户端而异。有关在 GitHub Actions 中配置工作流的一般信息,请参阅 编写工作流

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

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

有关 GITHUB_TOKEN 的更多信息,请参阅 在工作流中使用 GITHUB_TOKEN 进行身份验证

使用 GITHUB_TOKEN 而非带有 repo 范围的个人访问令牌(经典),可提升仓库安全性,因为您无需使用提供不必要访问权限的长期个人令牌。有关安全最佳实践的更多信息,请参阅 安全使用参考

  1. 前往您的软件包主页。

  2. 为确保您的软件包能够访问您的工作流,您必须将存放工作流的仓库添加到软件包中。在 “Manage Actions access”(管理 Actions 访问)下,点击 Add repository 并搜索您要添加的仓库。

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

    注意

    使用软件包设置中的 “Manage Actions access” 下的 Add Repository 按钮将仓库添加到软件包的方式,与将软件包连接到仓库不同。更多信息请参阅 配置软件包的访问控制和可见性将仓库连接到软件包

  3. 可选地,使用 Role 下拉菜单选择您希望该仓库对您的软件包拥有的默认访问级别。

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

例如,此工作流将 Docker 镜像发布到容器注册表,并使用 ${{ secrets.GITHUB_TOKEN }} 进行身份验证。更多信息请参阅 Docker 文档中的 Set up Automated Builds

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 Packages。

    steps:
      - uses: actions/checkout@v5
      - 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@v5

      - 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
© . This site is unofficial and not affiliated with GitHub, Inc.