Cloud Native 17 min read

Transform Tekton CI/CD into a GitOps Workflow with Argo CD

This guide shows how to refactor a Tekton CI/CD pipeline by extracting Helm chart templates into a separate repository, configuring Argo CD to manage the deployment stage, and adding Tekton tasks that update Helm values, sync the application, and handle health checks, achieving a full GitOps workflow on Kubernetes.

Ops Development Stories
Ops Development Stories
Ops Development Stories
Transform Tekton CI/CD into a GitOps Workflow with Argo CD

Previously we used Tekton to implement the CI/CD pipeline, but the CD stage was performed within Tekton tasks. Now we redesign the pipeline to use GitOps, delegating the CD part to Argo CD.

First, extract the Helm Chart templates from the project

http://git.k8s.local/course/devops-demo.git

into a dedicated repository

http://git.k8s.local/course/devops-demo-deploy

. This repository will contain only the Helm chart used for application deployment, making it easier to integrate with Argo CD.

Add the new repository to Argo CD, then create a new Application. First, define an

AppProject

CRD, which groups applications logically and includes the following key fields:

sourceRepos

: repositories from which the applications can fetch manifests.

destinations

: target clusters and namespaces for deployment.

roles

: role definitions for resource access within the project.

<code>apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: demo
  namespace: argocd
spec:
  destinations:
  - namespace: '*'
    server: https://kubernetes.default.svc
  sourceRepos:
  - http://git.k8s.local/course/devops-demo-deploy.git
</code>

After creating the project, define an

Application

that points to the Helm chart:

<code>apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: devops-demo
  namespace: argocd
spec:
  destination:
    namespace: default
    server: 'https://kubernetes.default.svc'
  project: demo
  source:
    path: helm
    repoURL: 'http://git.k8s.local/course/devops-demo-deploy.git'
    targetRevision: HEAD
    helm:
      parameters:
      - name: replicaCount
        value: '2'
      valueFiles:
      - my-values.yaml
</code>

The application will initially be in

OutOfSync

because it has not been deployed yet.

Next, modify the original Tekton pipeline to remove the

deploy

and

rollback

tasks, since deployment will now be handled by Argo CD. After the Docker image is built and pushed, a new task updates the Helm values file and triggers Argo CD synchronization.

<code># pipeline.yaml (excerpt)
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: pipeline
spec:
  workspaces:
  - name: go-repo-pvc
  params:
  - name: git_url
  - name: git_infra_url
  - name: revision
    type: string
    default: "master"
  - name: image
  - name: image_tag
  - name: registry_url
    type: string
    default: "harbor.k8s.local"
  - name: registry_mirror
    type: string
    default: "https://ot2k4d59.mirror.aliyuncs.com/"
  - name: git_manifest_dir
    default: "helm"
  - name: argocd_url
  - name: argocd_secret
  - name: app_name
  - name: app_revision
    type: string
    default: "HEAD"
  tasks:
  - name: clone
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: go-repo-pvc
    params:
    - name: url
      value: $(params.git_url)
    - name: revision
      value: $(params.revision)
  - name: test
    taskRef:
      name: test
  - name: build
    taskRef:
      name: build
    runAfter:
    - test
    - clone
    workspaces:
    - name: go-repo
      workspace: go-repo-pvc
  - name: docker
    taskRef:
      name: docker
    runAfter:
    - build
    workspaces:
    - name: go-repo
      workspace: go-repo-pvc
    params:
    - name: image
      value: $(params.image):$(params.image_tag)
    - name: registry_url
      value: $(params.registry_url)
    - name: registry_mirror
      value: $(params.registry_mirror)
  - name: manifests
    taskRef:
      name: change-manifests
    runAfter:
    - docker
    params:
    - name: git_url
      value: $(params.git_infra_url)
    - name: git_manifest_dir
      value: $(params.git_manifest_dir)
    - name: image_tag
      value: $(params.image_tag)
  - name: sync
    taskRef:
      name: sync
    runAfter:
    - manifests
    params:
    - name: argocd_url
      value: $(params.argocd_url)
    - name: argocd_secret
      value: $(params.argocd_secret)
    - name: app_name
      value: $(params.app_name)
    - name: app_revision
      value: $(params.app_revision)
</code>

The new

sync

task logs into Argo CD and runs

argocd app sync

followed by

argocd app wait

to ensure the application reaches a healthy state.

