All Products
Search
Document Center

Container Service for Kubernetes:Create CI pipelines for Golang projects in workflow clusters

Last Updated:Jul 03, 2024

Distributed Cloud Container Platform for Kubernetes (ACK One) workflow clusters are developed based on open source Argo Workflows. With the benefits of ultrahigh elasticity, auto scaling, and zero O&M costs, hosted Argo Workflows can help you quickly create Continuous Integration (CI) pipelines with low costs. This topic describes how to create CI pipelines for Golang projects in workflow clusters.

Introduction

To create CI pipelines in ACK One workflow clusters, use BuildKit to build and push container images and use BuildKit Cache to accelerate image building. Using Apsara File Storage NAS (NAS) to store the Go mod cache can accelerate the Go Test and Go Build steps. This greatly reduces the time required for creating CI pipelines.

image

Introduction to the predefined ClusterWorkflowTemplate

By default, workflow clusters provide a predefined ClusterWorkflowTemplate named ci-go-v1. The template uses BuildKit Cache and NAS to store the Go mod cache, which greatly accelerates CI pipeline creation.

You can directly use the predefined template or create a custom template based on the predefined template.

The predefined template consists of the following steps:

  1. Git Clone & Checkout

    • Clone the Git repository and check out the Git repository to the destination branch.

    • Obtain the commit ID, which is appended as a suffix to the image tag during image building.

  2. Run Go Test

    • Run all test cases (Go projects) in the Git repository by default.

    • You can set the pipeline parameter enable_test to specify whether to perform this step.

    • The Go mod cache is stored in the /pkg/mod directory of the NAS file system to accelerate Go Test and Go Build.

  3. Build & Push Image

    • Use BuildKit to build and push container images, and use caches of the registry type in BuildKit Cache to accelerate image building.

    • By default, the image tag is in the {container_tag}-{commit_id} format. You can specify whether to append the commit ID to the image tag when you submit the pipeline.

    • During image pushing, the latest version of the image is pushed to overwrite the current version.

Content of the predefined template:

View template content

apiVersion: argoproj.io/v1alpha1
kind: ClusterWorkflowTemplate
metadata:
  name: ci-go-v1
