What is Github Action?

GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that lets you automate your build, test, and deployment processes. You can create workflows to build and test every pull request to your repository, or deploy merged pull requests to production.

GitHub Actions is more than just DevOps; it lets you run workflows when other events happen in your repository. For example, you can run a workflow to automatically add appropriate labels when someone creates a new issue in your repository.

GitHub offers Linux, Windows, and macOS virtual machines to run your workflows, or you can host your own self-hosted runners in your own data center or cloud infrastructure.

CICD tool selection

Currently, the CICD market is really flourishing. In addition to github actions, there are many other CICD tools to choose from, such as: Gitlab CI, Jenkins, Tekton focusing on cloud native, Bitbucket Pipelines, AWS CodePipeline, Bitbucket Pipelines, Azure DevOps, Alibaba Cloud Effect, etc.

Which method to choose to implement your business automation pipeline depends on your actual situation. The following recommendations start from the following aspects:

  • Cost, whether to choose an open source solution or a paid commercial version. If you put cost first, you need to consider the cost of building an open source software server and the licensing cost of paid software.

  • Ease of use and learning path, mainly consider whether the system interface is beautiful and whether the technical documentation is complete. The interface is difficult to judge, and the technical documentation can check whether the official documentation is detailed and whether the workflow uses yaml or a new language.

  • Scalability and flexibility, mainly consider whether the system plug-ins and custom requirements can be met. This also depends on personal needs. For example, some companies need CICD and jira to be connected, then it is better to choose Bitbucket Pipelines.

  • Integration capability, mainly consider whether it is integrated with the current code repository, test framework, deployment environment and the degree of API function perfection. For example, if your code repository is on Github, of course, it is better to choose github actions.

  • Security, mainly examine whether there are security features such as access control and data encryption. This is selected according to your actual needs.

  • Performance, mainly examine the performance bottleneck of large-scale deployment. Often this needs to be compared with cost or resource requirements. For example, if you have strict requirements for file transfer and bandwidth in daily construction, using github actions is not the best choice.

  • Enterprise-level solutions, mainly examine high concurrency, multi-tenancy, security compliance, etc. Often, for enterprises of a certain scale, there will be many customized requirements. See if the tool has enterprise solutions.

  • Cloud native support, mainly examine the degree of support for the business under kubernetes, especially the new version, in which Tekton has more advantages.

  • Community and ecology, mainly examine which users of the project or product are using it, and the community activity. In this regard, jenkins, gitlab, and github are relatively more advantageous.

Github Actions Components

1. workflow

From the literal meaning, we can see that workflow is a kind of work flow, and here it is mainly used to configure the CICD automation process of github actions. It is usually defined using yaml files. After the definition is completed, the workflow can be triggered automatically or manually.

The working directory of workflow is generally under the .github/workflow directory of the repository. A repository can have multiple workflows, and each workflow can perform a different set of tasks. The tasks here are also commonly referred to as job tasks. For example:

  • Build and test pull requests.

  • Deploy your application every time you release it.

  • Add tags every time you open a new issue.

Of course, workflows can also reference each other.

In actual use, we usually use workflow templates to quickly write workflows, and GitHub also provides workflow templates for various scenarios, such as

  • CI: continuous integration workflow
  • Deployment: deployment workflow
  • Automation: automation workflow
  • Code scanning: code scanning workflow
  • github pages: pages workflow

When writing workflows, you need to pay attention to the meaning of common keywords. Below I have briefly sorted them out for easy use later:

  • name: define the workflow name
  • run-name: define the workflow runtime name
  • on: define the trigger, which can be one event or multiple events or triggered based on matching
  • env: define workflow global variables
  • jobs: define workflow tasks
  • permissions: define workflow permissions for warehouses
  • default: define default configuration, which can be used globally or in a job, such as defining shells or working directories, etc.
  • on.schedule: define workflow time schedule
  • on.workflow_call: define information transmission during the input and output of different workflows
  • on.workflow_dispatch: define a specific workflow, enter some tags to trigger
  • jobs.<job_id>.name: define the task name of a single job
  • jobs.<job_id>.runs-on: select the jobs running environment, the default is github official, you can also choose a high-performance machine or host your own host
  • jobs.<job_id>.steps: define different running stages of a single job, for example, a job has checkout code and build
  • jobs.<job_id>.env: define a single job specific variable, belongs to the map type, and can also be set globally.
  • jobs.<job_id>.environment: define a reference in a single job, the content can be a variable or context expression
  • jobs.<job_id>.uses: defines which action to use. Sometimes, when deploying some complex scenarios, you need to use some open source actions.
  • jobs.<job_id>.with: specifies parameters. Generally, when building a task, you need to specify a version.
  • jobs.<job_id>.needs: generally, when there are multiple jobs, handle the dependencies between jobs.
  • jobs.<job_id>.if: specifies the job running conditions.
  • jobs.<job_id>.container: specifies the container service in a single job. Note that there are requirements for the runner’s operating system, such as Ubuntu.
  • jobs.<job_id>.outputs: defines the output of the job.

