Github Actions可复用工作流最佳实践
一 背景
在使用Github Actions作为项目CI/CD流水线时,会遇到几个项目类型相似,其CI/CD存在不少相同配置,为了保持代码整洁规范,保持CI/CD 流程的 DRY(Don`t repeat yourself),可以采用类似Jenkins/Gitlab CI模版库的思路来实现,本文利用一个golang项目CI过程实战Github Actions构建可复用工作流。
二 使用模版特点
任何方案都有特定的适用场景,需要根据自己项目实际情况来选择,以下列出使用模版工作流的特点:
2.1 优点
GitHub Actions 可以使用复用工作流(reusable workflows)来避免在不同仓库中重复编写相同的工作流。优点包括:
- 提高开发效率:复用工作流可以避免在不同仓库中编写相同的工作流,节省了编写和维护工作流的时间。
- 保持一致性:复用工作流可以确保在不同仓库中使用相同的工作流,避免了因为使用不同的工作流而导致的不一致性。
- 可维护性:复用工作流可以使得修改工作流变得更加容易,只需要修改一处就可以在多个仓库中生效。
2.2 缺点
- 可读性:复用工作流可能会变得更加复杂,需要更多的注释和文档来解释其作用。
- 限制性:复用工作流可能会限制不同仓库中工作流的灵活性和定制性,因为它们必须遵循相同的模板和规则。
- 依赖性:复用工作流可能会造成多个仓库之间的依赖性,一旦复用工作流发生问题,可能会影响到多个仓库的构建和部署。
三 实战
3.1 项目机构简介
需要创建两个仓库,
- 一个为
github-action-templates
,其作为共享模版库,在其中可根据实际业务定义不同场景的CI/CD流程; - 另外一个为具体业务仓库流实现
image_api
在其部署中,引用模版仓库进行复用模版实现业务部署需求。
3.2 相关概念介绍
3.2.1 可重用工作流的属性
与其他GitHub操作工作流文件一样,可重用工作流位于公共或私有存储库的. GitHub /workflows目录中。在我们的例子中,github-action-templates
公共存储库。
注意:不支持工作流目录下的子目录。
3.2.2 添加workflow_call触发器
Workflow_call触发器是可重用工作流与普通工作流之间的关键区别。对于可重用的工作流,on的值必须包括workflow_call:
on:
workflow_call:
3.2.3 添加可选的输入参数
可重用工作流在概念上是模板,这意味着它们很可能需要传递参数,以使它们特定于调用工作流。但是参数并不是使工作流可重用的必要条件。在大多数情况下,可重用工作流利用输入参数使其可用于各种环境、不同版本的编程语言等。
注意每个输入参数上面的注释行,以了解更多关于这些输入参数的用途。
on:
workflow_call:
inputs:
# pass in environment through manual trigger, if not passed in, default to 'dev'
env:
required: true
type: string
default: 'dev'
# working-directory is added to accommodate monorepo. For multi repo, defaults to '.', current directory
working-directory:
required: false
type: string
default: '.'
# pass in java version to allow different app requiring different java versions to reuse the same workflow, default to java 17
java-version:
required: false
type: string
default: '17'
# allowing calling workflows to pass in maven parameter(s) such as '-Dmaven.test.skip' for certain apps, default to blank, not to skip test
maven-params:
required: false
type: string
default: ''
- 在可重用工作流中,我们使用输入关键字来定义将从调用方工作流传递的输入。
- 在可重用工作流中,我们以 on 方法中定义的输入被引用${{ inputs.###}},例如 ${{ inputs.env}}
3.2.4 如何调用可重用工作流?
由于我们将可重用工作流托管在可重用工作流模块公共存储库中,所以我们可以使用以下语法引用可重用工作流文件:
{owner}/{repo}/.github/workflows/{filename}@{ref}
{ref}可以是SHA、发布标记或分支名称。例如,我们的客户-服务-可重用工作流示例的ci。
# This CI workflow can be triggered by PR creation or code push in PR, or manually using workflow dispatch.
name: CI workflow for building, testing microservice, and publishing image to ECR
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment to run the workflow against'
type: environment
required: true
pull_request:
branches: [ main ]
jobs:
build-and-test:
permissions:
id-token: write # need this for OIDC
contents: read
uses: org/reusable-workflows-modules/.github/workflows/java-maven-build-test.yml@main
with:
env: ${{ github.event.inputs.environment }}
secrets: inherit
- 在可重用工作流场景中,特定作业的权限是在调用工作流中定义的。
- 为了从调用工作流传递输入或秘密,我们在调用工作流的作业中使用with关键字(第22行)。在同一个组织中调用可重用工作流的工作流可以使用inherit关键字(第24行)隐式传递在GitHub中定义的秘密。
3.2.5 密钥敏感信注入
通过在调用工作流中配置secrets: inherit,我们可以在可重用工作流中引用秘密,即使它们没有在on键中定义。请参见第4行和第5行。
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@05b148adc31e091bafbaf404f745055d4d3bc9d2
with:
role-to-assume: ${{ secrets.ROLE_TO_ASSUME }}
aws-region: ${{ secrets.AWS_REGION }}
3.3 代码结构
3.3.1 模版仓库
├── .github
│ └── workflows
│ └── ci-golang.yml
└── README.md
- ci-golang.yml 文件
name: CI-Golang
on:
workflow_call:
inputs:
env:
required: true
type: string
default: 'dev'
working-directory:
required: false
type: string
default: '.'
dockerfile-location:
required: false
type: string
default: './Dockerfile'
image-platforms:
required: false
type: string
default: 'linux/amd64,linux/arm64'
image-registry:
required: true
type: string
default: ''
image-namespace:
required: true
type: string
default: ''
app-name:
required: true
type: string
default: ''
app-tag:
required: true
type: string
default: ''
permissions:
contents: read
jobs:
build:
permissions:
contents: read
id-token: write
name: build ant test
runs-on: ubuntu-latest
outputs:
output1: ${{ steps.build-image-push.outputs.name }}
defaults:
run:
working-directory: ${{ inputs.working-directory }}
env:
#
REGISTRY_PWD: ${{ secrets.REGISTRY_PWD }}
#
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
steps:
# 安全扫描
- name: Harden Runner
uses: step-security/harden-runner@18bf8ad2ca49c14cbb28b91346d626ccfb00c518
with:
egress-policy: audit
# clone 代码
- name: Checkout Code
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
# v2.4.1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7
- name: Generate build ID
id: tag
run: |
sha=${GITHUB_SHA::8}
echo "::set-output name=TAG::${sha}"
- name: log
run: |
echo ${{ inputs.image-registry }}/${{ inputs.image-namespace }}/${{ inputs.app-name }}:${{ steps.tag.outputs.TAG }}
echo ${{ env.REGISTRY_PWD}}
echo "${{ env.REGISTRY_USER }}"
- name: Build, tag, and push image to tencent TCR
id: build-image-push
run: |
TAG=${GITHUB_SHA::8}
# Build a docker container and push it to tencent TCR
docker build -t ${{ inputs.image-registry }}/${{ inputs.image-namespace }}/${{ inputs.app-name }}:${{ steps.tag.outputs.TAG }} .
echo ${{ env.REGISTRY_PWD}} | docker login ${{ inputs.image-registry}} -u "${{ env.REGISTRY_USER }}" --password-stdin
docker push ${{ inputs.image-registry }}/${{ inputs.image-namespace }}/${{ inputs.app-name }}:${{ steps.tag.outputs.TAG }}
echo "::set-output name=${{ inputs.image-registry }}/${{ inputs.image-namespace }}/${{ inputs.app-name }}:${{ steps.tag.outputs.TAG }}"
# 校验镜像
- name: verify image
run:
docker buildx imagetools inspect ${{ inputs.image-registry }}/${{ inputs.image-namespace }}/${{ inputs.app-name }}:${{ steps.tag.outputs.TAG }}
# trivy 扫描镜像
- name: Scan image with Trivy vulnerability scanner
uses: aquasecurity/trivy-action@8bd2f9fbda2109502356ff8a6a89da55b1ead252
with:
image-ref: ${{ inputs.image-registry }}/${{ inputs.image-namespace }}/${{ inputs.app-name }}:${{ steps.tag.outputs.TAG }}
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
3.3.2 业务仓库
...业务代码
Dockerfile
.github
└── workflows
└── ci.yml
- ci.yml
name: business-stage
on:
workflow_dispatch:
inputs:
environment:
description: 'Environment to run the workflow against'
type: environment
required: true
image-registry:
required: true
type: string
image-namespace:
required: true
type: string
app-name:
required: true
type: string
app-tag:
required: true
type: string
push:
branches:
- 'main'
- 'releases/**'
permissions:
contents: read
jobs:
build-and-test:
name: Build and test
permissions:
id-token: write # need this for OIDC
contents: read
uses: redhatxl/github-action-templates/.github/workflows/ci-golang.yml@main
with:
env: dev
image-registry: ccr.ccs.tencentyun.com
image-namespace: xxxximagens
app-name: image-api
app-tag: latest
secrets: inherit
四 测试
4.1 流水线敏感信息配置
敏感信息通过github actions 密钥传入
提交新代码变更,触发流水线执行。
4.2 查看流水线
4.3 查看镜像
五 注意事项
如果 github-action-templates
使用私有仓库,则需要模版库权限,否则业务仓库找不到模版库。
六 适应场景
- 自动化测试:测试是软件开发过程中必不可少的一部分,而测试流水线通常需要在不同的仓库中使用相同的测试框架和工具。通过将测试流水线定义为可复用的工作流模板,可以在多个仓库中使用相同的测试流程,并且可以根据需要进行自定义配置。
- 代码质量检查:代码质量检查可以帮助开发人员在代码提交之前发现问题并修复它们。通过将代码质量检查流水线定义为可复用的工作流模板,可以在多个仓库中使用相同的质量检查流程,并且可以根据需要进行自定义配置。
- 构建和部署:构建和部署是软件交付流程中的关键步骤。通过将构建和部署流水线定义为可复用的工作流模板,可以在多个仓库中使用相同的构建和部署流程,并且可以根据需要进行自定义配置。
- 发布到不同平台:在开发过程中,需要将应用程序发布到不同的平台,例如 Android、iOS、Web 等。通过将发布流水线定义为可复用的工作流模板,可以在多个仓库中使用相同的发布流程,并且可以根据需要进行自定义配置。
- 自定义流水线:开发者可以根据需要定义自己的流水线模板,以满足特定的需求,并在多个仓库中使用这些模板。使用可复用的工作流模板可以提高开发效率,保持一致性,并提高可维护性。
需要根据业务实际情况选择是否使用。
参考链接
- 点赞
- 收藏
- 关注作者
评论(0)