spec:
  entrypoint: main
  volumes:
  - name: run-test
    emptyDir: {}
  - name: workdir
    persistentVolumeClaim:
      claimName: pvc-nas
  - name: docker-config
    secret:
      secretName: docker-config
  arguments:
    parameters:
    - name: repo_url
      value: ""
    - name: repo_name
      value: ""
    - name: target_branch
      value: "main"
    - name: container_image
      value: ""
    - name: container_tag
      value: "v1.0.0"
    - name: dockerfile
      value: "./Dockerfile"
    - name: enable_suffix_commitid
      value: "true"
    - name: enable_test
      value: "true"
  templates:
    - name: main
      dag:
        tasks:
          - name: git-checkout-pr
            inline:
              container:
                image: alpine:latest
                command:
                  - sh
                  - -c
                  - |
                    set -eu
                    
                    apk --update add git
          
                    cd /workdir
                    echo "Start to Clone "{{workflow.parameters.repo_url}}
                    git -C "{{workflow.parameters.repo_name}}" pull || git clone {{workflow.parameters.repo_url}} 
                    cd {{workflow.parameters.repo_name}}
          
                    echo "Start to Checkout target branch" {{workflow.parameters.target_branch}}
                    git checkout --track origin/{{workflow.parameters.target_branch}} || git checkout {{workflow.parameters.target_branch}}
                    git pull
                    
                    echo "Get commit id" 
                    git rev-parse --short origin/{{workflow.parameters.target_branch}} > /workdir/{{workflow.parameters.repo_name}}-commitid.txt
                    commitId=$(cat /workdir/{{workflow.parameters.repo_name}}-commitid.txt)
                    echo "Commit id is got: "$commitId
                                        
                    echo "Git Clone and Checkout Complete."
                volumeMounts:
                - name: "workdir"
                  mountPath: /workdir
                resources:
                  requests:
                    memory: 1Gi
                    cpu: 1
                activeDeadlineSeconds: 1200
          - name: run-test
            when: "{{workflow.parameters.enable_test}} == true"
            inline: 
              container:
                image: golang:1.22-alpine
                command:
                  - sh
                  - -c
                  - |
                    set -eu
                    
                    if [ ! -d "/workdir/pkg/mod" ]; then
                      mkdir -p /workdir/pkg/mod
                      echo "GOMODCACHE Directory /pkg/mod is created"
                    fi
                    
                    export GOMODCACHE=/workdir/pkg/mod
                    
                    cp -R /workdir/{{workflow.parameters.repo_name}} /test/{{workflow.parameters.repo_name}} 
                    echo "Start Go Test..."
                    
                    cd /test/{{workflow.parameters.repo_name}}
                    go test -v ./...
                    
                    echo "Go Test Complete."
                volumeMounts:
                - name: "workdir"
                  mountPath: /workdir
                - name: run-test
                  mountPath: /test
                resources:
                  requests:
                    memory: 4Gi
                    cpu: 2
              activeDeadlineSeconds: 1200
            depends: git-checkout-pr    
          - name: build-push-image
            inline: 
              container:
                image: moby/buildkit:v0.13.0-rootless
                command:
                  - sh
                  - -c
                  - |         
                    set -eu
                     
                    tag={{workflow.parameters.container_tag}}
                    if [ {{workflow.parameters.enable_suffix_commitid}} == "true" ]
                    then
                      commitId=$(cat /workdir/{{workflow.parameters.repo_name}}-commitid.txt)
                      tag={{workflow.parameters.container_tag}}-$commitId
                    fi
                    
                    echo "Image Tag is: "$tag
                    echo "Start to Build And Push Container Image"
                    
                    cd /workdir/{{workflow.parameters.repo_name}}
                    
                    buildctl-daemonless.sh build \
                    --frontend \
                    dockerfile.v0 \
                    --local \
                    context=. \
                    --local \
                    dockerfile=. \
                    --opt filename={{workflow.parameters.dockerfile}} \
                    build-arg:GOPROXY=http://goproxy.cn,direct \
                    --output \
                    type=image,\"name={{workflow.parameters.container_image}}:${tag},{{workflow.parameters.container_image}}:latest\",push=true,registry.insecure=true \
                    --export-cache mode=max,type=registry,ref={{workflow.parameters.container_image}}:buildcache \
                    --import-cache type=registry,ref={{workflow.parameters.container_image}}:buildcache
                    
                    echo "Build And Push Container Image {{workflow.parameters.container_image}}:${tag} and {{workflow.parameters.container_image}}:latest Complete."
                env:
                  - name: BUILDKITD_FLAGS
                    value: --oci-worker-no-process-sandbox
                  - name: DOCKER_CONFIG
                    value: /.docker
                volumeMounts:
                  - name: workdir
                    mountPath: /workdir
                  - name: docker-config
                    mountPath: /.docker
                securityContext:
                  seccompProfile:
                    type: Unconfined
                  runAsUser: 1000
                  runAsGroup: 1000
                resources:
                  requests:
                    memory: 4Gi
                    cpu: 2
              activeDeadlineSeconds: 1200
            depends: run-test

The following table describes the parameters in the template.

Parameter

Description

Example

entrypoint

Specify the entry template.

main

repo_url

The URL of the Git repository.

https://github.com/ivan-cai/echo-server.git

repo_name

The name of the repository.

echo-server

target_branch

The destination branch of the repository.

Default value: main.

main

container_image

The image to be built. Format: <ACR EE Domain>/<ACR EE Namespace>/<Repository Name>.

test-registry.cn-hongkong.cr.aliyuncs.com/acs/echo-server

container_tag

The image tag.

Default: v1.0.0.

v1.0.0

dockerfile

The directory and name of the Dockerfile.

Specify the relative path in the root directory. Default: ./Dockerfile.

./Dockerfile

enable_suffix_commitid

Specify whether to append the commit ID to the image tag. Valid values:

  • true: Append.

  • false: Do not append.

