Github Action是什么?

GitHub Actions 是一个持续集成和持续交付 (CI/CD) 平台,可让您自动化构建、测试和部署流程。您可以创建工作流程来构建和测试对存储库的每个拉取请求,或将合并的拉取请求部署到生产环境中。

GitHub Actions 不仅仅是 DevOps,它还允许您在存储库中发生其他事件时运行工作流程。例如,您可以运行工作流程,以便在有人在您的存储库中创建新问题时自动添加适当的标签。

GitHub提供 Linux、Windows 和 macOS 虚拟机来运行您的工作流程,或者您可以在自己的数据中心或云基础设施中托管自己的自托管运行器。

CICD工具选型

目前CICD的市场真是百花齐放,除了github actions外还有很多其他CICD工具可供选择, 比如:Gitlab CI、Jenkins、专注于云原生的Tekton、Bitbucket Pipelines、AWS CodePipeline、Bitbucket Pipelines、Azure DevOps、阿里云云效等等

而选择那种方式来实现自己业务自动化流水线,就要根据自己的实际情况来选择了,下面推荐从如下几个方面入手:

  • 成本,是选择开源方案还是选择付费商业版本,如果把成本放在第一位,需要考虑搭建开源软件服务器成本和付费软件的授权成本。
  • 易用性和学习路线,主要考虑系统界面是否美观以及技术文档是否完善,界面这方面很难评判,而技术文档可以查看官方文档是否详细以及工作流是采用yaml还是新语言。
  • 可扩展和灵活性,主要考虑系统插件和自定义需求是否能够满足,这方面还要看个人需求,比如有些企业需要CICD和jira打通,那选择Bitbucket Pipelines更好。
  • 集成能力,主要考虑是否和目前代码仓库、测试框架、部署环境集成以及API功能完善程度,比如你的代码仓库在Github上,当然选择github actions更好一些。
  • 安全性,主要考察是否有访问控制、数据加密等安全特性,这个根据自己实际需求来选择。
  • 性能,主要考察大规模部署的性能瓶颈,往往这个需要结合成本或者资源需求来比较,比如你日常构建对文件传输和带宽有很严格需要,用github actions这种就不是最好的选择了。
  • 企业级方案,主要考察高并发、多租户、安全合规等,往往对于企业到一定规模,会有很多定制需求,看工具是否有企业解决方案。
  • 云原生支持,主要考察业务在kubernetes下的支持程度,特别是新版本,这方面Tekton更有优势。
  • 社区和生态,主要考察项目或者产品哪些用户在使用,以及社区活跃度,这方面jenkins、gitlab、github相对更有优势。

Github Actions组件

1. workflow

从字面意思可以看出workflow是一种工作流程,而这里主要为了配置github actions的CICD自动化流程,通常使用yaml文件定义,定义完成以后可以自动触发工作流也可以手动触发工作流程。

workflow的工作目录一般为仓库的下.github/workflow目录下,一个存储库可以有多个工作流,每个工作流可以执行一组不同的任务,这里的任务也就是常说的job任务。 例如:

  • 构建和测试拉取请求。
  • 每次发布时部署您的应用程序。
  • 每当打开新问题时添加标签。

当然,工作流之间也可以相互引用。

在实际使用当中,我们通常采用workflow模版来快速编写工作流程,而github也提供了各类场景工作流模版,比如

  • CI:持续集成工作流
  • 部署:部署工作流
  • 自动化:自动化工作流
  • 代码扫描:代码扫描工作流
  • github pages:pages工作流

在编写工作流的时候,需要注意常见关键字的意思,下面我简单梳理了一下,方便后面使用:

  • name: 定义工作流程名称
  • run-name: 定义工作流运行时名称
  • on: 定义触发器,可以是一个事件也可以是多个事件或者是根据匹配来触发
  • env: 定义工作流全局变量
  • jobs: 定义工作流任务
  • permissions: 定义工作流对仓库权限
  • default: 定义默认配置,可以用在全局或者某一个job中,比如定义shell或者工作目录等
  • on.schedule: 定义工作流时间计划
  • on.workflow_call: 定义不同工作流的输入和输出过程中信息传递。
  • on.workflow_dispatch: 定义特定工作流中,输入一些标记来触发
  • jobs.<job_id>.name: 定义单个job的任务名称
  • jobs.<job_id>.runs-on: 选择jobs运行环境,默认为github官方的,也可以选择高性能机器或者托管自己主机
  • jobs.<job_id>.steps: 定义单个job不同的运行阶段,比如一个job里有checkout代码,也有build
  • jobs.<job_id>.env: 定义单个job特定变量,属于map类型,也可以设置在全局。
  • jobs.<job_id>.environment: 定义单个Job里引用,内容可以是变量或者上下文的表达式。
  • jobs.<job_id>.uses: 定义使用那种action,有的时候部署一些复杂场景,需要用到一些开源比较好的action
  • jobs.<job_id>.with: 指定参数,一般在任务构建的时候,需要指定一个版本
  • jobs.<job_id>.needs: 一般多个job的时候,处理job之间依赖关系
  • jobs.<job_id>.if: 指定job运行条件
  • jobs.<job_id>.container: 指定单个job里指定容器服务,注意对runner的操作系统有要求,比如ubuntu
  • jobs.<job_id>.outputs: 定义作业输出一些内容