2. Event triggers

In the previous step, we know the workflow, so how to trigger the workflow? At this time, you need to define an event trigger, such as the common event trigger method:

  • Triggered by code repository changes, such as when pushed to the default branch of the code
  • Occurs outside GitHub and triggers the repository_dispatch event
  • Scheduled time
  • Manual trigger

Workflow triggers are defined using on, and there are several common configurations:

Set a trigger for an event, which is triggered when pushed to any branch in the workflow repository:

1
on: push

Set a trigger for multiple events, which is triggered when pushed to any branch in the workflow repository:

1
on: [push, fork]

When there are multiple branches, you need to filter specific branches, such as main or releases related branches, and trigger when there is a push:

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

GitHub itself can also match issues to trigger

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

3. Jobs

Generally, a workflow consists of one or more jobs, which run in parallel by default. Note that jobs.<job_id> is the unique identifier of the job.

For example, we define a job named Docker build, and for this job, build is the unique identifier of the job.

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

In addition, dependencies can also be defined between jobs, defined by the jobs.<job_id>.needs keyword, such as:

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

In this example, job1 must be successfully completed before job2 starts, and job3 waits for job1 and job2 to complete.

4. Actions

Action is a custom application on Github that is used to perform complex but often repeated tasks. Using actions helps reduce the amount of repetitive code you write in your workflow files.

Actions can pull your Git repository from GitHub, set up the correct toolchain for your build environment, or set up authentication for your cloud provider.

Generally defined by the keyword uses, such as using the official: 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

You can write your own actions or find actions used in workflows in the GitHub Marketplace.

5. Runners

Runners are servers that run workflows when they are triggered. Define which type of runners to use by using the keyword runs-on. Each runner can run one job at a time, which is indeed very similar to the runner in gitlab CI.

GitHub provides Ubuntu Linux, Microsoft Windows, and macOS related runners to run workflows. Each workflow runs in a new, newly configured virtual machine.

Of course, if the default runners cannot meet your business needs, such as requiring an ARM architecture virtual machine, hosting your own server to GitHub for management; or if the resources are insufficient, you can also apply for larger runners.

The following sample workflow has two jobs, named Run-npm-on-Ubuntu and Run-PSScriptAnalyzer-on-Windows. When this workflow is triggered, GitHub provisions a new virtual machine for each job.

The job named Run-npm-on-Ubuntu is executed on a Linux VM because the job runs-on: specifies ubuntu-latest. The job named Run-PSScriptAnalyzer-on-Windows is executed on a Windows VM because the job runs-on: specifies windows-latest.

1
2
3
4
5
Install-Module PSScriptAnalyzer -ErrorAction Stop
- name: Get list of rules
shell: pwsh
run: |
Get-ScriptAnalyzerRule

This GitHub Actions workflow file defines two jobs:

  • Run-npm-on-Ubuntu: Runs the npm help command on an Ubuntu virtual machine.

  • Run-PSScriptAnalyzer-on-Windows: Installs the PSScriptAnalyzer module on a Windows virtual machine and lists all available rules.

These two jobs show how to run specific commands and scripts on different operating systems. In this way, you can ensure consistency and compatibility in different environments.

Common examples of Github Actions

1. Front-end build deployment

For example, a template for deploying a front-end Nodejs project to the Azure cloud, 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
on:
push:
branches: [ "master" ]
workflow_dispatch: # Allows manual triggering of workflows

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

This GitHub Actions workflow file defines two main jobs: build and deploy. The build job is responsible for checking out the code, setting up the Node.js environment, installing dependencies, building and testing the project, and uploading the build results as artifacts. The deploy job downloads the artifacts from the build job and deploys them to the Azure Web App. The entire process automates the entire process from code submission to application deployment.

2. Golang multi-version

Example: The following is a go multi-version build example

 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

This GitHub Actions workflow file mainly defines the build support for multi-version golang environments.

3. Container example

Example: Run Docker container service in a node with runners as ubuntu

 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 # Map the container port 80 to the host port 80.
volumes:
- my_docker_volume:/volume_mount # Mount a Docker volume named my_docker_volume to the container's /volume_mount path
options: --cpus 1 # Limit the number of CPUs used by the container to 1 core
steps:
- name: Check for dockerenv file
run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv)

This GitHub Actions workflow file defines a CI job that runs on a recent Ubuntu VM and uses the Node.js 18 Docker image. The job configures environment variables, port mappings, volume mounts, and CPU limits. The only step is to check if a .dockerenv file exists to confirm that the current environment is a Docker container.

4. Deploy the application to 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

This GitHub Actions workflow The file defines a CI/CD process for building and deploying Docker images to Amazon ECS. The design content includes: checking out code, configuring AWS credentials, logging in to Amazon ECR, building tags and pushing images to ECR, and updating ECS ​​task definitions. Image ID in, deploy the updated ECS task definition.

