March 25, 2024

Gitops: Using Git as the Sole Source of Truth for Infrastructure

GitOps represents a set of principles aimed at the efficient operation and management of software systems. These principles are grounded in modern software operations while building upon established and widely used best practices.

Control Theory

Its approach is inspired by Control Theory, a field of engineering and applied mathematics focusing on controlling dynamic systems in engineering processes and machines. The main goal is to develop a model or algorithm that regulates the application of inputs to the system, directing it towards a desired state while minimizing delays, overshooting, or steady-state errors, and ensuring an adequate level of control stability.

In GitOps, the infrastructure is defined by representing the desired state of the system. Any changes in the desired state are reflected in the git repository, automatically triggering deployment processes to converge to the new state.

Let's see how the basic structure of control theory is constructed:

When we abstract for GitOps implementation, we have the following result:

Thus, any infrastructure code pushed to our GitOps repository is monitored by ArgoCD, which ensures that the current state of the cluster matches the desired state defined in the YAML files of the repository. This represents the system's output following the implementation of any changes.

I'll delve into more details to explore how these concepts relate to practice.

Architecture

The foundation of our architecture for this publication is based on building an Nginx deployment file, using ArgoCD's declarative configuration to monitor this repository, and applying these configurations to the cluster. In our Git repository, you will find the deployment file (don't worry, all files will be made available in the interface below), where a basic Nginx deployment is configured. Declaratively, we will instruct ArgoCD to monitor this repository, and whenever there is a change, it will apply the changes to the cluster.

ArgoCD

ArgoCD is a tool employed for deploying and managing applications on Kubernetes. It embraces the GitOps paradigm, utilizing Git repositories as the primary source of infrastructure definitions and application configurations. With ArgoCD, you can establish the desired state of your Kubernetes cluster in a Git repository, and ArgoCD will ensure that the cluster is aligned with this desired state. The tool automates the deployment of desired application states to specified target environments. These deployments can track updates in branches, tags, or be pinned to a specific version of manifests in a Git commit.

ArgoCD is configured as a Kubernetes controller that continuously monitors running applications. It compares the current real-time state with the desired target state, as specified in the Git repository. Any deployed application whose current state deviates from the target state is identified as OutOfSync.

Let's implement ArgoCD in our cluster. First, let's create the namespace for it:

shellcopy
kubectl create namespace argocd

After that we can apply your installation manifest:

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

Execute:

shellcopy
kubectl get all -n argocd

If everything went well, you should be able to visualize all the resources provided by ArgoCD.

Next, let's change the service of ArgoCD to type NodePort. This way, the service should be available on all nodes of the Kubernetes cluster on the specified port. You can access it using the IP of any node in the cluster and the specified port.

shellcopy
kubectl patch svc argocd-server -n argocd --type='json' -p  '[{"op":"replace","path":"/spec/type","value":"NodePort"},{"op":"replace","path":"/spec/ports/0/nodePort","value":30000}]'

You can find the IP of any node using the following command:

shellcopy
kubectl get nodes -o wide

Suppose the IP of one of the nodes is 192.168.1.100. You can access your service using http://192.168.1.100:30000.

After accessing the ArgoCD interface, you'll need to retrieve the administrator password. You can do this using the following command:

shellcopy
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Remember, you should use the username admin and the retrieved password.

Gitops

As mentioned previously, in this example, we will be creating a repository intended to store our GitOps file for deploying nginx. To ensure an organized structure, we will name this repository as nginx-gitops.

In this same repository, we will create our deployment file.

nginx-deployment.yamlcopy
apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deploymentspec:  replicas: 3  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx:latest        ports:        - containerPort: 80

After the ArgoCD environment has been deployed in our cluster and our repositories with the desired configurations have been confirmed, it's time to instruct ArgoCD to monitor changes in our repository. As mentioned earlier, we'll do this declaratively, although it's still possible to configure this through the ArgoCD's user interface.

Let's see how our manifest should look like:

nginx-application.yamlcopy
apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata:  name: nginxapp  namespace: argocdspec:  project: default  source:    repoURL: https://github.com/username/nginx-gitops.git    targetRevision: HEAD    path: .  destination:    server: https://kubernetes.default.svc    namespace: default