2. 事件触发器

上一步,我们知道了工作流,那如何触发工作流呢?这个时候就需要定义一个事件触发器,比如常用事件触发器方式:

  • 代码仓库变更触发,比如推送到代码默认分支时触发
  • github之外发生,并触发repository_dispatch事件
  • 预定时间
  • 手动触发

工作流触发器使用on定义,常见几种配置:

设置一个事件的触发器,当推送到工作流存储库中的任何分支时触发:

1
on: push

设置一个多个事件的触发器,当推送到工作流存储库中的任何分支时触发:

1
on: [push, fork]

当有多个分支的时候,需要过滤特定分支,比如main或者releases相关分支,有推送即触发:

1
2
3
4
5
on:
  push:
    branches:
      - main
      - 'releases/**'

github本身也可以对issues进行匹配来触发

1
2
3
4
5
on:
  issues:
    types:
      - opened
      - labeled

3. Jobs

一般工作流中由一个或多个jobs组成,默认情况下并行运行,需要注意:jobs.<job_id>是job的唯一标识符

比如,我们定义一个job名为Docker build,而对于这个job, build才是job的唯一标识符

1
2
3
4
5
6
jobs:
  build:
    name: Docker build
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

另外,job之间也可以定义依赖关系,通过jobs.<job_id>.needs关键字定义,比如:

1
2
3
4
5
6
jobs:
  job1:
  job2:
    needs: job1
  job3:
    needs: [job1, job2]

在此示例中,job1必须在job2开始之前成功完成,并且job3等待job1和job2完成。

4. Actions

Action是Github上自定义应用程序,用于执行复杂但经常重复的任务。使用操作有助于减少您在工作流程文件中编写的重复代码量。

Actions可以从GitHub拉取您的Git仓库,为您的构建环境设置正确的工具链,或设置对您的云提供商的身份验证。

一般通过关键字uses来定义,比如使用官方: actions/checkout@v4

1
2
3
4
5
6
7
8
9
jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

    steps:
    - name: Checkout
      uses: actions/checkout@v4

您可以编写自己的操作,也可以在 GitHub Marketplace 中找到工作流程中使用的操作。

5. Runners

Runners是一种在触发工作流程时运行工作流程的服务器。通过关键字runs-on来定义使用那种类型runners。每个运行器一次可以运行一项作业,这点确实和gitlab CI里的runner很像。

GitHub提供Ubuntu Linux、Microsoft Windows和macOS相关的runner来运行工作流。每个工作流程都运行在在全新、新配置的虚拟机中执行。

当然,如果默认Runners无法满足你的业务需求,比如需要ARM架构虚拟机,将自己服务器托管给github来管理;或者资源无法满足也可以申请更大的runners。

以下示例工作流有两个作业,名为 Run-npm-on-Ubuntu 和 Run-PSScriptAnalyzer-on-Windows。 触发此工作流时,GitHub 为每个作业预配新的虚拟机。

名为 Run-npm-on-Ubuntu的作业在Linux VM上执行,因为作业runs-on: 指定 ubuntu-latest。 名为 Run-PSScriptAnalyzer-on-Windows的作业在Windows VM 上执行,因为作业runs-on: 指定 windows-latest。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
name: Run commands on different operating systems
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  Run-npm-on-Ubuntu:
    name: Run npm on Ubuntu
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '14'
      - run: npm help

  Run-PSScriptAnalyzer-on-Windows:
    name: Run PSScriptAnalyzer on Windows
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install PSScriptAnalyzer module
        shell: pwsh
        run: |
          Set-PSRepository PSGallery -InstallationPolicy Trusted
          Install-Module PSScriptAnalyzer -ErrorAction Stop          
      - name: Get list of rules
        shell: pwsh
        run: |
          Get-ScriptAnalyzerRule          

