Self Managed Argo CD — App Of Everything

Burak Kurt
Devops Türkiye☁️ 🐧 🐳 ☸️
8 min readMay 10, 2021

Argo CD one of the most popular continues deployment tools used in Kubernetes. It is very simple to use and quite powerful. Personally, it is the first tool in my mind when I think of Kubernetes GitOps.

Argo CD employs the App of Apps pattern for cluster bootstrapping. This enables us to programmatically and automatically create Argo CD apps instead of manually creating each application. The concept is straightforward: create a single Argo CD application that points to a specific Git repo path and place all Argo CD application definition files there. Consequently, whenever an application definition file is added to that Git repo path, an Argo CD application is automatically created. Drawing inspiration from this approach, it becomes possible to create or manage any Kubernetes object, including Argo CD itself.

In this article, I will attempt to explain how to install Argo CD with the App of Apps pattern in an automated manner. I will utilize ‘kind’ to create a local Kubernetes cluster, GitHub for the repository, and Helm to install the initial setup. After completing these steps, you will have an Argo CD instance managing itself, two Argo CD applications responsible for creating additional Argo CD applications, and Argo CD projects automatically. Finally, we will test it with a sample application.

Before we begin, please take note of my previous article on Argo CD LDAP configuration and RBAC for LDAP.

If you already have a Kubernetes cluster, you can skip the first part and proceed to the second section, ‘Designing Git Repository Hierarchy”.

1. Creating Local Kubernetes Cluster

kind is a tool for running local Kubernetes clusters using Docker container “nodes”. To initiate a kind cluster, we first need Docker installed. If you don’t have Docker running, you can follow this link.

Install kind binary.

On Linux:

curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64
chmod +x ./kind
mv ./kind /some-dir-in-your-PATH/kind

On Mac (homebrew):

brew install kind

On Windows:

curl.exe -Lo kind-windows-amd64.exe https://kind.sigs.k8s.io/dl/v0.11.1/kind-windows-amd64
Move-Item .\kind-windows-amd64.exe c:\some-dir-in-your-PATH\kind.exe

