Introduction to GitOps and ArgoCD.

Introduction to GitOps  and ArgoCD.

GitOps

GitOps is a way of implementing Continuous Deployment for cloud native applications. It focuses on a developer-centric experience when operating infrastructure, by using tools developers are already familiar with, including Git and Continuous Deployment tools. It is defined as infrastructure as code done right. Let's see how.

Before anything else, let's understand what infrastructure as code is. Instead of performing everything manually, the infrastructure is written in code. Many more concepts emerged along with Infrastructure as code, including policy as code, security as code, etc. For example writing Terraform code, Ansible code, kubernetes manifest, and other YAML files can be more efficient than manually setting up servers in AWS and kubernetes cluster in EKS.

infrastructure_as_code.jpg

How we use IaC incorrectly? Either we save the files and execute them locally, or we version control the files (i.e. save them in git) so that other team members may also collaborate. However, this could go "south" because you might not have a suitable pull/merge request mechanism, automated testing, etc, which may led to unexpected consequences.

Every change made to the files using this method is always manually deployed to the infrastructure, which is inefficient. Everyone has access to the infrastructure, and there is no code review, which will cause security problems. Aside from this, there is no testing available here, so we will receive the results after setting everything up, which will undoubtedly be very depressing if, at the end, you are still experiencing problems. Therefore, even if we use IaC, our entire process is manual and ineffective.

So this is where GitOps comes into play. With this method, we define infrastructure as code and have a full CI/CD pipeline while treating IaC the same as application code.

In GitOps, every change must first pass through the CI pipeline, where all building and testing take place. Senior developers and operations staff must also approve the change before it can be merged and deployed to the environment via the CD pipeline. As a result, we are getting automated, high-quality IaC.

Changes to the environment in GitOps can be made in one of two ways:

  • Push Deployment: It is the fundamental method we use, in which we push the application onto an environment, such as a kubernetes cluster, using the CI/CD pipelines of Jenkins or Gitlab.

push.png

  • Pull Deployment: In this case, we have an environment with an agent installed that will continuously pull changes from the git repository. The agent will continuously check the repository for changes, and if any are found, it will pull the changes and apply them to the environment to change it from the actual state to the desired state. Tools like Flux and ArgoCD are examples of pull-based models.

pull.png

The advantages of pull deployment:

  • If the present state is not functioning properly, easy rollbacks are available.
  • Git becomes the single source of truth, making management incredibly simple.
  • Increases security because we won't have to grant access to as many individuals. Instead, the agent will handle that, while team members are still welcome to submit pull requests.

ArgoCD

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

CD workflow without ArgoCD

Let's say a bugfix needs to be implemented. After that, the code will go through build and testing, and if necessary, the docker image will be updated. The section up to this point falls under CI, and whichever tool we choose will make the necessary modifications in the yaml file and apply them in the cluster, for example using kubectl, after updating the image.

As a result, Jenkins is handling all of the pushing work in this situation, but there are challenges because we need to install additional tools like kubectl and helm on Jenkins, grant Jenkins access to the Kubernetes cluster, and if we are using EKS, give Jenkins access to AWS as well. This poses a serious security risk. Another significant problem is that once Jenkins has deployed the changes, it loses access to the cluster, making it impossible to check anything that has been deployed.

So argocd can be used to increase the efficiency of the CD segment, specifically for Kubernetes. How does argocd makes the process more efficient? Instead of using a tool outside the cluster, now the tool is part of the Kubernetes cluster and it uses the pull-based deployment.

Workflow with ArgoCD

ArgoCD is first setup on the cluster, after which we connect it to the git repository. As soon as a change is made in the repository, argocd will pull it and apply it to the Kubernetes cluster. Because the configuration contains more than just yaml files and also includes secrets, services, and ingress, it is best practise to separate the application code from the application configuration in a separate repository because there is no need to run the entire CI pipeline when making changes to any configuration or service.

Jenkins will update the manifest file in the configuration git repository, and argocd will pull and apply the changes to the cluster as soon as it becomes aware of the change. Kubernetes YAML files, Helm files, and Kustomize files are supported by argocd. Another name for the configuration repository is the GitOps Repository. Therefore, the CI and CD are separated, with the CI configured, for instance, on Jenkins, and the CD configured on argocd .

Benefits of GitOps

  1. Since the git repository contains the complete application configuration, all changes are applied there rather than to the cluster itself.
  2. Even if a change is made manually to the cluster, argocd will still be able to match the desired and actual states since it keeps an eye on both the cluster and the git repository. The git repository is the source of truth.
  3. Since everything is version controlled, we can see the history of changes and see who changed what.
  4. If necessary, we can easily roll things back. This method of rolling back is much more effective than doing it manually because we are working with so many clusters.

Advantages of using ArgoCD

Since argocd is built on GitOps principles, all the advantages of using GitOps are included, plus using argocd offers some additional benefits.

  • Git allows us to set up access rules so that any members can submit pull requests, but only senior or experienced members can merge them.
  • Because argocd is already in the cluster and is in charge of everything, we don't need to grant Jenkins or other external tools any access to the cluster.

