Getting started with a local Argo CD stack

Published on May 21, 2024

Argo CD synchronises the resources in our k8s cluster with a desired state defined in a Git repository. This allows us to declare the desired state instead of explicitly deploying and updating resources. Argo CD will take care of applying updates to ensure that the apps in our cluster are in the desired state.

The approach

Let's install Argo CD into a new cluster and synchronise resources with a local Git server. In a typical Argo CD installation we'd reference a hosted Git repository outside of the cluster, however for the purpose of this demo we'll quickly install a Gitea server inside the cluster so that we can explicitly see all the configuration and readily clean up at the end.

Let's start by installing our cluster with k3d.

k3d cluster create my-cluster

Create a Git repository

To start using Argo CD we need a Git repository that holds the desired state of the resources in the k8s cluster. We can create a local in-cluster Git service, or if you prefer you can use your favourite hosted Git service. I'll use a local in-cluster Git service, but if you're hosting your repository elsewhere, set the Git URL accordingly.

Let's define a lightweight k8s resource that will be deployed with Argo CD and push it to our Git repository where Argo CD will be able to access it.

mkdir nginx
cat << EOF > nginx/pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx:latest
      ports:
        - containerPort: 80
EOF
git add .
git commit -m "k8s resource for Argo CD testing"
git push

Install Argo CD command line

The Argo CD command line is convenient way to interact with the Argo CD API and an alternative to clicking the operations in with the UI. You can do most operations with either, but let's go with the CLI to help us codify our steps. Let's install it with brew, or you installer of choice.

brew install argocd

Install Argo CD Helm chart

Install Argo CD service with Helm into a specific argocd namespace.

helm repo add argo https://argoproj.github.io/argo-helm
helm install my-argo-cd argo/argo-cd \
    --namespace argocd --create-namespace

Port forward onto this Argo CD server so we can access it from local.

kubectl port-forward service/my-argo-cd-argocd-server -n argocd 8080:443 &

Get the Argo CD admin initial password with:

argocd admin initial-password -n argocd | head -n 1 | pbcopy

Or if don't have the Argo CD command line installed and wish to log into the Argo CD web UI you can get it directly from the k8s secret with:

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

Login with the Argo CD command line with the admin user and the password from above.

argocd login localhost:8080

Note that once you have logged into an Argo CD instance the local Argo CD context configuration is located at ~/.config/argocd/config.

Create a test application

Create a new namespace where we will configure Argo CD to deploy resources to.

kubectl create namespace demo

And create an app in Argo CD with command line:

argocd app create nginx \
  --repo http://gitea-http.git.svc.cluster.local:3000/bob/gitops.git \
  --path nginx \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace demo

You can also create this app with the Argo CD UI, by visiting https://localhost:8080/ and log in with admin user and the password from above.

We can now view the status of the new app with:

argocd app get nginx

Which should show something like:

Name:               argocd/nginx
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          demo
URL:                https://argocd.example.com/applications/nginx
Source:
- Repo:             http://gitea-http.git.svc.cluster.local:3000/bob/gitops.git
  Target:
  Path:             nginx
SyncWindow:         Sync Allowed
Sync Policy:        Manual
Sync Status:        OutOfSync from  (7877278)
Health Status:      Missing

GROUP  KIND  NAMESPACE  NAME   STATUS     HEALTH   HOOK  MESSAGE
       Pod   demo       nginx  OutOfSync  Missing

We can sync the app manually with:

argocd app sync nginx

And should see the nginx pod deployed:

kubectl get pods -n demo

Automated synchronisation

We often want Argo CD to automatically synchronise our resources. We can turn this on with:

argocd app set nginx --sync-policy automated

By default Argo CD will synchronise ever 3 minutes, as per the timeout.reconcilliation value in the argocd-cm config map.

Making a k8s resource change

Now let's make a change to the pod resource yaml in Git and see Argo CD apply the change. Edit the k8s resource and push to the Git repository, for example add a label

metadata:
  name: nginx
  labels:
    environment: dev

Argo CD should automatically synchronise the pod configuration after a few minutes. You can see whether that has happened with:

argocd app get nginx

And once it has you should be able to see the port change with

kubectl -n demo get pod nginx -o jsonpath="{.metadata.labels}"

What next?

This is a quick bootstrap example of GitOps with Argo CD. The Argo CD docs go into a lot more of the features that are available, however we've covered the basic approach of Argo CD where we can configure in a Git repository the state of the apps we want and let Argo CD take care of the deployment.

One important approach to read from the Argo CD documentation is the App of Apps pattern. This allows one app to create many of apps and can really simplify the bootstrapping and management of a collection apps that you may want to deploy.

Clean up

Once done, clean up the cluster.

k3d cluster delete my-cluster