On Windows via Chocolatey (https://chocolatey.org/packages/kind)

choco install kind

Create a local Kubernetes Cluster.

$ kind create cluster — name my-cluster
Creating cluster “my-cluster” …
✓ Ensuring node image (kindest/node:v1.21.1) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to “kind-my-cluster”
You can now use your cluster with:
kubectl cluster-info — context kind-my-cluster
Thanks for using kind! 😊

Check the cluster is running and healthy.

$ kubectl cluster-info — context kind-my-cluster
Kubernetes control plane is running at https://127.0.0.1:50589
KubeDNS is running at https://127.0.0.1:50589/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use ‘kubectl cluster-info dump’.

2. Designing Git Repository Hierarchy

A Git repository can be designed in any hierarchy. Typically, creating three folders for Argo CD installation, Argo CD Applications, and Argo CD Application Projects is sufficient. I have organized this repository with the following folder structure.

Repository folder tree:

argocd/
├── argocd-appprojects # stores ArgoCD App Project's yaml files
├── argocd-apps # stores ArgoCD Application's yaml files
├── argocd-install # stores Argo CD installation files
│ ├── argo-cd # argo/argo-cd helm chart
│ └── values-override.yaml # custom values.yaml for argo-cd chart

3. Create App Of Everything Pattern

If we check the values-override.yaml file, it can be seen that there are three application definitions and one app project definition. Additionally, the source Git repository is added in the “server.config.repositories” section.

The “argocd” application is for managing Argo CD itself. It consists of the Argo CD Helm chart and custom values files. The “argocd-apps” application exemplifies the app of apps pattern. It monitors the “argocd-apps” folder, which contains Argo CD application definition files. Whenever a new application YAML is created in that folder, the argocd-apps application automatically applies this YAML to the cluster, thereby creating an Argo CD application automatically. The “argocd-appprojects” application is similar to “argocd-apps” and is responsible for creating Argo CD Application Projects.

The additional project “argocd” is utilized in Argo CD additional applications to ensure proper access control.

server:
configEnabled: true
config:
repositories: |
- type: git
url: https://github.com/bukurt/argocd.git
- name: argo-helm
type: helm
url: https://argoproj.github.io/argo-helm
additionalApplications:
- name: argocd
namespace: argocd
destination:
namespace: argocd
server: https://kubernetes.default.svc
project: argocd
source:
helm:
version: v3
valueFiles:
- values.yaml
- ../values-override.yaml
path: argocd-install/argo-cd
repoURL: https://github.com/bukurt/argocd.git
targetRevision: HEAD
syncPolicy:
syncOptions:
- CreateNamespace=true
- name: argocd-apps
namespace: argocd
destination:
namespace: argocd
server: https://kubernetes.default.svc
project: argocd
source:
path: argocd-apps
repoURL: https://github.com/bukurt/argocd.git
targetRevision: HEAD
directory:
recurse: true
jsonnet: {}
syncPolicy:
automated:
selfHeal: true
prune: true
- name: argocd-appprojects
namespace: argocd
destination:
namespace: argocd
server: https://kubernetes.default.svc
project: argocd
source:
path: argocd-appprojects
repoURL: https://github.com/bukurt/argocd.git
targetRevision: HEAD
directory:
recurse: true
jsonnet: {}
syncPolicy:
automated:
selfHeal: true
prune: true
additionalProjects:
- name: argocd
namespace: argocd
additionalLabels: {}
additionalAnnotations: {}
description: Argocd Project
sourceRepos:
- '*'
destinations:
- namespace: argocd
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: '*'
kind: '*'
orphanedResources:
warn: false

With that configuration, we have set up our Argo CD installation for both self-management and the app of apps pattern.

4. Install… Ready !

We are ready to install. Pull the repository and execute the helm install command.

$ git clone https://github.com/bukurt/argocd.git
$ cd argocd/argocd-install/
$ helm install argocd ./argo-cd \
--namespace=argocd \
--create-namespace \
-f values-override.yaml

Wait until all pods are running.

$ kubectl -n argocd get podsNAME                                            READY   STATUS    RESTARTS
argocd-application-controller-bcc4f7584-vsbc7 1/1 Running 0
argocd-dex-server-77f6fc6cfb-v844k 1/1 Running 0
argocd-redis-7966999975-68hm7 1/1 Running 0
argocd-repo-server-6b76b7ff6b-2fgqr 1/1 Running 0
argocd-server-848dbc6cb4-r48qp 1/1 Running 0

Get the initial admin password.

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

Forward the port 80 of the argocd-server service to localhost:8080 using kubectl.

$ kubectl -n argocd port-forward service/argocd-server 8080:80

Browse http://localhost:8080 and log in with the initial admin password. As you can see, the three applications described in our values-override.yaml file are ready. The “argocd” application may appear out of sync, but don’t worry. This is a result of using different templating parameters between my local Helm binary and Argo CD’s Helm binary. Simply click the “Sync” button and wait until it turns green.

Finally, we have a self-managed Argo CD with the app of apps pattern. All configurations and definitions are located in our Git repository. Simply push changes to our Git repository to configure Argo CD or to create/update an application. If you prefer, you can also enable auto-sync for the “argocd” application. However, I recommend keeping it manual for a more secure and stable management.

5. Sample Application Demo

In this demo, we will create an application project called “sample-project” that can only access the “sample-app” namespace and create an application called “sample-app” in that project.

Let’s begin with “sample-project.”

Create a YAML file with the content below and place it in the application project folder in your Git repository. In my case, it is the “argocd-appprojects” folder.

$ cat << EOF > argocd-appprojects/sample-project.yaml
> apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: sample-project
namespace: argocd
spec:
clusterResourceWhitelist:
- group: '*'
kind: '*'
destinations:
- namespace: sample-app
server: https://kubernetes.default.svc
orphanedResources:
warn: false
sourceRepos:
- '*'
EOF

Push changes to your repository.

$ git add argocd-appprojects/sample-project.yaml
$ git commit -m "Create sample-project"
$ git push

Argo CD checks the Git repository every three minutes. You can either wait a couple of minutes or click the “Refresh” button of the “argocd-appproject” application. After synchronization, you can observe that “sample-project” has been created. You can also verify this under the Project menu in the Settings pane.

Next, “sample-app”.

Create a YAML file with the content below and place it in the application folder in your Git repository. In my case, it is the “argocd-apps” folder. You can refer to the Argo CD official documentation for all available fields and parameters.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: sample-app
namespace: argocd
spec:
destination:
namespace: sample-app
server: https://kubernetes.default.svc
project: sample-project
source:
path: sample-app/
repoURL: https://github.com/bukurt/argocd.git
targetRevision: HEAD
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
selfHeal: true
prune: true

Push changes to your repository.

$ git add argocd-apps/sample-app.yaml
$ git commit -m "Create application"
$ git push

In several minutes or by clicking the refresh button of “argocd-apps,” you can observe the creation of “sample-app” on the GUI.

You can also verify via kubectl commands.

$ kubectl -n sample-app get all
NAME READY STATUS AGE
pod/details-v1-79f774bdb9-7sw9q 1/1 Running 112m
pod/productpage-v1-6b746f74dc-vwkdq 1/1 Running 112m
pod/ratings-v1-b6994bb9-rf7lk 1/1 Running 112m
pod/reviews-v1-545db77b95-pzcj9 1/1 Running 112m
pod/reviews-v2-7bf8c9648f-q8b6m 1/1 Running 112m
pod/reviews-v3-84779c7bbc-9nfp4 1/1 Running 112m
NAME TYPE CLUSTER-IP PORT(S) AGE
service/details ClusterIP 10.96.27.232 9080/TCP 112m
service/productpage ClusterIP 10.96.72.223 9080/TCP 112m
service/ratings ClusterIP 10.96.0.174 9080/TCP 112m
service/reviews ClusterIP 10.96.115.169 9080/TCP 112m
NAME READY UP-TO-DATE AVAILABLE
deployment.apps/details-v1 1/1 1 1
deployment.apps/productpage-v1 1/1 1 1
deployment.apps/ratings-v1 1/1 1 1
deployment.apps/reviews-v1 1/1 1 1
deployment.apps/reviews-v2 1/1 1 1
deployment.apps/reviews-v3 1/1 1 1
NAME DESIRED CURRENT READY
replicaset.apps/details-v1-79f774bdb9 1 1 1
replicaset.apps/productpage-v1-6b746f74dc 1 1 1
replicaset.apps/ratings-v1-b6994bb9 1 1 1
replicaset.apps/reviews-v1-545db77b95 1 1 1
replicaset.apps/reviews-v2-7bf8c9648f 1 1 1
replicaset.apps/reviews-v3-84779c7bbc 1 1 1

Everything is running and ready!

6. Cleanup

Remove application and application project definition files in the git repository.

$ rm -f argocd-apps/sample-app.yaml
$ rm -f argocd-appprojects/sample-project.yaml
$ git rm argocd-apps/sample-app.yaml
$ git rm argocd-appprojects/sample-project.yaml
$ git commit -m "Remove app and project."
$ git push

Delete application “sample-app”.

Synchronize “argocd-apps” and “argocd-appprojects” by selecting “Prune” option.

Uninstall argo-cd helm deployment.

$ helm uninstall argocd

Wait until all resources are deleted in argocd namespace.

$ kubectl -n argocd get pods
NAME READY STATUS
argocd-application-controller-bcc4f7584-vsbc7 0/1 Terminating
argocd-dex-server-77f6fc6cfb-v844k 0/1 Terminating
argocd-redis-7966999975-68hm7 0/1 Terminating
argocd-repo-server-6b76b7ff6b-2fgqr 0/1 Terminating
argocd-server-848dbc6cb4-r48qp 0/1 Terminating

Delete “argocd” and “sample-app” namespaces.

$ kubectl delete ns argocd
$ kubectl delete ns sample-app

Delete kind cluster.

$ kind delete cluster --name my-cluster
Deleting cluster "my-cluster" ...

--

--