ArgoCD is the first tool that enables a fully declarative Continuous Delivery on Kubernetes. However, we've seen it often being used in a way that introduces (at least) one imperative step during the Application setup; this single mistake defeats the purpose of using ArgoCD.
In case you are unfamiliar with Kubernetes Custom Resource Definition (CRD) and ArgoCD Applications, here is some context: Kubernetes CRD is a mechanism to extend the Kubernetes API; it allows, for example, to define new operations to be performed by a controller. ArgoCD defines an Application CRD that tells Argo where to find the manifests to apply to deploy a given application: which git repository and which folder, along with kustomize or helm parameters.
There are many options for creating these CRDs, either from the web console, CLI, or by applying an Application Manifest in your Kubernetes cluster.
The first two approaches have one fatal flaw: store the Application records on the infrastructure that can be destroyed; therefore, all the manual steps will have to be performed again unless a backup of the Application manifests is maintained.
Maintaining such backups is cumbersome and unnecessary, and it breaks the GitOps pattern of having part of the infrastructure definition out of a Git repository.
Using Application Manifests can be made to work declaratively, but it brings many code replication and maintainability complexities that need to be more worth it existing a fourth and correct approach.
The fourth option is Application Sets. This Custom Resource Definition in Argo was created to allow one single manifest to be used as a template to create Applications based on a given rule. Let's see an example that will make things clear.
One of the simplest and easiest to understand is the Git Generator (but there are others). It allows you to generate Applications based on a folder structure using path regex rules and gives you access to the path directive that will include the full path that matches the rules so you can use it in the Application spec.
This is the structure you have defined in your Git repository: One service called app1 and one addon called app2
services/
app1/
Chart.yaml
values.yaml
env/
values.yaml
secrets.yaml
addons/
app2/
Chart.yaml
values.yaml
env/
values.yaml
secrets.yaml
On the other hand you have the following CRD defined in ArgoCD
apiVersion: https://argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: general
namespace: argocd
spec:
generators:
- git:
directories:
- path: services/**/env
- path: addons/**/env
repoURL: https://github.com/org/deployments-repo.git
revision: HEAD
template:
metadata:
name: '{{path[1]}}'
spec:
destination:
namespace: '{{path[0]}}'
server: https://kubernetes.default.svc/
project: '{{path[0]}}'
source:
helm:
releaseName: '{{path[1]}}'
valueFiles:
- /{{path[0]}}/{{path[1]}}/values.yaml
- /{{path}}/values.yaml
- /{{path}}/secrets.yaml
path: '{{path}}'
repoURL: https://github.com/org/deployments-repo.git
targetRevision: HEAD
syncPolicy:
automated:
selfHeal: false
The combination of both will render the following Applications CRDs
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: app1
namespace: argocd
spec:
destination:
namespace: services
server: https://kubernetes.default.svc
project: services
source:
helm:
releaseName: app1
valueFiles:
- /services/app1/values.yaml
- /services/app1/env/values.yaml
- /services/app1/env/secrets.yaml
path: services/app1/env
repoURL: https://github.com/org/deployments-repo.git
targetRevision: HEAD
syncPolicy:
automated: {}
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: app2
namespace: argocd
spec:
destination:
namespace: addons
server: https://kubernetes.default.svc
project: addons
source:
helm:
releaseName: app2
valueFiles:
- /services/app2/values.yaml
- /services/app2/env/values.yaml
- /services/app2/env/secrets.yaml
path: services/app2/env
repoURL: https://github.com/org/deployments-repo.git
targetRevision: HEAD
syncPolicy:
automated: {}
As you can see, using Argos CRDs, you can define logic and structures for deploying applications quite easily.
With this approach, the platform team can manage a single or a handful of files and scale the number of Applications effortlessly, enabling a genuine, transparent self-service mechanism for the developers in the organization.