这个GitHub Actions工作流文件定义了两个作业:

  • Run-npm-on-Ubuntu: 在 Ubuntu 虚拟机上运行 npm help 命令。
  • Run-PSScriptAnalyzer-on-Windows: 在 Windows 虚拟机上安装 PSScriptAnalyzer 模块并列出所有可用的规则。

这两个作业分别展示了如何在不同的操作系统上运行特定的命令和脚本。通过这种方式,你可以确保在不同环境中的一致性和兼容性。

Github Actions常见示例

1. 前端构建部署

举例, 一个部署前端Nodejs项目到Azure云的模版, Deploy Node.js to Azure Web App:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
on:
  push:
    branches: [ "master" ]
  workflow_dispatch:  # 允许手动触发工作流

env:
  AZURE_WEBAPP_NAME: your-app-name    # set this to your application's name
  AZURE_WEBAPP_PACKAGE_PATH: '.'      # set this to the path to your web app project, defaults to the repository root
  NODE_VERSION: '20.x'                # set this to the node version to use

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Set up Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'

    - name: npm install, build, and test
      run: |
        npm install
        npm run build --if-present
        npm run test --if-present        

    - name: Upload artifact for deployment job
      uses: actions/upload-artifact@v3
      with:
        name: node-app
        path: .

  deploy:
    permissions:
      contents: none
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'Development'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

    steps:
    - name: Download artifact from build job
      uses: actions/download-artifact@v3
      with:
        name: node-app

    - name: 'Deploy to Azure WebApp'
      id: deploy-to-webapp
      uses: azure/webapps-deploy@v2
      with:
        app-name: ${{ env.AZURE_WEBAPP_NAME }}
        publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
        package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}

这个GitHub Actions工作流文件定义了两个主要作业:build 和 deploy。build 作业负责检出代码、设置 Node.js 环境、安装依赖、构建和测试项目,并将构建结果上传为 artifact。 deploy 作业则从 build 作业下载 artifact,并将其部署到 Azure Web App。整个流程自动化了从代码提交到应用部署的全过程。

2. Golang多版本

举例:如下是一个go多版本构建示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
name: Go

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        go-version: [ '1.19', '1.20', '1.21.x' ]

    steps:
      - uses: actions/checkout@v4
      - name: Setup Go ${{ matrix.go-version }}
        uses: actions/setup-go@v5
        with:
          go-version: ${{ matrix.go-version }}
      # You can test your matrix by printing the current Go version
      - name: Display Go version
        run: go version

这个GitHub Actions工作流文件主要定义支持多版本golang环境的构建。

3. 容器示例

举例:一个runners为ubuntu的节点里运行docker容器服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
name: CI
on:
  push:
    branches: [ main ]
jobs:
  container-test-job:
    runs-on: ubuntu-latest
    container:
      image: node:18
      env:
        NODE_ENV: development
      ports:
        - 80   # 将容器80端口映射到主机的80端口。
      volumes:
        - my_docker_volume:/volume_mount # 将名为my_docker_volume的Docker卷挂载到容器的/volume_mount路径
      options: --cpus 1 # 限制容器使用的CPU数量为1个核
    steps:
      - name: Check for dockerenv file
        run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv)

这个GitHub Actions工作流文件定义了一个CI任务,该任务在最新的Ubuntu虚拟机上运行,并使用 Node.js 18的Docker镜像。 作业配置了环境变量、端口映射、卷挂载和CPU限制。唯一的一个步骤是检查是否存在 .dockerenv 文件,以确认当前环境是否为 Docker 容器。

4. 部署应用到AWS ECS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# This workflow will build and push a new container image to Amazon ECR,
# and then will deploy a new task definition to Amazon ECS, when there is a push to the "master" branch.
#
# To use this workflow, you will need to complete the following set-up steps:
#
# 1. Create an ECR repository to store your images.
#    For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`.
#    Replace the value of the `ECR_REPOSITORY` environment variable in the workflow below with your repository's name.
#    Replace the value of the `AWS_REGION` environment variable in the workflow below with your repository's region.
#
# 2. Create an ECS task definition, an ECS cluster, and an ECS service.
#    For example, follow the Getting Started guide on the ECS console:
#      https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun
#    Replace the value of the `ECS_SERVICE` environment variable in the workflow below with the name you set for the Amazon ECS service.
#    Replace the value of the `ECS_CLUSTER` environment variable in the workflow below with the name you set for the cluster.
#
# 3. Store your ECS task definition as a JSON file in your repository.
#    The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.
#    Replace the value of the `ECS_TASK_DEFINITION` environment variable in the workflow below with the path to the JSON file.
#    Replace the value of the `CONTAINER_NAME` environment variable in the workflow below with the name of the container
#    in the `containerDefinitions` section of the task definition.
#
# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
#    See the documentation for each action used below for the recommended IAM policies for this IAM user,
#    and best practices on handling the access key credentials.

