ArgoCD app of apps installation in Kubernetes with Helm

Learn to initiate your ArgoCD environment within Kubernetes using a helm chart and a straightforward bash script in this instructional post.

Series - ArgoCD Insights

By creating a single Bash script, you will learn how to bootstrap and automate the creation of an ArgoCD instance in Kubernetes, along with the creation of the initial project, repository, and the main application in the app of apps pattern.

Create a repository on GitHub, GitLab or wherever you prefer. Generate a personal access token if you are using GitHub, or create a project access token if you are using GitLab. Save it somewhere safe, because you will need it for ArgoCD later.

Create the necessary directories and files like the example below. The repository structure should look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
argocd
├── apps
└── bootstrap
    ├── init.sh
    ├── manifests
    │   ├── application.yaml
    │   └── project.yaml
    └── values.yaml

3 directories, 4 files

You will populate the files with content later. For now, just make the init.sh script executable so you don’t forget later:

1
chmod +x argocd/bootstrap/init.sh

This is where we are setting up the automated first time installation of ArgoCD. To do so, follow these steps and edit each file:

The argocd/bootstrap/manifests/application.yaml manifest will configure the main application, paste this inside and replace with your own values:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: example-infrastructure
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: example-project
  source:
    path: argocd/apps # it watches over the apps directory
    repoURL: https://github.com/example/infrastructure.git # always put the .git extension here
    targetRevision: HEAD
    directory:
      recurse: true
  destination:
    server: 'https://kubernetes.default.svc'
    namespace: argocd
  syncPolicy:
    syncOptions:
    - CreateNamespace=false
    automated:
      selfHeal: false

The argocd/bootstrap/manifests/project.yaml manifest will configure the project which will be used for the application, paste this inside and replace with your own values:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: example-project
  namespace: argocd
spec:
  # Deny all cluster-scoped resources from being created, except for Namespace
  clusterResourceWhitelist:
  - group: '*'
    kind: '*'
  # Project description
  description: Example infrastructure project
  # Only permit applications to deploy to the guestbook namespace in the same cluster
  destinations:
  - namespace: '*'
    server: '*'
  # Allow manifests to deploy from any Git repos
  sourceRepos:
  - '*'

The argocd/bootstrap/values.yaml file is for the custom Helm chart values. You can look at the available values here. We are setting up values for the following:

  1. If you want to expose the ArgoCD UI with your ingress controller, the SSL termination must be done at the ingress controller level. That is why we are setting the --insecure flag for the server. If you don’t set this field, the UI will not open in a browser in any way other that port forwarding.

  2. We are also adding the health assessment of applications custom script to be able to use sync waves between applications. Read more here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
configs:
  # Enable the health assessment of applications
  cm:
    resource.customizations.health.argoproj.io_Application: |
      hs = {}
      hs.status = "Progressing"
      hs.message = ""
      if obj.status ~= nil then
        if obj.status.health ~= nil then
          hs.status = obj.status.health.status
          if obj.status.health.message ~= nil then
            hs.message = obj.status.health.message
          end
        end
      end
      return hs      

  # Patching the TLS because we want our SSL termination to happen on Ingress Gateway level
  params:
    server.insecure: true

The argocd/bootstrap/init.sh bash script will ask you for the repository URL and the access token. After that, it will install ArgoCD in your Kubernetes cluster with Helm, it will create the repository secret, and it will create the project and the application. Remember to replace anything you want with your own values here. Paste the script into your own init.sh:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

# Create repository and API Token variables
read -p "Enter the full repository URL (with .git at the end): " repository
read -p "Enter the Git API token with api scope permissions: " git_api_token
read -p "Continue? (Y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1

# Set the working directory to always be argocd/bootstrap/
cd "$(dirname "${BASH_SOURCE[0]}")"

# Install ArgoCD
echo "Installing ArgoCD..."
kubectl create namespace argocd

helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd -n argocd argo/argo-cd -f values.yaml

# Create a secret for the infrastructure repository
echo "Configuring repository access..."
kubectl create secret generic example-infrastructure-repo --namespace=argocd --type=Opaque --from-literal=url=$repository --from-literal=password=$git_api_token
kubectl label secret -n argocd example-infrastructure-repo argocd.argoproj.io/secret-type=repository

# Create project
echo "Creating the main project..."
kubectl apply -f manifests/project.yaml

# Create the app of apps
echo "Creating the app of apps..."
kubectl apply -f manifests/application.yaml

After this, you can now push the code to your repository after you have reviewed it.

To install ArgoCD, prepare the repository URL and the access token for when the script asks you to provide them, and run it:

1
./argocd/bootstrap/init.sh

After some time, it will deploy ArgoCD and set it up for you. The initial username is admin. You can get the initial admin password with this command:

1
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

Now, if you have an ingress controller in place, you can create an ingress resource to expose the UI, or you can simple use port forwarding to access it on localhost. Here is the command for port forwarding, and after it’s done, you can access it on the browser with http://localhost:8080:

1
kubectl port-forward -n argocd svc/argocd-server 8080:443

You can check the official docs to see examples of exposing the UI with various ingress controllers.

This is where the children applications of the main application will be stored. For example, if you want to add an application, it will look like this:

1
2
3
4
argocd/apps/cert-manager
└── application.yaml

0 directories, 1 file

And the apps/cert-manager/application.yaml manifest will look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cert-manager
  namespace: argocd
spec:
  project: example-project
  source:
    repoURL: 'https://charts.jetstack.io'
    targetRevision: 1.7.2
    chart: cert-manager
    helm:
      valueFiles:
        - values.yaml
      parameters:
        - name: installCRDs
          value: "true"
  destination:
    server: 'https://kubernetes.default.svc'
    namespace: cert-manager
  syncPolicy:
    automated:
      selfHeal: true
    syncOptions:
      - CreateNamespace=true