5. Combine with Helm to deploy the application to the AKS cluster

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

This GitHub Actions workflow file defines a CI/CD process for building and pushing a Docker image to Azure Container Registry (ACR), then Deploy the application to Azure Kubernetes Service (AKS) cluster. The main steps include: check out the code, log in with Azure credentials, build and push the Docker image to ACR, get the kubeconfig file of the AKS cluster, render the deployment manifest file with Helm, and deploy the application.

6. Combine with Helm to deploy the application to Alibaba Cloud ACK cluster

  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        

This GitHub Actions works The flow file defines a CI/CD process for building and pushing Docker images to Alibaba Cloud Container Registry (ACR), and then deploying the application to Alibaba Cloud Container Service for Kubernetes (ACK). The specific steps include: Checking out code, use AccessKey to log in to ACR, build and push Docker images to ACR, scan images in ACR, set the context of ACK cluster, set Kustomize, and deploy applications.

7. Combine with Helm to deploy applications to Google Cloud Cluster

  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          

This GitHub Actions workflow file defines a CI/CD process for building and pushing a Docker image to Google Cloud Artifact Registry (GAR) and then deploying the application to Google Kubernetes Engine (GKE ).

The specific steps include: check out the code, authenticate to Google Cloud using Workload Identity Provider, authenticate Docker to push the image to Artifact Registry, obtain the credentials of the GKE cluster, build and push the Docker image to Artifact Registry, set up Kustomize, and deploy the application program to GKE.

Github Actions Advantages and Disadvantages

Through using it for a few days, I feel that GitHub Actions is a powerful tool for automating software development workflows such as continuous integration (CI), continuous deployment (CD), testing, and release etc. It is directly integrated on the GitHub platform, providing rich functionality and flexibility.

However, like all tools, GitHub Actions also has its pros and cons. Here is a summary of its advantages and disadvantages:

Advantages

  1. Seamless integration:
  • Seamless integration with GitHub: GitHub Actions is directly integrated into the GitHub platform, allowing easy access to code in the repository and metadata.
  • Automatic triggering: Workflows can be automatically triggered based on events such as code push, pull request, tag creation, etc.
  1. Rich market:
  • Action market: GitHub provides A rich Action Marketplace, where users can find a large number of pre-built Actions for common tasks such as code quality checks, deployments, notifications, etc.
  • Community Support: A large developer community provides a wealth of resources and Best practices help users solve problems quickly.
  1. Flexibility and scalability:
  • Custom workflow: Users can customize complex multi-step workflows to meet specific needs.
    • Environment variables and key management*: Support environment variables and key management to ensure the security of sensitive information.
  • Parallel execution: Support parallel execution of multiple tasks to improve efficiency.
  1. Built-in security and audit:
  • Security features: GitHub provides a variety of security features, such as dependency review, code scanning, etc.
  • Audit log: Detailed audit log records , easy to track and debug.
  1. Cost-effectiveness:
  • Free plan: For open source projects and individual developers, GitHub provides free Actions usage quota.
  • Pay as you go: For Enterprise users can pay based on actual usage to avoid wasting resources.

Disadvantages

  1. Learning curve:
  • Complexity: Although it provides rich functions, it requires configuration and management of complex workflows It may take some time to learn and experience.
  • Documentation and Examples: Although there is a lot of documentation and examples, it may take some time for beginners to find the right resources and best practices.
  1. Performance and resource limits:
  • Resource limits: The free plan has limited resources, which may not be enough for large projects or high-frequency CI/CD pipelines.
  • Performance fluctuations: During peak hours, GitHub Actions Performance may be affected, resulting in slower builds and deployments.
  1. Depends on GitHub:
  • Platform lock-in: Using GitHub Actions will increase your reliance on the GitHub platform, and the migration cost is high.
  • External integration: Although GitHub Actions supports integration with external tools and Service integration, but may require more configuration and maintenance than other CI/CD tools.
  1. Difficult debugging:
  • Debugging tools: Although logs and outputs are provided, debugging is complex Multi-step workflows can be difficult, especially when problems arise.
  • Lack of visualization: GitHub Actions has limited visualization and monitoring capabilities compared to some commercial CI/CD tools.
  1. *Security risks *:
  • Third-party Action: Using third-party Action may bring security risks and requires careful evaluation and selection.
  • Permission management: Improper permission management may lead to security vulnerabilities and requires careful configuration.

Summary

GitHub Actions is a powerful and flexible CI/CD tool that is particularly suitable for projects integrated with GitHub. Its advantages lie in seamless integration, rich market, flexibility and security.

However, it also has some disadvantages, such as a steep learning curve, resource limitations, platform lock-in, and debugging difficulties. The choice of whether to use GitHub Actions should be based on the specific needs of the project and the team’s technology stack.

For small projects and open source projects, GitHub Actions is a very good choice; for large enterprise projects, you may need to consider more professional CI/CD tools.