Next, we will deploy the manifest to our cluster and witness the magic happening:

shellcopy
kubectl apply -f nginx-application.yaml

If all the steps are executed correctly, you should be able to visualize an application in ArgoCD. Within this application, you will find a deployment of nginx with three replicas, as defined in our manifest.

Source of Truth

With all operational infrastructure configured, it's time to experience the main benefit of GitOps: having a single source of truth.

In the GitOps repository, make the change to the replica count in the manifest and commit the file. ArgoCD will automatically detect this change and indicate that your application is not synchronized. Therefore, you can perform a synchronization to ensure that your single source of truth reflects the manifest in your repository.

Helm

So far, our example would have worked for small applications without taking into account security and scalability aspects. For this reason, let's enhance our architecture by incorporating Helm to create custom charts and separate responsibilities.

Kubernetes, a widely utilized system for container orchestration, provides an effective approach to managing and deploying applications in distributed environments. However, dealing with the complexity of Kubernetes deployments can pose a challenge. In this scenario, Helm Charts emerge as a solution, simplifying the process of defining, installing, and managing applications.

Helm is a package management tool for Kubernetes, designed to streamline the consistent deployment of complex applications. At the core of Helm are Helm Charts – packages that encapsulate the information and configurations necessary for deploying a Kubernetes application.

For a deeper understanding of how Helm works, we recommend consulting our publication on Umbrella Charts: Creating high-level charts to abstract global configurations.

The underlying proposal of our new architecture is managing our GitOps repository while keeping only configurable values for our cluster. This implies segregating responsibilities so that the creation of manifests is delegated to a template repository.

Sure, here's how the structure of our template repository might look:

shellcopy
├── Chart.yaml└── templates    ├── deployment.yaml    └── _helpers.tpl

To gain a deeper understanding of how this structure functions, we recommend consulting our publication on Umbrella Charts: Creating high-level charts to abstract global configurations

Feel free to explore the files in our editor:

filehelm-templates
      • file_helpers.tpl
      • filedeployment.yaml
  • fileChart.yaml
fileChart.yaml
apiVersion: v2name: nginx-chartdescription: A Helm chart for deploying Nginxversion: 0.1.0

After completing all necessary configurations, it's time to adjust our values file in the GitOps repository. Make sure your configuration follows the pattern established by the template to ensure compliance with the rules.

values.yamlcopy
replicaCount: 3image:  repository: nginx  tag: stable  pullPolicy: IfNotPresentservice:  type: ClusterIP  port: 3000

Finally, let's configure our application, but this time let's instruct Argo CD to observe more than one data source. For more details, Multiple Sources for an Application

nginx-application.yamlcopy
apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata:  name: nginxapp  namespace: argocdspec:  destination:    server: 'https://kubernetes.default.svc'    namespace: default  project: default  sources:  - repoURL: 'https://github.com/user/helm-templates.git'    path: .    targetRevision: HEAD    helm:      valueFiles:        - '$values/values.yaml'  - repoURL: 'https://github.com/user/nginx-gitops.git'    targetRevision: HEAD    ref: values

When this manifest is applied, ArgoCD should generate an application with three replicas, as illustrated in the previous example.

shellcopy
kubectl apply -f nginx-application.yaml

Unlike the previous example, when using Helm, we can modify only the values file to change the characteristics of our infrastructure. Let's run a test again: change the number of replicas in your values file and observe how this configuration is reflected in your cluster. By separating the infrastructure resource templates from the specific configuration values, you maintain a clear separation of concerns. This facilitates the management and updating of infrastructure resources without modifying the specific values.

Conclusion

This text serves as an introduction to the countless possibilities that adopting GitOps offers. Don't limit yourself to the examples presented here. Create, adapt, and destroy – that's the essence of learning. I hope you experience the same sense of empowerment that I felt when understanding the potential of this tool.

Time is a precious commodity, and I appreciate you generously sharing a portion of yours with me.

For more thoughts like thisJoin the community
instagraminstagraminstagraminstagram