author-pic

Amila Senadheera

Tech enthusiast

GitOps using Argo CD


Published on July 20, 2023

When you have an application deployed in a k8s environment, all the artifacts are version controlled in a version-control system like GitHub as a best practice. But who do apply these declarative manifests? In the previous blog posts, I apply all the artifacts manually. It is not a very scalable approach. We can automate the artifact syncing process. GitOps methodology uses the artifacts in the version control system as a single source of truth and automates the application deployment and management in k8s environments. Argo CD is one of the GitOps tools and it is also a CNCF Graduated project.

When you have properly set up a deployment pipeline like this, once the deployment artifacts are updated to reflect the new state after going through the usual code review for the PR (for example changing the image to a new version). Once the authorized person commits the changes, Argo CD will detect the updates and takes care of synching the artifacts to the predefined destination clusters. In this post, I will show you how to set up Argo CD in a k8s cluster and do a simple application deployment.

Installing Argo CD

Apply the following artifacts to your k8s environment:

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

This will basically install a complete set of artifacts needed to run Argo CD. You can see a list of all the features it comes with here.

Argo CD comes with a very nice web UI where you can view what's going on with your applications. You can access it via the service/argocd-server in argocd namespace. It is by default installed as a ClusterIP service. We can change it to a NodePort by patching it:

kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'

Get the default password saved in secrets/argocd-initial-admin-secret.

kubectl get secret -n argocd argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d

Use the NodePort populated in service/argocd-server and IP address of one of the worker nodes to access it in a browser. Log in with the username as admin and with the password we retrieved above.

Create a Repository source in Argo CD

Since I have a private repository containing the artifacts of the application I need to generate a fine-grained GitHub access token only for that repository with read-only scopes. Don't directly use your GitHub password to give full access. If some intruder managed to get into your cluster then they will delete your repos at the worst-case scenario.

Go to Settings -> Repositories -> Connect Repo, Use the following feild to setup the repo:

Feild Value
Choose your connection method: VIA HTTPS
Type git
Repository URL https://github.com/usename/reponame.git
Username GitHub username
Password Fine grained Github token you retrieved

Click Connect to create it. You should be able to see a repo connection with successful status.

These repo access details are saved in a secret in argocd namespace you can view its content below:

k get secret -n argocd repo-<random-number> -o yaml
apiVersion: v1
data:
  password: aGFoYSwgSSBleHBlY3QgeW91IGhlcmUuIFlvdSBjb29sIGxpdHRsZSBoYWNrZXIK
  project: ZGVmYXVsdA==
  type: Z2l0
  url: aHR0cHM6Ly9naXRodWIuY29tLzx1c2VybmFtZT4vPHJlcG9uYW1lPi5naXQK
  username: PHVzZXJuYW1lPgo=
kind: Secret
metadata:
  annotations:
    managed-by: argocd.argoproj.io
  labels:
    argocd.argoproj.io/secret-type: repository
  name: repo-<random-number>
  namespace: argocd
type: Opaque

Create an Argo Application

We need to point to the application artifacts directory in the repo for Argo to keep looking for declarative artifact changes. I have created a repo that has a k8s Deployment and a Service in the path kubernetes/apps/myapp.

Now go to Applications -> New App. Give the details for the following fields:

Feild Value
Application Name myapp
SYNC POLICY Automatic -> SELF HEAL
SOURCE > Repository URL Select the previous repo we created from the drop-down
SOURCE > Path Give the relative path to the artifacts folder. Ex: kubernetes/apps/my-app
DESTINATION > Cluster URL Select the cluster URL which is https://kubernetes.default.svc
DESTINATION > Namespace Your application namespace

Click on Create to create the application. You can see the application state changes Syncing -> Synced. If you check the namespace you defined above, it has deployed. Since we select the Self Heal policy above even if you delete the deployment from the environment directly, it will create the deployment again by looking at the deployment artifact in the repository path. It is clear Argo is utilizing operator pattern and its desired state is retrieved from an external source which is the artifacts in a git repository.

We can actually have a look at the Argo CD Application CRs:

k get applications.argoproj.io -n argocd -o yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd
spec:
  destination:
    namespace: default
    server: https://kubernetes.default.svc
  project: default
  source:
    path: kubernetes/apps/myapp
    repoURL: https://github.com/usename/reponame.git
    targetRevision: HEAD
  syncPolicy:
    automated:
      selfHeal: true
status:
    ...
    ...
    syncResult:
      resources:
      - group: ""
        hookPhase: Running
        kind: Service
        message: service/my-app created
        name: my-app-svc
        namespace: default
        status: Synced
        syncPhase: Sync
        version: v1
      - group: apps
        hookPhase: Running
        kind: Deployment
        message: deployment.apps/my-app created
        name: my-app
        namespace: default
        status: Synced
        syncPhase: Sync
        version: v1
      revision: 4517874a2f4b5121822e7932e86d3b9aa41acff3
      source:
        path: kubernetes/apps/my-app
        repoURL: https://github.com/username/reponame.git
        targetRevision: HEAD
  ...
  ...
  sync:
    comparedTo:
      destination:
        namespace: default
        server: https://kubernetes.default.svc
      source:
        path: kubernetes/apps/myapp
        repoURL: https://github.com/username/reponame.git
        targetRevision: HEAD
    status: Synced

The status.syncResult field shows which k8s artifacts were synced to the cluster. According to the docs, Argo checks the status every 3 minutes. You can also use Github Webhooks instead of the default polling check.

I just barely touched very basic aspects of Argo CD, it is so powerful, and many companies have adopted the flexibility of Argo CD. There is a lot to explore in the GitOps space.

Hope you enjoy reading this article and learned something.

Thanks for reading!

If you like it, share it!


Created by potrace 1.16, written by Peter Selinger 2001-2019 © 2024 Developer Diary.

Made withusing Gatsby, served to your browser from a home grown Raspberry Pi cluster.
contact-me@developerdiary.me