name: Deploy to Amazon ECS

on:
  push:
    branches: [ "master" ]

env:
  AWS_REGION: MY_AWS_REGION                   # set this to your preferred AWS region, e.g. us-west-1
  ECR_REPOSITORY: MY_ECR_REPOSITORY           # set this to your Amazon ECR repository name
  ECS_SERVICE: MY_ECS_SERVICE                 # set this to your Amazon ECS service name
  ECS_CLUSTER: MY_ECS_CLUSTER                 # set this to your Amazon ECS cluster name
  ECS_TASK_DEFINITION: MY_ECS_TASK_DEFINITION # set this to the path to your Amazon ECS task definition
                                               # file, e.g. .aws/task-definition.json
  CONTAINER_NAME: MY_CONTAINER_NAME           # set this to the name of the container in the
                                               # containerDefinitions section of your task definition

permissions:
  contents: read

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

    steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ env.AWS_REGION }}

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        IMAGE_TAG: ${{ github.sha }}
      run: |
        # Build a docker container and
        # push it to ECR so that it can
        # be deployed to ECS.
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT        

    - name: Fill in the new image ID in the Amazon ECS task definition
      id: task-def
      uses: aws-actions/amazon-ecs-render-task-definition@v1
      with:
        task-definition: ${{ env.ECS_TASK_DEFINITION }}
        container-name: ${{ env.CONTAINER_NAME }}
        image: ${{ steps.build-image.outputs.image }}

    - name: Deploy Amazon ECS task definition
      uses: aws-actions/amazon-ecs-deploy-task-definition@v1
      with:
        task-definition: ${{ steps.task-def.outputs.task-definition }}
        service: ${{ env.ECS_SERVICE }}
        cluster: ${{ env.ECS_CLUSTER }}
        wait-for-service-stability: true

这个GitHub Actions工作流文件定义了一个 CI/CD流程,用于将Docker镜像构建并部署到Amazon ECS。设计内容有:检出代码、配置AWS凭证、登录到Amazon ECR、 构建标记并推送镜像到ECR、更新ECS任务定义中的镜像ID、部署更新后的ECS任务定义。

5. 结合Helm部署应用到AKS集群

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# This workflow will build and push an application to a Azure Kubernetes Service (AKS) cluster when you push your code
#
# This workflow assumes you have already created the target AKS cluster and have created an Azure Container Registry (ACR)
# The ACR should be attached to the AKS cluster
# For instructions see:
#   - https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal
#   - https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal
#   - https://learn.microsoft.com/en-us/azure/aks/cluster-container-registry-integration?tabs=azure-cli#configure-acr-integration-for-existing-aks-clusters
#   - https://github.com/Azure/aks-create-action
#
# To configure this workflow:
#
# 1. Set the following secrets in your repository (instructions for getting these
#    https://docs.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux)):
#    - AZURE_CLIENT_ID
#    - AZURE_TENANT_ID
#    - AZURE_SUBSCRIPTION_ID
#
# 2. Set the following environment variables (or replace the values below):
#    - AZURE_CONTAINER_REGISTRY (name of your container registry / ACR)
#    - CONTAINER_NAME (name of the container image you would like to push up to your ACR)
#    - RESOURCE_GROUP (where your cluster is deployed)
#    - CLUSTER_NAME (name of your AKS cluster)
#    - IMAGE_PULL_SECRET_NAME (name of the ImagePullSecret that will be created to pull your ACR image)
#
# 3. Choose the appropriate render engine for the bake step https://github.com/Azure/k8s-bake. The config below assumes Helm.
#    Set your helmChart, overrideFiles, overrides, and helm-version to suit your configuration.
#    - CHART_PATH (path to your helm chart)
#    - CHART_OVERRIDE_PATH (path to your helm chart with override values)
#
# For more information on GitHub Actions for Azure, refer to https://github.com/Azure/Actions
# For more samples to get started with GitHub Action workflows to deploy to Azure, refer to https://github.com/Azure/actions-workflow-samples
# For more options with the actions used below please refer to https://github.com/Azure/login

