21 Deployment Dependencies - seadogger-tech/seadogger-homelab GitHub Wiki
Deployment Dependencies Analysis
GitHub Issues:
For the maintained operator entry points and validation command, read Deployment and Validation. The analysis below includes historical dependency proposals; inspect the linked playbooks for current ordering.
This document analyzes the "spider web" of deployment dependencies in the Seadogger Homelab and proposes solutions to untangle them.
Current Deployment Order (main.yml)
1. Raspberry Pi Configuration (all nodes)
2. K3s Control Plane (control_plane)
3. K3s Workers (nodes)
4. MetalLB (control_plane) β Infrastructure layer
5. Rook-Ceph (control_plane) β Infrastructure layer
6. ArgoCD (control_plane) β GitOps layer
7. Namespace Pre-cooking β Preparation
8. Internal PKI + Cert-Manager β Certificate infrastructure
9. Applications:
- Bedrock Gateway
- PiHole
- OpenWebUI
- N8N
- Nextcloud
- Jellyfin
Dependency Graph
Layer 0: Cluster Foundation
ββββββββββββββββββββ
β K3s Cluster β (control plane + workers)
ββββββββββ¬ββββββββββ
β
βββββ Required by: Everything else
Layer 1: Core Infrastructure
ββββββββββββββββββββ ββββββββββββββββββββ
β MetalLB β β Rook-Ceph β
β (Load Balancer) β β (Storage) β
ββββββββββ¬ββββββββββ ββββββββββ¬ββββββββββ
β β
β β
Required by: Required by:
- Traefik (ingress entry) - Nextcloud PVC
- Pi-hole DNS LB - Jellyfin PVC
- Other app PVCs
Layer 2: GitOps & PKI
ββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ
β ArgoCD β β Cert-Manager β β Internal PKI β
β (GitOps) β β (K8s Certs) β β (CA + Certs) β
ββββββββββ¬ββββββββββ ββββββββββ¬ββββββββββ ββββββββββ¬ββββββββββ
β β β
Required by: Required by: Required by:
- All apps via ArgoCD - All app TLS certs - Cert-Manager CA
- Infrastructure mgmt - Certificate CRDs - Traefik TLS
- Node trust stores
Layer 3: Applications
βββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ
β PiHole βNextcloudβJellyfin βOpenWebUIβ N8N β
βββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ
Detailed Dependency Analysis
1. MetalLB Dependencies
What ACTUALLY needs MetalLB:
- β Traefik - Ingress controller entry point (LoadBalancer for HTTP/HTTPS)
- β
PiHole - DNS service needs LoadBalancer IP for network DNS
pihole-values.yaml-serviceDns.loadBalancerIP: 192.168.1.250
What MetalLB depends on:
- K3s cluster (API server, CNI)
- Nothing else!
Current ordering: β CORRECT - MetalLB deployed before Traefik/PiHole
2. Rook-Ceph Dependencies
What depends on Rook-Ceph:
-
β Nextcloud - Uses
storageClassName: ceph-filesystem- Stores all user files, photos, documents
-
β Jellyfin - Uses static PV backed by Ceph
jellyfin/static-pv.yaml- Media library metadata
-
β N8N - Workflow persistence
-
β OpenWebUI - Chat history
What Rook-Ceph depends on:
- K3s cluster
- Storage nodes with available disks
- Nothing else!
Current ordering: β CORRECT - Rook-Ceph deployed before apps
Issue: Rook-Ceph is default(false) in main.yml but apps assume it exists!
# main.yml:51
- name: Deploy Rook-Ceph - Part 1 (Core Components)
import_tasks: tasks/rook_ceph_deploy_part1.yml
when: enable_rook_ceph_part1 | default(false) # β Default FALSE
Risk: If Rook-Ceph disabled, all apps fail with PVC binding issues!
3. ArgoCD Dependencies
What depends on ArgoCD:
- β
Most applications - Deployed via ArgoCD Application CRDs
- Nextcloud, PiHole, OpenWebUI, N8N, Jellyfin
What ArgoCD depends on:
- K3s cluster
- Optional: MetalLB for LoadBalancer service
- Nothing else!
Current ordering: β CORRECT - ArgoCD before apps
Hybrid Deployment Issue: Some components deployed via:
- Ansible direct Helm (MetalLB, Rook-Ceph)
- ArgoCD (apps via
kubernetes.core.k8screating Application CRDs) - Ansible kubectl apply (Ingress manifests downloaded from GitHub)
This creates inconsistency - no single source of truth!
4. Cert-Manager + Internal PKI Dependencies
What depends on Cert-Manager:
-
β All Application TLS Certificates - Uses Certificate CRD
argocd-certificate.yml- ArgoCD dashboard HTTPSnextcloud-certificate.yml- Nextcloud HTTPSjellyfin-certificate.yml- Jellyfin HTTPSpihole-certificate.yml- PiHole admin HTTPSn8n-certificate.yml- N8N HTTPSopenwebui-certificate.yml- OpenWebUI HTTPSceph-dashboard-certificate.yml- Ceph dashboard HTTPS
-
β Traefik Ingress - Consumes TLS secrets created by cert-manager
- IngressRoute objects reference TLS secrets
- Traefik terminates TLS at ingress using these certs
-
β Internal PKI ClusterIssuer - Must exist before Certificate resources
ClusterIssuer: internal-local-issuerreferences CA secret
What Cert-Manager depends on:
- CRITICAL: K3s cluster (API server, CRDs)
- CRITICAL: ArgoCD (deployed as ArgoCD Application)
cert-manager-application.yml- Uses Helm chart from Jetstack- Chart version: v1.14.4
installCRDs: true- Installs Certificate CRDs
What Internal PKI depends on:
- CRITICAL: Cert-Manager must be running first
- Creates CA hierarchy on control plane node (yoda)
- Root CA β Intermediate CA
- Stores CA keypairs as Kubernetes secrets in
cert-managernamespace
Current ordering: β CORRECT - Internal PKI deployed after ArgoCD/cert-manager
Current implementation flow:
# Step 1: ArgoCD deploys cert-manager (via Application CRD)
# Step 2: Ansible waits for cert-manager pods ready
# Step 3: Generate Root CA on yoda.local:
# - openssl genrsa (4096-bit root CA key)
# - openssl req -x509 (self-signed root cert, 10 years)
# Step 4: Generate Intermediate CA on yoda.local:
# - openssl genrsa (4096-bit intermediate key)
# - openssl req + x509 (signed by root CA, 5 years)
# Step 5: Create Kubernetes secrets in cert-manager namespace:
# - internal-intermediate-ca-secret (type: kubernetes.io/tls)
# - internal-root-ca-secret (type: Opaque, archival)
# Step 6: Create ClusterIssuer pointing to intermediate CA secret
# Step 7: Apply Certificate manifests for all apps
# Step 8: Distribute root CA to all nodes' trust stores
# - /usr/local/share/ca-certificates/internal-root-ca.crt
# - update-ca-certificates (Debian/Ubuntu)
Key Files:
ansible/tasks/internal_pki_deploy.yml(492 lines)certificates/cert-manager-application.yml(ArgoCD app)certificates/*-certificate.yml(7 app certificates)
Issue: Complex multi-step process mixing OpenSSL, Ansible, and Kubernetes
- CA generation on one node (yoda.local)
- Manual secret creation
- Certificate application via kubectl
- Trust distribution via Ansible
Opportunity: Could be simplified with cert-manager CA Injector or external-secrets operator
5. Application Dependencies
Nextcloud:
- CRITICAL: Rook-Ceph (
ceph-filesystemStorageClass) - CRITICAL: ArgoCD (deployed via Application CRD)
- Optional: MetalLB (if using LoadBalancer vs Ingress)
PiHole:
- CRITICAL: MetalLB (DNS needs LoadBalancer IP)
- CRITICAL: ArgoCD (deployed via Application CRD)
- Optional: Rook-Ceph (persistence disabled in current config)
Jellyfin:
- CRITICAL: Rook-Ceph (static PV for metadata)
- CRITICAL: ArgoCD (deployed via Application CRD)
- CRITICAL: Pre-existing PV/PVC for media mount
Problems with Current Approach
Problem 1: Implicit Dependencies
Dependencies are encoded in task execution order, not declared explicitly. A stateful application can reach its ArgoCD Application step before its storage class or PVC is usable. Check the intended prerequisites before that step.
Problem 2: Default Configuration Conflicts
# main.yml
enable_rook_ceph_part1: default(false) # Disabled by default!
enable_metallb_native: default(true) # Enabled by default
# But apps assume both are enabled:
# nextcloud-values.yaml:
storageClassName: ceph-filesystem # β Fails if Rook-Ceph disabled!
# pihole-values.yaml:
serviceDns:
type: LoadBalancer
loadBalancerIP: 192.168.1.250 # β Pending if MetalLB disabled!
Problem 3: External URL Dependencies
Multiple tasks download from GitHub during deployment:
# argocd_native_deploy.yml:103-106
- name: Download ArgoCD IngressRoutes manifest from GitHub
ansible.builtin.get_url:
url: "https://raw.githubusercontent.com/seadogger/seadogger-homelab/master/ingress/traefik-argocd-ingress.yml"
Risk:
- GitHub down = deployment fails
- Manifest changed = unexpected behavior
- No version control of exact manifest used
Problem 4: Mixed Deployment Methods
| Component | Method | Managed By | Issue |
|---|---|---|---|
| MetalLB | Ansible + Helm | Ansible | Can't see in ArgoCD UI |
| Rook-Ceph | Ansible + Helm | Ansible | Can't see in ArgoCD UI |
| Cert-Manager | ArgoCD Application | ArgoCD | β Consistent |
| Internal PKI | Ansible + OpenSSL | Ansible | Manual CA generation on yoda.local |
| Nextcloud | ArgoCD Application | ArgoCD | β Consistent |
| Ingress | Ansible + kubectl | Ansible | Separate from app deployment |
Problem: No single source of truth, drift between Ansible state and cluster state.
Problem 5: No Dependency Validation
Tasks don't check prerequisites:
# nextcloud_deploy.yml - No check for:
# β Is ArgoCD running?
# β Is Rook-Ceph ready?
# β Does ceph-filesystem StorageClass exist?
- name: Create Nextcloud ArgoCD Application
kubernetes.core.k8s:
state: present
definition:
apiVersion: argoproj.io/v1alpha1
kind: Application
# ... creates app that will fail if deps missing
Problem 6: Namespace Pre-cooking is Misplaced
# main.yml:60-66
# Namespaces created AFTER ArgoCD deployed
- name: Pre-cook Namespaces
import_tasks: tasks/namespaces_precook.yml
But ArgoCD has syncOptions: - CreateNamespace=true so this is redundant!
Problem 7: Complex PKI Bootstrap Process
The internal PKI setup is a 492-line Ansible task that:
- Runs OpenSSL commands on one specific node (yoda.local)
- Generates CA hierarchy outside Kubernetes
- Manually creates secrets in cert-manager namespace
- Distributes CA to all node trust stores via Ansible
- Applies Certificate manifests via kubectl
Issues:
- Fragile: Depends on yoda.local being available
- Not GitOps: CA generation not declarative
- Manual: Certificate manifests applied via Ansible, not ArgoCD
- Drift risk: Node trust stores managed outside K8s
Proposed Solutions
Solution 1: Explicit Dependency Checks (Immediate)
Add validation tasks before each deployment:
Example: Validate the storage class before deploying a stateful application:
- name: Check Rook-Ceph StorageClass exists
kubernetes.core.k8s_info:
kind: StorageClass
name: ceph-block-data
register: storage_class
failed_when: storage_class.resources | length == 0
Solution 2: Dependency Declaration with Ansible Role Dependencies
Restructure as roles with meta/main.yml dependencies:
# roles/nextcloud/meta/main.yml
---
dependencies:
- role: rook-ceph
- role: argocd
Ansible automatically ensures dependencies are installed first!
Benefits:
- β Explicit dependency graph
- β Automatic ordering
- β
Can run
ansible-playbooktargeting any role
Solution 3: ArgoCD ApplicationSets with Waves
Use ArgoCD sync waves to control ordering:
---
# argocd/infrastructure-appset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: infrastructure
namespace: argocd
spec:
generators:
- list:
elements:
# Wave 0: Core infrastructure
- name: metallb
namespace: metallb-system
wave: "0"
chart: metallb/metallb
- name: rook-ceph-operator
namespace: rook-ceph
wave: "0"
chart: rook-release/rook-ceph
- name: cert-manager
namespace: cert-manager
wave: "0"
chart: jetstack/cert-manager
# Wave 1: Storage cluster + PKI (depends on operator)
- name: rook-ceph-cluster
namespace: rook-ceph
wave: "1"
chart: rook-release/rook-ceph-cluster
- name: internal-pki
namespace: cert-manager
wave: "1"
path: deployments/infrastructure/base/internal-pki
template:
metadata:
name: '{{name}}'
annotations:
argocd.argoproj.io/sync-wave: "{{wave}}" # β Controls order!
spec:
project: default
source:
repoURL: '{{chart}}'
targetRevision: '{{version}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
# Wait for previous wave to complete
- RespectIgnoreDifferences=true
Benefits:
- β ArgoCD enforces dependencies automatically
- β Visible in ArgoCD UI with sync waves
- β Can manually re-sync any wave
- β Removes Ansible from deployment loop (only bootstrap ArgoCD)
Solution 4: Health Checks with Retry Logic
Wait for storage, certificates and load-balancer allocation when a dependent application needs them. Set bounded retries and report the missing prerequisite instead of continuing after a failed readiness check.
Solution 5: Remove External URL Dependencies
Store all manifests in Git repo:
Before:
- name: Download ArgoCD IngressRoutes from GitHub
ansible.builtin.get_url:
url: "https://raw.githubusercontent.com/.../traefik-argocd-ingress.yml"
After:
- name: Apply ArgoCD IngressRoutes from local repo
kubernetes.core.k8s:
definition: "{{ lookup('file', 'manifests/ingress/argocd.yml') }}"
Or better, bundle with Helm chart:
# argocd-chart/templates/ingress.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
# ...
Solution 6: Configuration Validation
Add Ansible assertions at playbook start:
---
# playbooks/validate-config.yml
- hosts: localhost
tasks:
- name: Validate required components are enabled
ansible.builtin.assert:
that:
- enable_metallb_native | bool
- enable_rook_ceph_part1 | bool
- enable_argocd_native | bool
fail_msg: |
ERROR: Core infrastructure components must be enabled!
Set in config.yml:
enable_metallb_native: true
enable_rook_ceph_part1: true
enable_argocd_native: true
- name: Validate storage class configuration
ansible.builtin.assert:
that:
- enable_rook_ceph_part1 | bool or default_storage_class is defined
fail_msg: "ERROR: No storage backend configured!"
Recommended Implementation Plan
Phase 1: Add Immediate Safeguards (Week 1)
-
Add pre-flight checks to each task
- Validate MetalLB before load-balanced services
- Validate Rook-Ceph before app deployments
- Validate ArgoCD before creating Applications
-
Add configuration validation playbook
- Run before main.yml
- Fail fast if requirements not met
-
Fix default values
# config.yml enable_rook_ceph_part1: true # Changed from false!
Phase 2: Store Manifests Locally (Week 2)
-
Copy all external manifests to repo
core/manifests/ βββ ingress/ β βββ argocd.yml β βββ ... βββ crds/ βββ configs/ -
Update tasks to use local files
Phase 3: Migrate to ArgoCD Sync Waves (Weeks 3-4)
-
Create ApplicationSets for infrastructure
- Wave 0: MetalLB, Rook-Ceph Operator
- Wave 1: Rook-Ceph Cluster
-
Create ApplicationSets for apps
- Wave 2: PiHole, Nextcloud, etc.
-
Simplify Ansible to only:
- Bootstrap K3s
- Deploy root ArgoCD application
- Everything else via GitOps
Phase 4: Convert to Ansible Roles (Weeks 5-6)
- Create role structure
- Add
meta/main.ymldependencies - Test in staging environment
Dependency Matrix
| Component | Depends On | Used By | Critical Path? |
|---|---|---|---|
| K3s Cluster | Hardware | Everything | β YES |
| MetalLB | K3s | Traefik, PiHole | β YES |
| Rook-Ceph | K3s, Storage devices | Persistent application volumes | β YES |
| ArgoCD | K3s | App deployments | β YES |
| Internal PKI | K3s | Traefik TLS | β οΈ Optional |
| Namespaces | K3s | Apps | β Auto-created by ArgoCD |
| Nextcloud | Rook-Ceph, ArgoCD | User files | App-level |
| PiHole | MetalLB, ArgoCD | DNS | App-level |
| Jellyfin | Rook-Ceph, ArgoCD, Static PV | Media | App-level |
Critical Path: K3s β MetalLB + Rook-Ceph β ArgoCD β Apps
Conclusion
The current deployment has an implicit dependency spider web where:
- Dependencies are encoded in execution order, not declared
- No validation that prerequisites are met
- Mixed deployment methods (Ansible + ArgoCD + kubectl)
- External URL dependencies create brittleness
Solutions:
- Immediate: Add pre-flight validation to each task
- Short-term: Store manifests locally, fix configuration defaults
- Medium-term: Migrate to ArgoCD sync waves for GitOps consistency
- Long-term: Convert to Ansible roles with explicit dependencies
Benefits:
- β Fail fast with clear errors
- β Self-documenting dependencies
- β Testable in staging
- β Single source of truth (Git)
- β Visible dependency graph
This transforms the "spider web" into a directed acyclic graph (DAG) that's explicit, validated, and maintainable.
Can Everything Be an ArgoCD App with Kustomize?
TL;DR: YES, with one exception (K3s itself)
What CAN be ArgoCD apps:
- β MetalLB
- β Rook-Ceph (both operator and cluster)
- β Cert-Manager (already is!)
- β Internal PKI (CA secrets + ClusterIssuer)
- β ArgoCD itself (self-managed!)
- β All applications (Nextcloud, PiHole, etc.)
- β Ingress resources
What CANNOT:
- β K3s installation (cluster must exist first)
- β ArgoCD bootstrap (chicken-and-egg, but see below)
- β οΈ CA generation (OpenSSL commands, but can be improved)
The Bootstrap Problem
You need ArgoCD to exist before it can manage itself. Solution: Bootstrap then self-manage
# Step 1: Ansible installs ArgoCD initially
- name: Bootstrap ArgoCD
kubernetes.core.helm:
name: argocd
chart_ref: argo/argo-cd
namespace: argocd
# Step 2: ArgoCD Application that manages ArgoCD itself
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: argocd
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/seadogger-tech/seadogger-homelab
path: deployments/argocd # β Kustomize overlay
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
After bootstrap, ArgoCD manages itself via GitOps!
Proposed Kustomize Structure
seadogger-homelab/
βββ deployments/
β βββ infrastructure/
β β βββ base/
β β β βββ metallb/
β β β β βββ kustomization.yaml
β β β β βββ namespace.yaml
β β β β βββ ipaddresspool.yaml
β β β βββ rook-ceph-operator/
β β β β βββ kustomization.yaml
β β β β βββ helm-values.yaml
β β β βββ rook-ceph-cluster/
β β β β βββ kustomization.yaml
β β β β βββ cluster.yaml
β β β β βββ storageclass.yaml
β β β βββ cert-manager/
β β β β βββ kustomization.yaml
β β β β βββ helm-values.yaml
β β β βββ internal-pki/
β β β β βββ kustomization.yaml
β β β β βββ ca-secret.yaml # β Sealed or external-secrets
β β β β βββ clusterissuer.yaml
β β β β βββ certificates/ # β All app certs
β β βββ overlays/
β β βββ production/
β β β βββ kustomization.yaml # IP addresses, sizes
β β βββ staging/
β β βββ kustomization.yaml # Smaller, different IPs
β β
β βββ apps/
β β βββ base/
β β β βββ nextcloud/
β β β β βββ kustomization.yaml
β β β β βββ values.yaml
β β β β βββ ingress.yaml
β β β βββ pihole/
β β β βββ jellyfin/
β β β βββ portal/ # β Already done in Pro!
β β βββ overlays/
β β βββ production/
β β βββ staging/
β β
β βββ argocd/
β βββ root-app.yaml # App-of-apps
β βββ infrastructure-appset.yaml
β βββ apps-appset.yaml
β
βββ ansible/
βββ playbooks/
βββ bootstrap.yml # ONLY installs K3s + ArgoCD root app
How ArgoCD Handles Helm with Kustomize
Option 1: ArgoCD native Helm support (Current)
# argocd/apps/nextcloud.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nextcloud
spec:
source:
repoURL: https://nextcloud.github.io/helm/
chart: nextcloud
targetRevision: "7.0.2"
helm:
valueFiles:
- $values/deployments/nextcloud/values.yaml
sources:
- repoURL: https://github.com/seadogger-tech/seadogger-homelab
targetRevision: main
ref: values
Option 2: Kustomize with helmCharts (More flexible)
# deployments/nextcloud/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
helmCharts:
- name: nextcloud
repo: https://nextcloud.github.io/helm/
version: "7.0.2"
releaseName: nextcloud
namespace: nextcloud
valuesFile: values.yaml
resources:
- ingress.yaml # Bundle ingress with app!
patches:
- target:
kind: Deployment
name: nextcloud
patch: |-
- op: add
path: /spec/template/spec/nodeSelector
value:
kubernetes.io/arch: arm64
Rook-Ceph as ArgoCD App (Full Example)
Operator Application:
---
# argocd/infrastructure-apps/rook-ceph-operator.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: rook-ceph-operator
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "0"
spec:
project: default
source:
repoURL: https://github.com/seadogger-tech/seadogger-homelab
path: deployments/infrastructure/base/rook-ceph-operator
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: rook-ceph
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Cluster Application (waits for operator):
---
# argocd/infrastructure-apps/rook-ceph-cluster.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: rook-ceph-cluster
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "1" # After operator!
spec:
project: default
source:
repoURL: https://github.com/seadogger-tech/seadogger-homelab
path: deployments/infrastructure/overlays/production/rook-ceph-cluster
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: rook-ceph
syncPolicy:
automated:
prune: false # Don't auto-delete storage!
selfHeal: true
syncOptions:
- ServerSideApply=true # For large CRDs
Kustomize structure:
# deployments/infrastructure/base/rook-ceph-cluster/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cluster.yaml
- storageclass-block.yaml
- storageclass-filesystem.yaml
- toolbox.yaml
- ingress.yaml # β Bundle ingress!
Production overlay:
# deployments/infrastructure/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base/rook-ceph-cluster
patches:
- target:
kind: CephCluster
patch: |-
- op: replace
path: /spec/storage/devices
value:
- name: /dev/nvme0n1p3 # Production NVMe
What Ansible Does (Minimal!)
---
# ansible/playbooks/bootstrap.yml
- name: Bootstrap Homelab
hosts: cluster
tasks:
# Stage 1: Install K3s
- import_role:
name: k3s
# Stage 2: Install ArgoCD
- import_role:
name: argocd-bootstrap
# Stage 3: Deploy root app
- name: Deploy root app-of-apps
kubernetes.core.k8s:
definition: "{{ lookup('file', '../deployments/argocd/root-app.yaml') }}"
# DONE! ArgoCD handles the rest
Migration Path
Phase 1: Store everything in Git (Week 1)
# Move external URLs to Git
mkdir -p core/deployments/manifests/{crds,ingress}
# All ingress manifests
mv core/ingress/*.yml core/deployments/manifests/ingress/
Phase 2: Convert to Kustomize (Weeks 2-3)
# For each component:
mkdir -p deployments/infrastructure/base/metallb
# Create kustomization.yaml, resources
Phase 3: Create ArgoCD Apps (Weeks 3-4)
# Deploy via ArgoCD
kubectl apply -f deployments/argocd/infrastructure-appset.yaml
Phase 4: Remove Ansible (Weeks 4-5)
# Delete deployment tasks, keep only bootstrap
rm ansible/tasks/*_deploy.yml
Portal Proof of Concept (Already Working!)
# deployments/portal/kustomization.yaml (Pro repo)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: portal
resources:
- deployment.yaml
- service.yaml
- ingressroutes.yml
- certificate.yml
configMapGenerator:
- name: portal-html
files:
- index.html=portal.html
This pattern works! Just replicate for all components.
Benefits of Full GitOps
β Single source of truth - Everything in Git β Visible in ArgoCD UI - See all apps, dependencies, health β Automatic sync - Git commit = cluster update β Easy rollback - Revert Git commit β Production/Staging overlays - Same base, different configs β No Ansible sprawl - Just bootstrap, rest is GitOps β Testable - Staging environment uses same manifests
Answer: YES, Everything Can Be ArgoCD + Kustomize!
Summary:
- β K3s - Ansible only (must exist first)
- β ArgoCD - Bootstrap with Ansible, then self-manage
- β MetalLB - ArgoCD app (wave 0)
- β Rook-Ceph - ArgoCD apps (wave 0-1)
- β All Apps - ArgoCD apps after their prerequisites
- β Ingress - Bundled with each app
Portal in Pro already proves this works!