App of Apps of Infra

Declarative infrastructure (IaC) by any means is necessary for the modern enterprise. A single source of truth in regards to not only applications but infrastructure and configuration is a must. Housing it all in git and adding necessary barriers further allows access control, multi-tenancy, and configuration boundaries via CI/CD and Gitops. Below, we will use Argo's App of Apps pattern to further describe the state of our Digital Ocean cluster using Crossplane. For the sake of brevity, I'll get straight to the needed components.

First lets stand up our bootstrap cluster using Kind

kind create cluster --name bootstrap

Next go ahead and fork, copy, whatever you wish in order to get the necessary files I've shared in this repository https://gitlab.com/jaymiracola/app-of-infra. After you've done so we will install ArgoCD followed by kicking off our app-of-apps pattern by applying the first application which is Argo itself. From there forward it will be managed via git.

helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argo argo/argo-cd -n argocd --create-namespace --set version=5.51.4

kubectl apply -f applications.yaml

Now ArgoCD and Crossplane have been installed and are being defined entirely from our git repository. It's time to define the infrastructure.

kubectl get applications -A
NAMESPACE   NAME           SYNC STATUS   HEALTH STATUS
argocd      applications   Synced        Healthy
argocd      argocd         Synced        Healthy
argocd      crossplane     Synced        Healthy
argocd      infra          Synced        Healthy

Next, we will define some infrastructure in Digital Ocean. Why Digital Ocean vs AWS, GCP, or Azure? Simple, I use them all the time for low cost services I use personally! Of course, from here you could define whatever you'd like with Crossplane so the cloud and infrastructure is up to you.

Now we need to start defining Providers and Provider Configurations to Crossplane to configure which Cloud Providers we want and the keys to allow Crossplane to configure them on our behalf. I've already added the Digital Ocean Provider so now we need to configure access.

I'll add the following manifest to my /app-of-infra/applications/infra/manifests/ folder as I've already defined and declared it as an application that ArgoCD is tracking. You can get a Digital Ocean token here.

apiVersion: v1
kind: Secret
metadata:
  namespace: crossplane
  name: provider-do-secret
type: Opaque
data:
  token: BASE64ENCODED_PROVIDER_CREDS
---
apiVersion: do.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
  name: do-config
  namespace: crossplane
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane
      name: provider-do-secret
      key: token

Important! Do NOT have this in a public repo. There is a reason this part of the instruction is omitted from my demonstration repository.

Last, it's time to declare infrastructure! As an example I will add the following configuration in /app-of-infra/applications/infra/manifests/ to create a Kubernetes cluster in my Digital Ocean account. More examples of different Digital Ocean infrastructure can be found here.

apiVersion: kubernetes.do.crossplane.io/v1alpha1
kind: DOKubernetesCluster
metadata:
  name: do-cluster
  namespace: infra
spec:
  providerConfigRef:
    name: do-config
  forProvider:
    region: nyc3
    version: 1.29.0-do.0
    nodePools:
      - size: s-1vcpu-2gb #lowest tier
        count: 1 #cost cutting for demo
        name: worker-pool
    maintenancePolicy:
      startTime: "03:00"
      day: sunday
    autoUpgrade: true
    surgeUpgrade: false
    highlyAvailable: false

Now you have successfully declared the entirety of your bootstrap cluster all the way into platform infrastructure in a not only declarative but also idempotent pattern! From here you can create more infrastructure as needed. You may also be interested in extending the control plane using Crossplane's Composite Resource Definitions allowing SRE teams to abstract infra with apps (and more) to easily consumable APIs.