This is a GitOps-managed Kubernetes demo deploying a data platform (Trino, Hive, Airflow, HDFS, etc.) using Stackable operators and ArgoCD.
stackablectl (just deploy)
└─> installs ArgoCD + bootstrap apps from infrastructure/stack.yaml
└─> ArgoCD deploys infrastructure/ (Forgejo, SealedSecrets, project, cluster-apps)
└─> Forgejo mirrors this GitHub repo into the cluster
└─> cluster-apps.yaml watches platform/applications/ (app-of-apps pattern)
└─> each Application in platform/applications/ deploys its manifests
infrastructure/ # Bootstrap: deployed by stackablectl, sets up ArgoCD + Forgejo + SealedSecrets
├── stack.yaml # stackablectl stack definition (entry point for `just deploy`)
├── project.yaml # ArgoCD AppProject definition
├── cluster-apps.yaml # App-of-apps: watches platform/applications/
├── forgejo.yaml # ArgoCD Application for Forgejo (Helm + manifests)
├── sealed-secrets.yaml # ArgoCD Application for SealedSecrets (Helm + manifests)
├── forgejo-manifests/ # Supporting manifests for Forgejo (admin secret, configure job)
└── sealed-secrets-manifests/ # SealedSecrets decryption key
platform/ # Everything ArgoCD manages after bootstrap
├── applications/ # ArgoCD Application definitions (one per component)
│ ├── <component>.yaml # Points to manifests dir and/or Helm chart
│ └── ...
└── manifests/ # Kubernetes manifests grouped by component
├── <component>/
│ ├── <resource>.yaml # Stackable CRDs, TrinoCatalogs, ZookeeperZnodes, etc.
│ └── sealed-*.yaml # SealedSecrets (generated, do not edit by hand)
└── ...
secrets/ # Plaintext Kubernetes Secrets (source of truth for sealed secrets)
└── manifests/
└── <component>/
└── <secret-name>.yaml # Plain Secret, mirrors structure of platform/manifests/
dags/ # Airflow DAG files (git-synced into Airflow pods)
justfile # Task runner (just deploy, just seal-secrets)
Never apply changes directly to the Kubernetes cluster (no kubectl apply, helm install, etc.). All changes must be committed to Git and deployed through ArgoCD. ArgoCD has selfHeal: true enabled, so any manual changes will be reverted automatically.
- Create
platform/manifests/<component>/with the CRD yaml files. - Create
platform/applications/<component>.yaml— an ArgoCD Application pointing to the manifests dir:source: repoURL: "http://forgejo-http.deployment.svc.cluster.local:3000/stackable/openmetadata-dbt-demo.git" targetRevision: "main" path: platform/manifests/<component>/
- Commit and push. ArgoCD picks it up automatically via cluster-apps.
- Create
platform/applications/<component>.yamlwith a Helm source:sources: - repoURL: "https://<helm-repo-url>" chart: <chart-name> targetRevision: "<version>" # optional but recommended helm: releaseName: <component>
- Do NOT set
path:when usingchart:— they are mutually exclusive.
Use multi-source — one source for the Helm chart, one for the manifests dir:
sources:
- repoURL: "registry-1.docker.io/bitnamicharts"
chart: postgresql
targetRevision: 16.6.3
helm:
releaseName: postgresql-<component>
valuesObject:
auth:
existingSecret: <secret-name>
- repoURL: "http://forgejo-http.deployment.svc.cluster.local:3000/stackable/openmetadata-dbt-demo.git"
targetRevision: "main"
path: platform/manifests/<component>/- Create the plaintext Secret in
secrets/manifests/<component>/<secret-name>.yaml. - Run
just seal-secrets— this generatesplatform/manifests/<component>/sealed-<secret-name>.yaml. - Never edit sealed-* files by hand. Always edit the plaintext in
secrets/and re-seal.
| Namespace | Components |
|---|---|
deployment |
ArgoCD, SealedSecrets, Forgejo |
stackable-operators |
Stackable operators |
shared |
GarageFS, all PostgreSQL instances (airflow, hive, hive-iceberg, openmetadata, superset) |
platform |
Airflow, Trino, Hive, HDFS, ZooKeeper, Kafka, NiFi, OpenMetadata, OpenSearch, Superset, Lakekeeper, all init jobs |
Cross-namespace service references must use FQDNs (<svc>.<namespace>.svc.cluster.local).
Services within the same namespace can use short names.
All applications should use:
project: dbt-openmetadata-demo(except infrastructure-level apps which usedefault)destination.server: https://kubernetes.default.svcdestination.namespace:shared,platform, ordeploymentdepending on component (see Namespace Layout)syncPolicy.automated.selfHeal: trueandprune: truesyncPolicy.syncOptions: [CreateNamespace=true]source.repoURL: usehttp://forgejo-http.deployment.svc.cluster.local:3000/stackable/openmetadata-dbt-demo.gitfor Forgejo sources
just deploy— bootstrap the cluster with stackablectl (installs ArgoCD, Forgejo, then ArgoCD takes over)just seal-secrets— re-seal all plaintext secrets fromsecrets/intoplatform/manifests/