name: Build and deploy an app to AKS with Helm

on:
  push:
    branches: ["master"]
  workflow_dispatch:

env:
  AZURE_CONTAINER_REGISTRY: "your-azure-container-registry"
  CONTAINER_NAME: "your-container-name"
  RESOURCE_GROUP: "your-resource-group"
  CLUSTER_NAME: "your-cluster-name"
  CHART_PATH: "your-chart-path"
  CHART_OVERRIDE_PATH: "your-chart-override-path"

jobs:
  buildImage:
    permissions:
      contents: read
      id-token: write
    runs-on: ubuntu-latest
    steps:
      # Checks out the repository this file is in
      - uses: actions/checkout@v4

      # Logs in with your Azure credentials
      - name: Azure login
        uses: azure/login@v1.4.6
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      # Builds and pushes an image up to your Azure Container Registry
      - name: Build and push image to ACR
        run: |
          az acr build --image ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }} --registry ${{ env.AZURE_CONTAINER_REGISTRY }} -g ${{ env.RESOURCE_GROUP }} .          

  deploy:
    permissions:
      actions: read
      contents: read
      id-token: write
    runs-on: ubuntu-latest
    needs: [buildImage]
    steps:
      # Checks out the repository this file is in
      - uses: actions/checkout@v4

      # Logs in with your Azure credentials
      - name: Azure login
        uses: azure/login@v1.4.6
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      # Use kubelogin to configure your kubeconfig for Azure auth
      - name: Set up kubelogin for non-interactive login
        uses: azure/use-kubelogin@v1
        with:
          kubelogin-version: 'v0.0.25'

      # Retrieves your Azure Kubernetes Service cluster's kubeconfig file
      - name: Get K8s context
        uses: azure/aks-set-context@v3
        with:
          resource-group: ${{ env.RESOURCE_GROUP }}
          cluster-name: ${{ env.CLUSTER_NAME }}
          admin: 'false'
          use-kubelogin: 'true'

      # Runs Helm to create manifest files
      - name: Bake deployment
        uses: azure/k8s-bake@v2
        with:
          renderEngine: "helm"
          helmChart: ${{ env.CHART_PATH }}
          overrideFiles: ${{ env.CHART_OVERRIDE_PATH }}
          overrides: |
            replicas:2            
          helm-version: "latest"
        id: bake

      # Deploys application based on manifest files from previous step
      - name: Deploy application
        uses: Azure/k8s-deploy@v4
        with:
          action: deploy
          manifests: ${{ steps.bake.outputs.manifestsBundle }}
          images: |
            ${{ env.AZURE_CONTAINER_REGISTRY }}.azurecr.io/${{ env.CONTAINER_NAME }}:${{ github.sha }}            

这个GitHub Actions工作流文件定义了一个CI/CD流程,用于将Docker镜像构建并推送到Azure容器注册表(ACR),然后将应用程序部署到Azure Kubernetes Service (AKS)集群。 主要步骤包括:检出代码、使用Azure凭证登录、构建并推送Docker镜像到ACR、获取AKS集群的kubeconfig文件、使用Helm渲染部署清单文件、部署应用程序。

7. 结合Helm部署应用到阿里云ACK集群

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# This workflow will build and push a new container image to Alibaba Cloud Container Registry (ACR),
# and then will deploy it to Alibaba Cloud Container Service for Kubernetes (ACK), when there is a push to the "master" branch.
#
# To use this workflow, you will need to complete the following set-up steps:
#
# 1. Create an ACR repository to store your container images.
#    You can use ACR EE instance for more security and better performance.
#    For instructions see https://www.alibabacloud.com/help/doc-detail/142168.htm
#
# 2. Create an ACK cluster to run your containerized application.
#    You can use ACK Pro cluster for more security and better performance.
#    For instructions see https://www.alibabacloud.com/help/doc-detail/95108.htm
#
# 3. Store your AccessKey pair in GitHub Actions secrets named `ACCESS_KEY_ID` and `ACCESS_KEY_SECRET`.
#    For instructions on setting up secrets see: https://developer.github.com/actions/managing-workflows/storing-secrets/
#
# 4. Change the values for the REGION_ID, REGISTRY, NAMESPACE, IMAGE, ACK_CLUSTER_ID, and ACK_DEPLOYMENT_NAME.
#