ArgoCD is an extension to the kubernetes API and is not simply deployed to the kubernetes cluster. Therefore, it uses Kubernetes functionalities to perform its function rather than constructing its own like using K8s Controller to monitor and etcd to store data. Benefits include visibility into the cluster, real-time updates on the status of the application, and the ability to monitor the cluster after changes have been made to check the health of the pods.

argocd.png

How to configure ArgoCD

Deploy argocd to kubernetes, and it will extend the kubernetes API using custom resource definitions (CRDs). This allows us to configure argocd using yaml files where we put the information of source, i.e., git repository, and destination, i.e., the k8s cluster, which can be any kubernetes cluster, including the one that argocd is running in, or external cluster which argocd is managing.

Even though we have many clusters in various areas, just one instance of argocd needs to be set up in order for it to control the entire k8s cluster.

If we have different cluster environments, such as deployment, staging, and production, we will deploy argocd separately. However, there is only one git repository where all the code and configuration are stored, so whenever any changes are made, we will first test them on each environment before promoting them to the the next one.

DEMO

  • Setup the Kubernetes cluster. You can set this up using cloud providers like Civo, AWS, or locally. I'm setting it up locally using minikube.
  • Create a argocd namespace.
$ kubectl create namespace argocd
namespace/argocd created
  • Run this to create all the objects required.
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/core-install.yaml
  • View the created objects. You can also use Lens IDE for better experience.
$ kubectl get all -n argocd
NAME                                                    READY   STATUS    RESTARTS   AGE
pod/argocd-application-controller-0                     1/1     Running   0          17m
pod/argocd-applicationset-controller-5cbcd886fc-qk9b2   1/1     Running   0          17m
pod/argocd-dex-server-6f4cdd4b64-5mz6x                  1/1     Running   0          17m
pod/argocd-notifications-controller-d8f8496c6-hf57k     1/1     Running   0          17m
pod/argocd-redis-558cfbbf7-5hn64                        1/1     Running   0          17m
pod/argocd-repo-server-75dc98cb84-x4842                 1/1     Running   0          17m
pod/argocd-server-88f575bcb-p8mq6                       1/1     Running   0          17m

NAME                                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
service/argocd-applicationset-controller          ClusterIP   10.107.223.61    <none>        7000/TCP,8080/TCP            17m
service/argocd-dex-server                         ClusterIP   10.111.239.93    <none>        5556/TCP,5557/TCP,5558/TCP   17m
service/argocd-metrics                            ClusterIP   10.111.44.183    <none>        8082/TCP                     17m
service/argocd-notifications-controller-metrics   ClusterIP   10.111.207.97    <none>        9001/TCP                     17m
service/argocd-redis                              ClusterIP   10.107.223.181   <none>        6379/TCP                     17m
service/argocd-repo-server                        ClusterIP   10.109.250.145   <none>        8081/TCP,8084/TCP            17m
service/argocd-server                             ClusterIP   10.110.226.135   <none>        80/TCP,443/TCP               17m
service/argocd-server-metrics                     ClusterIP   10.110.149.209   <none>        8083/TCP                     17m

NAME                                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/argocd-applicationset-controller   1/1     1            1           17m
deployment.apps/argocd-dex-server                  1/1     1            1           17m
deployment.apps/argocd-notifications-controller    1/1     1            1           17m
deployment.apps/argocd-redis                       1/1     1            1           17m
deployment.apps/argocd-repo-server                 1/1     1            1           17m
deployment.apps/argocd-server                      1/1     1            1           17m

NAME                                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/argocd-applicationset-controller-5cbcd886fc   1         1         1       17m
replicaset.apps/argocd-dex-server-6f4cdd4b64                  1         1         1       17m
replicaset.apps/argocd-notifications-controller-d8f8496c6     1         1         1       17m
replicaset.apps/argocd-redis-558cfbbf7                        1         1         1       17m
replicaset.apps/argocd-repo-server-75dc98cb84                 1         1         1       17m
replicaset.apps/argocd-server-88f575bcb                       1         1         1       17m

NAME                                             READY   AGE
statefulset.apps/argocd-application-controller   1/1     17m
  • Install the argocd CLI.
$ brew install argocd
  • After installing, change the service type to LoadBalancer.
 $ kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
service/argocd-server patched
  • Port forward it for localhost access.
$ kubectl port-forward svc/argocd-server -n argocd 8080:443

image.png

  • The initial password for the admin account is auto-generated and stored as clear text in the field password in a secret named argocd-initial-admin-secret in your Argo CD installation namespace. You can simply retrieve this password using kubectl.
$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
  • You will see this UI after entering your username and password.

argoUI.png

  • A git repository is required. I'm using this repo.

  • Apps can be created using the UI or CLI. I'm creating a guestbook app, read the entire process here and after creating, the UI will look like this.

status.png

  • The app is out of sync as can be seen in the screenshot above, to get it back in sync, use the sync button or command.
  • It will display the status after syncing whether the pods are healthy or degrading.

healthy.png

NOTE: Make sure to include argocd labels if you are supplying Kubernetes objects, such as configmap, as argocd won't be able to use it without labels. Additionally, you may utilise datree to determine whether or not each Argo rule was satisfied.

Did you find this article valuable?

Support WeMakeDevs by becoming a sponsor. Any amount is appreciated!