4.2 Argo CD

GitOps with Argo CD.

Introduction to GitOps

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.

Argo CD follows the GitOps pattern of using Git repositories as the source of truth for defining the desired application state. Kubernetes manifests can be specified in several ways:

  • kustomize applications
  • helm charts
  • ksonnet applications
  • jsonnet files
  • Plain directory of YAML/json manifests
  • Any custom config management tool configured as a config management plugin

Argo CD automates the deployment of the desired application states in the specified target environments. Application deployments can track updates to branches, tags, or pinned to a specific version of manifests at a Git commit. See tracking strategies for additional details about the different tracking strategies available.

For a quick 10 minute overview of Argo CD, check out the demo presented to the Sig Apps community meeting:

Task 4.2.1: Getting started

Login within the Web IDE

You can access Argo CD via Web UI (URL is provided by your teacher) or using the CLI. The Argo CD CLI Tool is already installed on the web IDE.

Since the sso login does not work inside the Web IDE for various reasons, your teacher will provide a generic local Argo CD account hannelore without any number.

argocd login argocd.techlab.openshift.ch --grpc-web --username hannelore

Task 4.2.2: Add Resources to a Git repository

As we are proceeding from now on according to the GitOps principle we need to push all existing resources located in <workspace>/*.yaml into a new Git repository. All the cli commands in this chapter must be executed in the terminal of the provided Web IDE.

Create an empty Git repository in Gitea. Visit https://gitea.techlab.openshift.ch/ with your browser and register a new account with your personal username and a password that you can remember ;)

Register new User in Gitea

Login with the new user and create a new Git repository with the Name gitops-resources.

The URL of the newly created Git repository will look like https://gitea.techlab.openshift.ch/<username>/gitops-resources.git

Git repository created

Change directory to the workspace where the yaml resources of the previous labs are located: cd <workspace>

Ensure that the LAB_USER environment variable is set.

echo $LAB_USER

If the result is empty, set the LAB_USER environment variable.

command hint
export LAB_USER=<username>

Configure your workspace folder to be a Git repository

git init

Configure the Git Client and verify the output

git config user.name "$LAB_USER"
git config user.email "foo@bar.org"
git config --local --list
git config --global credential.helper store

Now add the resource definitions to your personal Git repository and push them to remote. Use the password you entered when creating your Gitea user.

After the Git push command a password input field will apear at the top of the Web IDE. You need to enter your Gitea password there.

git add --all
git commit -m "Initial commit of resource definitions"
git remote add origin https://$LAB_USER@gitea.techlab.openshift.ch/$LAB_USER/gitops-resources.git
git push -u origin master

After a successful push you should see the following output

Enumerating objects: 15, done.
Counting objects: 100% (15/15), done.
Delta compression using up to 4 threads
Compressing objects: 100% (15/15), done.
Writing objects: 100% (15/15), 4.02 KiB | 4.02 MiB/s, done.
Total 15 (delta 1), reused 0 (delta 0)
remote: . Processing 1 references
remote: Processed 1 references in total
To https://gitea.techlab.openshift.ch/<username>/gitops-resources.git
 * [new branch]      master -> master

Go back to the webinterface of Gitea and inspect the structure and files in your personal Git repository: https://gitea.techlab.openshift.ch/<username>/gitops-resources

Task 4.2.3: Deploying the resources with Argo CD

Now we want to deploy the resources of the previous labs with Argo CD to demonstrate how Argo CD works.

Change to your main Project.

oc project $LAB_USER

To deploy the resources using the Argo CD CLI use the following command:

argocd app create argo-$LAB_USER --repo https://gitea.techlab.openshift.ch/$LAB_USER/gitops-resources.git --path '.' --dest-server https://kubernetes.default.svc --dest-namespace $LAB_USER

Expected output: application 'argo-<username>' created

Once the application is created, you can view its status:

argocd app get argo-$LAB_USER
$$Name: argo- Project: default Server: https://kubernetes.default.svc Namespace: URL: https://argocd.techlab.openshift.ch/applications/argo- Repo: https://gitea.techlab.openshift.ch//gitops-resources.git Target: Path: . SyncWindow: Sync Allowed Sync Policy: Sync Status: OutOfSync from (891cabc) Health Status: Missing GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE ConfigMap consumer-config OutOfSync PersistentVolumeClaim pipeline-workspace OutOfSync Healthy Service data-consumer OutOfSync Healthy Service data-producer OutOfSync Healthy apps Deployment data-consumer OutOfSync Healthy apps Deployment data-producer OutOfSync Healthy build.openshift.io BuildConfig data-producer OutOfSync image.openshift.io ImageStream data-producer OutOfSync kafka.strimzi.io Kafka amm-techlab OutOfSync kafka.strimzi.io KafkaTopic manual OutOfSync route.openshift.io Route data-consumer OutOfSync route.openshift.io Route data-producer OutOfSync tekton.dev Pipeline build-and-deploy OutOfSync tekton.dev Task apply-manifests OutOfSync template.openshift.io Template pipeline-run-template OutOfSync Missing$$

The application status is initially in OutOfSync state. To sync (deploy) the resource manifests, run:

argocd app sync argo-$LAB_USER

This command retrieves the manifests from the git repository and performs a kubectl apply on them. Because all our manifests have been deployed manually before, no new rollout of them will be triggered on OpenShift. But from now on, all resources are managed by Argo CD. Congrats, the first step in direction GitOps! :)

Check the Argo CD UI to browse the application and their components: https://argocd.techlab.openshift.ch

Argo CD App overview

Application Tree

Or use the CLI to check the state of the Argo CD application:

argocd app get argo-$LAB_USER

which gives you an output similar to this:

$$Name: argo- Project: default Server: https://kubernetes.default.svc Namespace: URL: https://argocd.techlab.openshift.ch/applications/argo- Repo: https://gitea.techlab.openshift.ch//gitops-resources.git Target: Path: . SyncWindow: Sync Allowed Sync Policy: Sync Status: Synced to (891cabc) Health Status: Healthy GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE ConfigMap consumer-config Synced configmap/consumer-config configured PersistentVolumeClaim pipeline-workspace Synced Healthy persistentvolumeclaim/pipeline-workspace configured Service data-consumer Synced Healthy service/data-consumer configured Service data-producer Synced Healthy service/data-producer configured apps Deployment data-producer Synced Healthy deployment.apps/data-producer configured apps Deployment data-consumer Synced Healthy deployment.apps/data-consumer configured kafka.strimzi.io Kafka amm-techlab Synced kafka.kafka.strimzi.io/amm-techlab configured tekton.dev Task apply-manifests Synced task.tekton.dev/apply-manifests configured tekton.dev Pipeline build-and-deploy Synced pipeline.tekton.dev/build-and-deploy configured route.openshift.io Route data-consumer Synced route.route.openshift.io/data-consumer configured build.openshift.io BuildConfig data-producer Synced buildconfig.build.openshift.io/data-producer configured route.openshift.io Route data-producer Synced route.route.openshift.io/data-producer configured image.openshift.io ImageStream data-producer Synced imagestream.image.openshift.io/data-producer configured kafka.strimzi.io KafkaTopic manual Synced kafkatopic.kafka.strimzi.io/manual configured template.openshift.io Template pipeline-run-template Synced template.template.openshift.io/pipeline-run-template created$$

Task 4.2.4: Automated Sync Policy and Diff

When there is a new commit in your Git repository, the Argo CD application becomes OutOfSync. Let’s assume we want to scale up our producer of the previous lab from 1 to 2 replicas. We will change this in the Deployment.

Change the number of replicas in your file <workspace>/producer.yaml.

$$
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: data-producer
    application: amm-techlab
  name: data-producer
spec:
  replicas: 2
  selector:
    matchLabels:
      deployment: data-producer
  strategy:
    type: Recreate
...
$$

Commit the changes and push them to the remote:

git add . && git commit -m 'Scaled up to 2 replicas' && git push

Don’t forget to interactively provide your personal Git password. After a successful push you should see a message similar to the following lines:

$$[master 18daed3] Scaled up to 2 replicas 1 file changed, 1 insertion(+), 1 deletion(-) Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 372 bytes | 372.00 KiB/s, done. Total 4 (delta 2), reused 0 (delta 0) remote: . Processing 1 references remote: Processed 1 references in total To https://gitea.techlab.openshift.ch//gitops-resources.git fe4e2b6..18daed3 master -> master$$

Check the state of the resources by cli:

argocd app get argo-$LAB_USER --refresh

The parameter --refresh triggers an update against the Git repository. Out of the box Git will be polled by Argo CD. To use a synchronous workflow you can use webhooks in Git. These will trigger a synchronization in Argo CD on every push to the repository.

You will see that the data-producer is OutOfSync:

$$... GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE ConfigMap consumer-config Synced configmap/consumer-config configured PersistentVolumeClaim pipeline-workspace Synced Healthy persistentvolumeclaim/pipeline-workspace configured Service data-consumer Synced Healthy service/data-consumer configured Service data-producer Synced Healthy service/data-producer configured apps Deployment data-producer OutOfSync Healthy deployment.apps/data-producer configured apps Deployment data-consumer Synced Healthy deployment.apps/data-consumer configured ...$$

When an application is OutOfSync then your deployed ’live state’ is no longer the same as the ’target state’ which is represented by the resource manifests in the Git repository. You can inspect the differences between live and target state by cli:

argocd app diff argo-$LAB_USER

which should give you an output similar to:

$$===== apps/Deployment /data-producer ====== 155c155 < replicas: 1 --- > replicas: 2$$

Now open the web console of Argo CD and go to your application. The deployment data-producer is marked as ‘OutOfSync’:

Application Out-of-Sync

With a click on Deployment > Diff you will see the differences:

Application Differences

Now click Sync on the top left and let the magic happens ;) The producer will be scaled up to 2 replicas and the resources are in Sync again.

Double-check the status by cli

argocd app get argo-$LAB_USER
$$... GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE ConfigMap consumer-config Synced configmap/consumer-config unchanged PersistentVolumeClaim pipeline-workspace Synced Healthy persistentvolumeclaim/pipeline-workspace unchanged Service data-producer Synced Healthy service/data-producer unchanged Service data-consumer Synced Healthy service/data-consumer unchanged apps Deployment data-consumer Synced Healthy deployment.apps/data-consumer unchanged apps Deployment data-producer Synced Progressing deployment.apps/data-producer configured kafka.strimzi.io Kafka amm-techlab Synced kafka.kafka.strimzi.io/amm-techlab unchanged ...$$

Argo CD can automatically sync an application when it detects differences between the desired manifests in Git, and the live state in the cluster. A benefit of automatic sync is that CI/CD pipelines no longer need direct access to the Argo CD API server to perform the deployment. Instead, the pipeline makes a commit and push to the Git repository with the changes to the manifests in the tracking Git repo.

To configure automatic sync run (or use the UI):

argocd app set argo-$LAB_USER --sync-policy automated

From now on Argo CD will automatically synchronize resources every time you commit to the Git repository.

Task 4.2.5: Automatic Self-Healing

By default, changes made to the live cluster will not trigger automatic sync. To enable automatic sync when the live cluster’s state deviates from the state defined in Git, run:

argocd app set argo-$LAB_USER --self-heal

Watch the deployment data-producer in a separate terminal

oc get deployment data-producer -w

Let’s scale our data-producer Deployment and observe whats happening:

oc scale deployment data-producer --replicas=1

Argo CD will immediately scale back the data-producer Deployment to 2 replicas. You will see the desired replicas count in the watched Deployment.

$$NAME READY UP-TO-DATE AVAILABLE AGE data-producer 2/2 2 2 78m data-producer 2/1 2 2 78m data-producer 2/1 2 2 78m data-producer 1/1 1 1 78m data-producer 1/2 1 1 78m data-producer 1/2 1 1 78m data-producer 1/2 1 1 78m data-producer 1/2 2 1 78m data-producer 2/2 2 2 78m$$

Task 4.2.7: Pruning

You probably asked yourself how can I delete deployed resources on the container platform? Argo CD can be configured to delete resources that no longer exist in the Git repository.

First delete the file imageStream.yaml from Git repository and push the changes

git rm imageStream.yaml
git add --all && git commit -m 'Removes ImageStream' && git push

Check the status of the application with

argocd app get argo-$LAB_USER --refresh

You will see that even with auto-sync and self-healing enabled the status is still OutOfSync

$$GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE ... build.openshift.io BuildConfig data-producer Synced image.openshift.io ImageStream data-producer OutOfSync kafka.strimzi.io Kafka amm-techlab Synced ...$$

Now enable the auto pruning explicitly:

argocd app set argo-$LAB_USER --auto-prune

Recheck the status again

argocd app get argo-$LAB_USER --refresh

Now the ImageStream was successfully deleted by Argo CD.

$$GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE ... image.openshift.io ImageStream data-producer Succeeded Pruned pruned Service data-producer Synced Healthy service/data-producer unchanged Service data-consumer Synced Healthy service/data-consumer unchanged apps Deployment data-producer Synced Healthy deployment.apps/data-producer unchanged ...$$

Task 4.2.8: Manage Tekton managed manifest with ArgoCD

In the previous Lab we’ve created our first tekton pipeline. The apply-manifests task applies a set of manifests to the namespace, within a pipeline run. Since we don’t want our manifests to be managed in two different ways (tekton and argocd) for simplicity reasons, we copy the tekton managed manifests to our workspace and push them to our git repository.

Let’s create the <workspace>/data-transformer.yaml resource within our workspace and push it to the git repository.

apiVersion: v1
kind: List
metadata:
  labels:
    application: amm-techlab
items:
  - apiVersion: image.openshift.io/v1
    kind: ImageStream
    metadata:
      labels:
        app: data-transformer
        application: amm-techlab
      name: data-transformer
    spec:
      lookupPolicy:
        local: true

  - apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: data-transformer
        application: amm-techlab
      name: data-transformer
    spec:
      replicas: 1
      selector:
        matchLabels:
          deployment: data-transformer
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: data-transformer
            application: amm-techlab
            deployment: data-transformer
        spec:
          containers:
            - image: image-registry.openshift-image-registry.svc:5000/<username>/data-transformer:latest
              imagePullPolicy: Always
              livenessProbe:
                failureThreshold: 5
                httpGet:
                  path: /health
                  port: 8080
                  scheme: HTTP
                initialDelaySeconds: 3
                periodSeconds: 20
                successThreshold: 1
                timeoutSeconds: 15
              readinessProbe:
                failureThreshold: 5
                httpGet:
                  path: /health
                  port: 8080
                  scheme: HTTP
                initialDelaySeconds: 3
                periodSeconds: 20
                successThreshold: 1
                timeoutSeconds: 15
              name: data-transformer
              env:
                - name: kafka.bootstrap.servers
                  value: 'amm-techlab-kafka-bootstrap:9092'
                - name: mp.messaging.incoming.data.connector
                  value: smallrye-kafka
                - name: mp.messaging.incoming.data.topic
                  value: manual
                - name: mp.messaging.incoming.data.value.deserializer
                  value: >-
                    ch.puzzle.quarkustechlab.reactivetransformer.control.SensorMeasurementDeserializer
                - name: transformer.jaeger.enabled
                  value: 'false'
              ports:
              - containerPort: 8080
                name: http
                protocol: TCP
              resources:
                limits:
                  cpu: '1'
                  memory: 500Mi
                requests:
                  cpu: 50m
                  memory: 100Mi

  - apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: data-transformer
        application: amm-techlab
      name: data-transformer
    spec:
      ports:
        - name: http
          port: 8080
          protocol: TCP
          targetPort: http
      selector:
        deployment: data-transformer
      sessionAffinity: None
      type: ClusterIP
git add data-transformer.yaml && git commit -m 'Add Transformer Manifest' && git push

Advanced resource management

In this lab we manage our OpenShift resources with plain yaml files. Doing it this way is limited.

As mentioned in the GitOps introduction, ArgoCD supports several tools to define the resources. For more advanced use cases kustomize or helm charts are the preferred tools. They use inheritance or external values files to adapt the yaml resources to the different environments.