name: Build and Deploy to ACK

on:
  push:
    branches: [ "master" ]

# Environment variables available to all jobs and steps in this workflow.
env:
  REGION_ID: cn-hangzhou
  REGISTRY: registry.cn-hangzhou.aliyuncs.com
  NAMESPACE: namespace
  IMAGE: repo
  TAG: ${{ github.sha }}
  ACK_CLUSTER_ID: clusterID
  ACK_DEPLOYMENT_NAME: nginx-deployment

  ACR_EE_REGISTRY: myregistry.cn-hangzhou.cr.aliyuncs.com
  ACR_EE_INSTANCE_ID: instanceID
  ACR_EE_NAMESPACE: namespace
  ACR_EE_IMAGE: repo
  ACR_EE_TAG: ${{ github.sha }}

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    environment: production

    steps:
    - name: Checkout
      uses: actions/checkout@v4

    # 1.1 Login to ACR
    - name: Login to ACR with the AccessKey pair
      uses: aliyun/acr-login@v1
      with:
        region-id: "${{ env.REGION_ID }}"
        access-key-id: "${{ secrets.ACCESS_KEY_ID }}"
        access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}"

    # 1.2 Build and push image to ACR
    - name: Build and push image to ACR
      run: |
        docker build --tag "$REGISTRY/$NAMESPACE/$IMAGE:$TAG" .
        docker push "$REGISTRY/$NAMESPACE/$IMAGE:$TAG"        

    # 1.3 Scan image in ACR
    - name: Scan image in ACR
      uses: aliyun/acr-scan@v1
      with:
        region-id: "${{ env.REGION_ID }}"
        access-key-id: "${{ secrets.ACCESS_KEY_ID }}"
        access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}"
        repository: "${{ env.NAMESPACE }}/${{ env.IMAGE }}"
        tag: "${{ env.TAG }}"

    # 2.1 (Optional) Login to ACR EE
    - uses: actions/checkout@v4
    - name: Login to ACR EE with the AccessKey pair
      uses: aliyun/acr-login@v1
      with:
        login-server: "https://${{ env.ACR_EE_REGISTRY }}"
        region-id: "${{ env.REGION_ID }}"
        access-key-id: "${{ secrets.ACCESS_KEY_ID }}"
        access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}"
        instance-id: "${{ env.ACR_EE_INSTANCE_ID }}"

    # 2.2 (Optional) Build and push image ACR EE
    - name: Build and push image to ACR EE
      run: |
        docker build -t "$ACR_EE_REGISTRY/$ACR_EE_NAMESPACE/$ACR_EE_IMAGE:$TAG" .
        docker push "$ACR_EE_REGISTRY/$ACR_EE_NAMESPACE/$ACR_EE_IMAGE:$TAG"        
    # 2.3 (Optional) Scan image in ACR EE
    - name: Scan image in ACR EE
      uses: aliyun/acr-scan@v1
      with:
        region-id: "${{ env.REGION_ID }}"
        access-key-id: "${{ secrets.ACCESS_KEY_ID }}"
        access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}"
        instance-id: "${{ env.ACR_EE_INSTANCE_ID }}"
        repository: "${{ env.ACR_EE_NAMESPACE}}/${{ env.ACR_EE_IMAGE }}"
        tag: "${{ env.ACR_EE_TAG }}"

    # 3.1 Set ACK context
    - name: Set K8s context
      uses: aliyun/ack-set-context@v1
      with:
        access-key-id: "${{ secrets.ACCESS_KEY_ID }}"
        access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}"
        cluster-id: "${{ env.ACK_CLUSTER_ID }}"

    # 3.2 Deploy the image to the ACK cluster
    - name: Set up Kustomize
      run: |-
        curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash /dev/stdin 3.8.6        
    - name: Deploy
      run: |-
        ./kustomize edit set image REGISTRY/NAMESPACE/IMAGE:TAG=$REGISTRY/$NAMESPACE/$IMAGE:$TAG
        ./kustomize build . | kubectl apply -f -
        kubectl rollout status deployment/$ACK_DEPLOYMENT_NAME
        kubectl get services -o wide        

这个GitHub Actions工作流文件定义了一个CI/CD流程,用于将Docker镜像构建并推送到阿里云容器镜像服务(ACR),然后将应用程序部署到阿里云容器服务for Kubernetes(ACK)。 具体步骤包括:检出代码、使用AccessKey对ACR进行登录、构建并推送Docker镜像到ACR、扫描ACR中的镜像、设置ACK集群的上下文、设置Kustomize、部署应用程序。