Default value: true.

true

enable_test

Specify whether to run the Go Test step. Valid values:

  • true: Run the step.

  • false: Do not run the step.

Default value: true.

true

Prerequisites

Procedure

A public Git repository is used as an example to demonstrate how to create a CI pipeline. If you use a private Git repository, you need to first clone the private repository in the CI pipeline.

Important

The Secret that stores the credentials for accessing the container image and the NAS volume must belong to the namespace of the pipeline to be submitted.

Step 1: Create credentials in the workflow cluster to access the Container Registry Enterprise Edition instance

The credentials are used to pull images from BuildKit.

  1. Configure access credentials for the Container Registry Enterprise Edition instance. For more information, see Configure access credentials for a Container Registry Enterprise Edition instance.

  2. Run the following command to create a Secret in the workflow cluster to store the credentials. The credentials will be used by BuildKit.

    Replace $username:$password with the credentials used to access the Container Registry Enterprise Edition instance.

    kubectl create secret generic docker-config --from-literal="config.json={\"auths\": {\"$repositoryDomain\": {\"auth\": \"$(echo -n $username:$password|base64)\"}}}"

Step 2: Mount the NAS volume to the workflow cluster

The NAS volume is used to meet the following requirements:

  • Share data among tasks of the pipeline, such as information about the cloned repository.

  • Store the Go mod cache, which is used to accelerate the Go Test and Go Build steps in the CI pipeline.

Perform the following steps to mount the NAS volume to the workflow cluster:

  1. Obtain the mount target of the NAS file system. For more information, see Manage mount targets.

  2. Create a persistent volume (PV) and persistent volume claim (PVC) in the workflow cluster based on the following template. For more information, see Use NAS volumes.

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv-nas
      labels:
        alicloud-pvname: pv-nas
    spec:
      capacity:
        storage: 100Gi
      accessModes:
        - ReadWriteMany
      csi:
        driver: nasplugin.csi.alibabacloud.com
        volumeHandle: pv-nas   # Specify the name of the PV. 
        volumeAttributes:
          server: <your nas filesystem mount point address>
          path: "/"
      mountOptions:
      - nolock,tcp,noresvport
      - vers=3
    ---
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: pvc-nas
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 100Gi
      selector:
        matchLabels:
          alicloud-pvname: pv-nas

Step 3: Launch a pipeline based on the predefined template

Submit a pipeline in the console

  1. Log on to the ACK One console. In the left-side navigation pane, click Workflow Cluster.

  2. On the Workflow Cluster page, click the Basic Information tab. In the Common Operations section, click Workflow Console (Argo).

  3. In the Argo workbench, click Cluster Workflow Templates in the left-side navigation pane and click the predefined template named ci-go-v1.

    image

  4. On the template details page, click + SUBMIT in the upper-right corner. In the panel that appears, configure the parameters and click + SUBMIT.

    Refer to Template parameters and configure the parameters.

    image

    After you complete the configuration, you can view the status of the pipeline on the Workflows details page.

    image

Use the Argo CLI to submit a pipeline

  1. Create a file named workflow.yaml and copy the following content to the file. Refer to Template parameters and configure the parameters.

    apiVersion: argoproj.io/v1alpha1
    kind: Workflow
    metadata:
      generateName: ci-go-v1-
      labels:
        workflows.argoproj.io/workflow-template: ackone-ci
    spec:
      arguments:
        parameters:
        - name: repo_url
          value: https://github.com/ivan-cai/echo-server.git
        - name: repo_name
          value: echo-server
        - name: target_branch
          value: main
        - name: container_image
          value: "test-registry.cn-hongkong.cr.aliyuncs.com/acs/echo-server"
        - name: container_tag
          value: "v1.0.0"
        - name: dockerfile
          value: ./Dockerfile
        - name: enable_suffix_commitid
          value: "true"
        - name: enable_test
          value: "true"
      workflowTemplateRef:
        name: ci-go-v1
        clusterScope: true
  2. Run the following command to submit a pipeline:

    argo submit workflow.yaml