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!