Building a CD Pipeline with GitOps and ArgoCD 🛠️
Tags: argocd, devops, gitops, tutorial
Published: 2024-02-06 13:30:50

## Project Objective 🚀

This project aims to establish a robust CD pipeline using a public repository and a Docker image, leveraging the power of GitOps with ArgoCD.

## Prerequisites:

1. [Minikube Cluster](https://minikube.sigs.k8s.io/docs/start/)
2. [kubectl](https://kubernetes.io/docs/tasks/tools/)
3. [ArgoCD](https://argo-cd.readthedocs.io/en/stable/getting_started/)
4. [GitHub Account](https://github.com/)
5. [Dockerhub Account](https://hub.docker.com/)
6. [Docker Engine](https://docs.docker.com/engine/install/)
   
In case you are stuck somewhere you can check my repo for this project. Github repo link: [https://github.com/panchanandevops/argocd-public](https://github.com/panchanandevops/argocd-public) 

If you have not installed argocd yet, you can check out my [Introducing to ArgoCD Blog.](https://dev.to/sre_panchanan/introducing-argocd-a-gitops-approach-to-continuous-deployment-p8e)

## Creating Our Own Docker Public Image

To establish a continuous delivery (CD) pipeline, let's create a public GitHub repository named **"argocd-public."** Clone this repository to your local machine.

For simulating a CD pipeline, we require a Docker image. We'll leverage the nginx Docker image and transform it into our custom Docker image named **"mynginx."**

To build this image, execute the following commands. Make sure to replace **"your_username"** with your actual Dockerhub username.

```bash
docker login
docker pull nginx:1.25.3
docker tag nginx:1.25.3 your_username/mynginx:v0.1.0
docker push your_username/mynginx:v0.1.0
```

## Set Up the Project Directories 📁
This will be the tree of our **argocd public** project,

argocd-public
├── k8s-resources
│   └── my-app
│       ├── namespace.yaml
│       └── deployment.yaml
└── argocd-application-files
    └── application.yaml


To set up the project structure Execute the following commands in the **argocd-public** directory:

```bash
mkdir k8s-resources | mkdir k8s-resources/my-app | touch k8s-resources/my-app/namespace.yaml k8s-resources/my-app/deployment.yaml
```

```bash
mkdir argocd-application-files | touch argocd-application-files/application.yaml
```

### YAML Code for Kubernetes Resources
Add the following code to **namespace.yaml** to create a namespace called **foo:**

```yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: foo
```

Add the following code to **deployment.yaml** to create a deployment:

```yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: foo
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: your_username/mynginx:v0.1.0
          ports:
            - containerPort: 80
```

This Kubernetes YAML defines a Deployment named **"nginx"** in the namespace **"foo"** creating one replica of the **"nginx"** application. It specifies a container using the image **"your_username/mynginx:v0.1.0"** exposing **port 80.**

## ArgoCD Application Files

Execute the following commands in the **argocd-public** directory:



Add the following YAML code inside **application.yaml:**

```yaml
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/your_username/argocd-public.git
    targetRevision: HEAD
    path: k8s-resources/my-app
  destination:
    server: https://kubernetes.default.svc
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - Validate=true
      - CreateNamespace=false
      - PrunePropagationPolicy=foreground
      - PruneLast=true
```

Then push these resources to your GitHub repository.

## Understanding CRD of ArgoCD 🧐

Let's break down the **application.yaml** file and understand how ArgoCD works behind the scenes.

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
```

Here we are defining `apiVersion` and `kind` according to the ArgoCD CRD.

```yaml
metadata:
  name: my-app
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
```

This YAML defines metadata for a Kubernetes resource named "my-app" in the "argocd" namespace, including a **finalizer to be executed when deleting the resource.**

```yaml
project: default
source:
  repoURL: https://github.com/your_username/argocd-public.git
  targetRevision: HEAD
  path: k8s-resources/my-app
destination:
  server: https://kubernetes.default.svc
```

This ArgoCD project configuration specifies a project named "default" with a Git repository as the source **(`https://github.com/your_username/argocd-public.git`)**. The target revision is set to `HEAD`, and the Kubernetes manifest files are located at the path **"k8s-resources/my-app."** The destination is a Kubernetes cluster specified by the server URL **`https://kubernetes.default.svc`**.

```yaml
syncPolicy:
  automated:
    prune: true
    selfHeal: true
    allowEmpty: false
```

The `syncPolicy` section of this ArgoCD project configuration enables automated synchronization with the specified Git repository, allowing pruning of resources, self-healing, and disallowing synchronization of empty manifests.

```yaml
syncOptions:
  - Validate=true
  - CreateNamespace=false
  - PrunePropagationPolicy=foreground
  - PruneLast=true
```

The `syncOptions` section in this ArgoCD project configuration provides specific synchronization options, including validation, avoiding the creation of namespaces, specifying pruning propagation policy as "**foreground**" and enabling the pruning of the last resource during synchronization.

Now that we understand how ArgoCD works, let's apply **application.yaml** in the local Kubernetes cluster. This is the only time we will apply `kubectl apply` manually.

```bash
kubectl apply -f argocd-public/argocd-application-files/application.yaml
```

You can verify your Kubernetes resources by applying these commands:

```bash
kubectl get namespaces
kubectl get deployments -n foo
```

For subsequent releases, update the image section of the deployment to the second version of the image. Push the changes to your GitHub repository. After approximately 3 minutes, ArgoCD will automatically deploy the updated deployment with the second version of the **mynginx** image.

## Acknowledgment 🙏

Special thanks to **Anton Putra** for sharing valuable insights and knowledge. You can find Anton on [Anton Putra's YouTube channel](https://www.youtube.com/@AntonPutra) where he provides educational content and tutorials.
## Conclusion 🚀

In this project, we've crafted a GitOps-driven Continuous Delivery (CD) pipeline using ArgoCD 🛠️. Leveraging a public GitHub repository, Docker images, and Kubernetes manifests, we demonstrated seamless synchronization of Kubernetes resources 📦. As you explore this GitOps approach, ensure continuous adaptation of configurations and ongoing improvement of your CD practices 🌟. Happy deploying! 💻🔥