Operations 16 min read

Boost CI/CD Speed with Jenkins, Argo CD & Argo Rollouts: Canary Deploys & Tagging

This guide shows how to combine Jenkins with Argo CD and Argo Rollouts to create a fast, automated CI/CD pipeline that speeds up Argo CD triggers, performs canary releases, and automatically tags GitLab repositories for version control.

Ops Development Stories
Ops Development Stories
Ops Development Stories
Boost CI/CD Speed with Jenkins, Argo CD & Argo Rollouts: Canary Deploys & Tagging

This article explains how to use Jenkins together with Argo CD and Argo Rollouts to implement a CI/CD pipeline, covering faster Argo CD triggers, canary releases, and automatic GitLab tagging.

Optimizing Argo CD Trigger Speed

Argo CD polls the Git repository every three minutes, which adds latency. To eliminate this delay, configure the API server to receive webhook events. Argo CD supports GitHub, GitLab, Bitbucket, and other providers; the example uses GitLab.

(1) Configure the webhook token in Argo CD:

<code>kubectl edit secret argocd-secret -n argocd</code>
<code>apiVersion: v1
kind: Secret
metadata:
  name: argocd-secret
  namespace: argocd
type: Opaque
stringData:
  # gitlab webhook secret
  webhook.gitlab.secret: coolops
</code>

After saving, a secret is generated:

<code># kubectl describe secret argocd-secret -n argocd
Name:          argocd-secret
Namespace:     argocd
Type:          Opaque
Data
====
webhook.gitlab.secret: 7 bytes
</code>

(2) Configure the webhook in the GitLab repository (screenshot).

Because the cluster uses an invalid internal certificate, disable SSL verification in the webhook settings.

Test the webhook; a successful test confirms correct configuration.

Now any commit to GitLab will trigger Argo CD immediately.

Using Argo Rollouts for Canary Releases

Install Argo Rollouts in the Kubernetes cluster:

<code>kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml
</code>

Install the kubectl plugin for Argo Rollouts:

<code>curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-linux-amd64
chmod +x ./kubectl-argo-rollouts-linux-amd64
mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts
</code>

Define the rollout and service manifests:

<code>apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-simple-java
spec:
  replicas: 3
  strategy:
    canary:
      canaryService: rollouts-simple-java-canary
      stableService: rollouts-simple-java-stable
      trafficRouting:
        nginx:
          stableIngress: rollouts-simple-java-stable
      steps:
      - setWeight: 20
      - pause: {duration: 60}
      - setWeight: 50
      - pause: {duration: 10}
      - setWeight: 80
      - pause: {duration: 10}
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: rollouts-simple-java
  template:
    metadata:
      labels:
        app: rollouts-simple-java
    spec:
      containers:
      - name: myapp
        image: registry.cn-hangzhou.aliyuncs.com/rookieops/myapp:latest
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /hello
            port: 8080
          initialDelaySeconds: 60
          periodSeconds: 15
        readinessProbe:
          httpGet:
            path: /hello
            port: 8080
          periodSeconds: 15
</code>
<code>apiVersion: v1
kind: Service
metadata:
  name: rollouts-simple-java-canary
spec:
  ports:
  - port: 8080
    targetPort: http
    protocol: TCP
    name: http
  selector:
    app: rollouts-simple-java
---
apiVersion: v1
kind: Service
metadata:
  name: rollouts-simple-java-stable
spec:
  ports:
  - port: 8080
    targetPort: http
    protocol: TCP
    name: http
  selector:
    app: rollouts-simple-java
</code>
<code>apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: rollouts-simple-java-stable
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: rollouts-simple-java.coolops.cn
    http:
      paths:
      - path: /
        backend:
          serviceName: rollouts-simple-java-stable
          servicePort: 8080
</code>
<code>commonLabels:
  app: rollouts-simple-java
resources:
- rollout.yaml
- services.yaml
- ingress.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: registry.cn-hangzhou.aliyuncs.com/rookieops/myapp
  newTag: "latest"
namespace: dev
</code>

Commit these files to the GitLab repository and let Argo CD sync them.

Tagging the Code Repository

Tagging provides a snapshot of the repository, allowing easy retrieval of specific versions without searching commit IDs.

The following Groovy script uses the GitLab API to obtain a project ID and create a tag:

<code>package org.devops

// HTTP request wrapper
def HttpReq(reqType, reqUrl, reqBody){
    def gitServer = "http://172.17.100.135:32080/api/v4"
    withCredentials([string(credentialsId: 'gitlab-token', variable: 'gitlabToken')]){
        result = httpRequest(
            customHeaders: [[maskValue: true, name: 'PRIVATE-TOKEN', value: "${gitlabToken}"]],
            httpMode: reqType,
            contentType: "APPLICATION_JSON",
            ignoreSslErrors: true,
            requestBody: reqBody,
            url: "${gitServer}/${reqUrl}"
        )
    }
    return result
}

// Get project ID by name
def GetProjectID(projectName){
    def projectApi = "projects?search=${projectName}"
    def response = HttpReq('GET', projectApi, '')
    def result = readJSON text: "${response.content}"
    for(repo in result){
        if(repo['path'] == "${projectName}"){
            return repo['id']
        }
    }
    return null
}

// Create a tag in GitLab
def TagGitlab(projectId, tag_name, tag_ref){
    def apiUrl = "projects/${projectId}/repository/tags"
    def reqBody = "{\"tag_name\": \"${tag_name}\", \"ref\": \"${tag_ref}\"}"
    HttpReq('POST', apiUrl, reqBody)
}
</code>

In the Jenkins pipeline, after a successful deployment, the

TagGitlab

stage calls these methods when the user confirms continuation:

<code>stage('TagGitlab') {
    steps {
        script {
            if ("${isUpdate}" == 'yes' && "${gitBranch}" == 'master') {
                repo_id = gitlab.GetProjectID("${repo_name}")
                tag_name = "release-${tools.getTime()}"
                gitlab.TagGitlab("${repo_id}", "${tag_name}", 'master')
            } else {
                echo 'No tag created'
            }
        }
    }
}
</code>

Final Notes

Argo CD and Argo Rollouts work well together, but keep backups of the YAML files used by Argo CD because the system is stateless and configmaps may be cleared. Also note that Argo Rollouts currently supports only Ingress and ALB for traffic routing.

ci/cdkubernetesGitLabJenkinsCanary DeploymentArgo CDArgo Rollouts
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.