8. 结合Helm部署应用到谷歌云集群

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# This workflow will build a docker container, publish it to Google Container
# Registry, and deploy it to GKE when there is a push to the "master"
# branch.
#
# To configure this workflow:
#
# 1. Enable the following Google Cloud APIs:
#
#    - Artifact Registry (artifactregistry.googleapis.com)
#    - Google Kubernetes Engine (container.googleapis.com)
#    - IAM Credentials API (iamcredentials.googleapis.com)
#
#    You can learn more about enabling APIs at
#    https://support.google.com/googleapi/answer/6158841.
#
# 2. Ensure that your repository contains the necessary configuration for your
#    Google Kubernetes Engine cluster, including deployment.yml,
#    kustomization.yml, service.yml, etc.
#
# 3. Create and configure a Workload Identity Provider for GitHub:
#    https://github.com/google-github-actions/auth#preferred-direct-workload-identity-federation.
#
#    Depending on how you authenticate, you will need to grant an IAM principal
#    permissions on Google Cloud:
#
#    - Artifact Registry Administrator (roles/artifactregistry.admin)
#    - Kubernetes Engine Developer (roles/container.developer)
#
#    You can learn more about setting IAM permissions at
#    https://cloud.google.com/iam/docs/manage-access-other-resources
#
# 5. Change the values in the "env" block to match your values.

name: 'Build and Deploy to GKE'

on:
  push:
    branches:
      - '"master"'

env:
  PROJECT_ID: 'my-project' # TODO: update to your Google Cloud project ID
  GAR_LOCATION: 'us-central1' # TODO: update to your region
  GKE_CLUSTER: 'cluster-1' # TODO: update to your cluster name
  GKE_ZONE: 'us-central1-c' # TODO: update to your cluster zone
  DEPLOYMENT_NAME: 'gke-test' # TODO: update to your deployment name
  REPOSITORY: 'samples' # TODO: update to your Artifact Registry docker repository name
  IMAGE: 'static-site'
  WORKLOAD_IDENTITY_PROVIDER: 'projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider' # TODO: update to your workload identity provider

jobs:
  setup-build-publish-deploy:
    name: 'Setup, Build, Publish, and Deploy'
    runs-on: 'ubuntu-latest'
    environment: 'production'

    permissions:
      contents: 'read'
      id-token: 'write'

    steps:
      - name: 'Checkout'
        uses: 'actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332' # actions/checkout@v4

      # Configure Workload Identity Federation and generate an access token.
      #
      # See https://github.com/google-github-actions/auth for more options,
      # including authenticating via a JSON credentials file.
      - id: 'auth'
        name: 'Authenticate to Google Cloud'
        uses: 'google-github-actions/auth@f112390a2df9932162083945e46d439060d66ec2' # google-github-actions/auth@v2
        with:
          workload_identity_provider: '${{ env.WORKLOAD_IDENTITY_PROVIDER }}'

      # Authenticate Docker to Google Cloud Artifact Registry
      - name: 'Docker Auth'
        uses: 'docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567' # docker/login-action@v3
        with:
          username: 'oauth2accesstoken'
          password: '${{ steps.auth.outputs.auth_token }}'
          registry: '${{ env.GAR_LOCATION }}-docker.pkg.dev'

      # Get the GKE credentials so we can deploy to the cluster
      - name: 'Set up GKE credentials'
        uses: 'google-github-actions/get-gke-credentials@6051de21ad50fbb1767bc93c11357a49082ad116' # google-github-actions/get-gke-credentials@v2
        with:
          cluster_name: '${{ env.GKE_CLUSTER }}'
          location: '${{ env.GKE_ZONE }}'

      # Build the Docker image
      - name: 'Build and push Docker container'
        run: |-
          DOCKER_TAG="${GAR_LOCATION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/${IMAGE}:${GITHUB_SHA}"

          docker build \
            --tag "${DOCKER_TAG}" \
            --build-arg GITHUB_SHA="${GITHUB_SHA}" \
            --build-arg GITHUB_REF="${GITHUB_REF}" \
            .

          docker push "${DOCKER_TAG}"          

      # Set up kustomize
      - name: 'Set up Kustomize'
        run: |-
          curl -sfLo kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.4.3/kustomize_v5.4.3_linux_amd64.tar.gz
          chmod u+x ./kustomize          

      # Deploy the Docker image to the GKE cluster
      - name: 'Deploy to GKE'
        run: |-
          # replacing the image name in the k8s template
          ./kustomize edit set image LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:TAG=$GAR_LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$IMAGE:$GITHUB_SHA
          ./kustomize build . | kubectl apply -f -
          kubectl rollout status deployment/$DEPLOYMENT_NAME
          kubectl get services -o wide          