<code>apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: sync
spec:
  volumes:
  - name: argocd-secret
    secret:
      secretName: $(inputs.params.argocd_secret)
  params:
  - name: argocd_url
    description: "The URL of the ArgoCD server"
  - name: argocd_secret
    description: "Secret containing username and password for Argo CD"
  - name: commit_id
    description: "The commit ID to update"
  - name: app_name
    description: "The name of the Argo CD application"
  - name: app_revision
    default: "HEAD"
    description: "Revision of the application"
  steps:
  - name: deploy
    image: argoproj/argocd
    volumeMounts:
    - name: argocd-secret
      mountPath: /var/secret
    command:
    - sh
    args:
    - -ce
    - |
      set -e
      echo "update commit id"
      argocd login --insecure $(params.argocd_url) --username $(/bin/cat /var/secret/username) --password $(/bin/cat /var/secret/password)
      argocd app sync $(params.app_name) --revision $(params.app_revision)
      argocd app wait $(params.app_name) --health
</code>

To modify the Helm

values.yaml

file directly, we add a

change-manifests

task that clones the repo, updates

image.tag

using

yq

, commits, and pushes the change.

<code>apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: change-manifests
spec:
  params:
  - name: git_url
    description: Git repository containing manifest files to update
  - name: git_email
    default: [email protected]
  - name: git_name
    default: Tekton Pipeline
  - name: git_manifest_dir
    description: Manifests files directory
  - name: tool_image
    default: cnych/helm-kubectl-curl-git-jq-yq
  - name: image_tag
    description: Deploy docker image tag
  steps:
  - name: git-push
    image: $(params.tool_image)
    env:
    - name: GIT_USERNAME
      valueFrom:
        secretKeyRef:
          name: gitlab-auth
          key: username
          optional: true
    - name: GIT_PASSWORD
      valueFrom:
        secretKeyRef:
          name: gitlab-auth
          key: password
          optional: true
    command: ["/bin/bash"]
    args:
    - -c
    - |
      set -eu
      git config --global user.email "$(params.git_email)"
      git config --global user.name "$(params.git_name)"
      git clone --branch master --depth 1 http://${GIT_USERNAME}:${GIT_PASSWORD}@$(params.git_url) repo
      cd "repo/$(params.git_manifest_dir)"
      yq w --inplace my-values.yaml 'image.tag' "$(params.image_tag)"
      if ! git diff-index --quiet HEAD --; then
        git add .
        git commit -m "helm values updated by tekton pipeline in change-manifests task"
        git push
      else
        echo "no changes, git repository is up to date"
      fi
</code>

Finally, create a secret for Argo CD login:

<code>apiVersion: v1
kind: Secret
metadata:
  name: argocd-auth
type: Opaque
stringData:
  username: admin
  password: admin321
</code>

Update the Tekton TriggerTemplate to launch the pipeline with the new parameters.

<code># gitlab-template.yaml
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
  name: gitlab-template
spec:
  params:
  - name: gitrevision
  - name: gitrepositoryurl
  resourcetemplates:
  - apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
      generateName: gitlab-run-
    spec:
      serviceAccountName: tekton-build-sa
      pipelineRef:
        name: pipeline
      workspaces:
      - name: go-repo-pvc
        persistentVolumeClaim:
          claimName: go-repo-pvc
      params:
      - name: git_url
        value: $(tt.params.gitrepositoryurl)
      - name: git_infra_url
        value: git.k8s.local/course/devops-demo-deploy.git
      - name: image
        value: "harbor.k8s.local/course/devops-demo"
      - name: image_tag
        value: "$(tt.params.gitrevision)"
      - name: argocd_url
        value: argocd.k8s.local
      - name: argocd_secret
        value: argocd-auth
      - name: app_name
        value: devops-demo
</code>

Argo CD’s default health check for

Ingress

resources may fail because the

status.loadBalancer.ingress

list is empty. To fix this, customize the health check using Lua in the

argocd-cm

ConfigMap:

<code># Edit ConfigMap argocd-cm
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations: |
    extensions/Ingress:
      health.lua: |
        hs = {}
        hs.status = "Healthy"
        return hs
</code>

After applying the customization, the application shows a healthy status in the Argo CD UI. Rollbacks can be performed directly from the UI using the "HISTORY AND ROLLBACK" feature.

The final pipeline run can be inspected with

tkn pr describe

, showing all tasks, parameters, and workspaces.

Overall, this workflow demonstrates how to combine Tekton and Argo CD to achieve a streamlined GitOps CI/CD pipeline on Kubernetes.

ci/cdkubernetesGitOpsHelmArgo CDTekton
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.