这个GitHub Actions工作流文件定义了一个CI/CD流程,用于将Docker镜像构建并推送到Google Cloud Artifact Registry(GAR),然后将应用程序部署到Google Kubernetes Engine(GKE)。

具体步骤包括:检出代码、使用Workload Identity Provider认证到Google Cloud、对Docker进行认证以推送镜像到Artifact Registry、获取GKE集群的凭证、构建并推送Docker镜像到Artifact Registry、设置Kustomize、部署应用程序到GKE。

Github Actions优缺点

通过这几天使用,我觉得GitHub Actions是一个强大的工具,用于自动化软件开发工作流程,如持续集成(CI)、持续部署(CD)、测试、发布等。它直接集成在GitHub平台上,提供了丰富的功能和灵活性。

然而,像所有工具一样,GitHub Actions也有其优点和缺点。以下是对其优缺点的总结:

优点

  1. 无缝集成

    • 与 GitHub 无缝集成:GitHub Actions 直接集成在 GitHub 平台内,可以轻松访问仓库中的代码和元数据。
    • 自动触发:可以根据代码推送、拉取请求、标签创建等事件自动触发工作流。
  2. 丰富的市场

    • Action 市场:GitHub 提供了丰富的 Action 市场,用户可以找到大量的预构建 Action,用于常见的任务,如代码质量检查、部署、通知等。
    • 社区支持:庞大的开发者社区提供了大量的资源和最佳实践,帮助用户快速解决问题。
  3. 灵活性和可扩展性

    • 自定义工作流:用户可以自定义复杂的多步骤工作流,满足特定需求。
    • 环境变量和密钥管理:支持环境变量和密钥管理,确保敏感信息的安全。
    • 并行执行:支持并行执行多个任务,提高效率。
  4. 内置安全性和审计

    • 安全特性:GitHub 提供了多种安全特性,如依赖项审查、代码扫描等。
    • 审计日志:详细的审计日志记录,方便追踪和调试。
  5. 成本效益

    • 免费计划:对于开源项目和个人开发者,GitHub 提供了免费的 Actions 使用额度。
    • 按需付费:对于企业用户,可以根据实际使用量付费,避免浪费资源。

缺点

  1. 学习曲线

    • 复杂性:虽然提供了丰富的功能,但配置和管理复杂的工作流可能需要一定的学习时间和经验。
    • 文档和示例:尽管有大量文档和示例,但对于初学者来说,找到合适的资源和最佳实践可能需要一些时间。
  2. 性能和资源限制

    • 资源限制:免费计划的资源有限,对于大型项目或高频率的 CI/CD 管道可能不够用。
    • 性能波动:在高峰时段,GitHub Actions 的性能可能会受到影响,导致构建和部署速度变慢。
  3. 依赖于 GitHub

    • 平台锁定:使用 GitHub Actions 会增加对 GitHub 平台的依赖,迁移成本较高。
    • 外部集成:虽然 GitHub Actions 支持与外部工具和服务的集成,但相比其他 CI/CD 工具,可能需要更多的配置和维护。
  4. 调试困难

    • 调试工具:虽然提供了日志和输出,但调试复杂的多步骤工作流可能较为困难,尤其是当出现问题时。
    • 可视化不足:相比于一些商业 CI/CD 工具,GitHub Actions 的可视化和监控功能较为有限。
  5. 安全风险

    • 第三方 Action:使用第三方 Action 可能带来安全风险,需要仔细评估和选择。
    • 权限管理:不当的权限管理可能导致安全漏洞,需要谨慎配置。

总结

GitHub Actions是一个功能强大且灵活的CI/CD 工具,特别适合与GitHub集成的项目。它的优点在于无缝集成、丰富的市场、灵活性和安全性。

然而,它也存在一些缺点,如学习曲线较陡、资源限制、平台锁定和调试困难。选择是否使用GitHub Actions 应根据项目的具体需求和团队的技术栈来决定。

对于小型项目和开源项目,GitHub Actions是一个非常不错的选择;对于大型企业项目,可能需要考虑更专业的 CI/CD工具。