Skip to content

Commit bf30105

Browse files
committed
up
1 parent 4178e17 commit bf30105

6 files changed

Lines changed: 58 additions & 48 deletions

File tree

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ A GitOps-driven Kubernetes cluster using **Talos OS** (secure, immutable Linux f
3434
```mermaid
3535
graph TD;
3636
subgraph "Bootstrap Process (Manual)"
37-
User(["👨‍💻 User"]) -- "kubectl apply -k" --> Kustomization["infrastructure/controllers/argocd/kustomization.yaml"];
37+
User(["👨‍💻 User"]) -- "kubectl apply -k" --> Kustomization["infrastructure/argocd/kustomization.yaml"];
3838
Kustomization -- "Deploys" --> ArgoCD["ArgoCD<br/>(from Helm Chart)"];
3939
Kustomization -- "Deploys" --> RootApp["Root Application<br/>(root.yaml)"];
4040
end
@@ -54,8 +54,8 @@ graph TD;
5454
```
5555

5656
### Key Features
57-
- **Enterprise GitOps Pattern**: ApplicationSets provide clean separation of concerns.
58-
- **Self-Managing ArgoCD**: ArgoCD manages its own installation, upgrades, and ApplicationSets from a co-located `apps` directory.
57+
- **2025 Homelab GitOps Pattern**: Flattened ApplicationSets provide clean separation of concerns.
58+
- **Self-Managing ArgoCD**: ArgoCD manages its own installation, upgrades, and ApplicationSets from Git.
5959
- **Simple Directory Discovery**: Applications are discovered automatically based on their directory path. No extra files needed.
6060
- **Production Ready**: Proper error handling, retries, and monitoring integration.
6161
- **GPU Integration**: Full NVIDIA GPU support via Talos system extensions and GPU Operator
@@ -151,7 +151,7 @@ This final step uses our "App of Apps" pattern to bootstrap the entire cluster.
151151
```bash
152152
# 1. Apply the ArgoCD main components and CRDs
153153
# This deploys the ArgoCD Helm chart, which creates the CRDs and controller.
154-
kustomize build infrastructure/controllers/argocd --enable-helm | kubectl apply -f -
154+
kustomize build infrastructure/argocd --enable-helm | kubectl apply -f -
155155
156156
# 2. Wait for the ArgoCD CRDs to be established in the cluster
157157
# This command pauses until the Kubernetes API server recognizes the 'Application' resource type.
@@ -167,15 +167,15 @@ kubectl wait --for=condition=Available deployment/argocd-server -n argocd --time
167167
# Now that ArgoCD is running and its CRDs are ready, we can apply the 'root' application
168168
# to kickstart the self-managing GitOps loop.
169169
echo "Applying the root application..."
170-
kubectl apply -f infrastructure/controllers/argocd/root.yaml
170+
kubectl apply -f infrastructure/argocd/root.yaml
171171
```
172172
**That's it!** You have successfully and reliably bootstrapped the cluster.
173173
174174
### What Happens Next Automatically?
175175
176-
1. **ArgoCD Syncs Itself**: The `root` Application tells ArgoCD to sync the contents of `infrastructure/controllers/argocd/apps/`.
176+
1. **ArgoCD Syncs Itself**: The `root` Application tells ArgoCD to sync the contents of `infrastructure/argocd/apps/`.
177177
2. **Projects & AppSets Created**: ArgoCD creates the `AppProject`s and the three `ApplicationSet`s (`infrastructure`, `monitoring`, `my-apps`).
178-
3. **Applications Discovered**: The `ApplicationSet`s scan the repository for any directories matching their defined paths (e.g., `my-apps/*/*`) and create the corresponding ArgoCD `Application` resources.
178+
3. **Applications Discovered**: The `ApplicationSet`s scan the repository for any directories matching their defined paths (e.g., `infrastructure/*`, `monitoring/*`, `my-apps/*/*`) and create the corresponding ArgoCD `Application` resources.
179179
4. **Cluster Reconciliation**: ArgoCD syncs all discovered applications, building the entire cluster state declaratively from Git.
180180
181181
## 🔍 Verification
@@ -376,12 +376,12 @@ kubectl delete applications --all -n argocd
376376
kubectl get applicationsets -n argocd -o name | xargs -I{} kubectl patch {} -n argocd --type json -p '[{"op": "remove","path": "/metadata/finalizers"}]'
377377
kubectl delete applicationsets --all -n argocd
378378
379-
# Bootstrap with the new enterprise pattern
379+
# Bootstrap with the new 2025 homelab pattern
380380
# Note: This is the full, correct bootstrap sequence.
381-
kustomize build infrastructure/controllers/argocd --enable-helm | kubectl apply -f -
381+
kustomize build infrastructure/argocd --enable-helm | kubectl apply -f -
382382
kubectl wait --for condition=established --timeout=60s crd/applications.argoproj.io
383383
kubectl wait --for=condition=Available deployment/argocd-server -n argocd --timeout=300s
384-
kubectl apply -f infrastructure/controllers/argocd/root.yaml
384+
kubectl apply -f infrastructure/argocd/root.yaml
385385
```
386386
387387
## 🚀 Taking to Production

docs/argocd.md

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The deployment flow is a two-phase process: a one-time manual bootstrap, followe
1111
```mermaid
1212
graph TD;
1313
subgraph "Bootstrap Process (Manual)"
14-
User(["👨‍💻 User"]) -- "kubectl apply -k" --> Kustomization["infrastructure/controllers/argocd/kustomization.yaml"];
14+
User(["👨‍💻 User"]) -- "kubectl apply -k" --> Kustomization["infrastructure/argocd/kustomization.yaml"];
1515
Kustomization -- "Deploys" --> ArgoCD["ArgoCD<br/>(from Helm Chart)"];
1616
Kustomization -- "Deploys" --> RootApp["Root Application<br/>(root.yaml)"];
1717
end
@@ -47,7 +47,7 @@ This final step uses our "App of Apps" pattern to bootstrap the entire cluster.
4747
```bash
4848
# 1. Apply the ArgoCD main components and CRDs
4949
# This deploys the ArgoCD Helm chart, which creates the CRDs and controller.
50-
kustomize build infrastructure/controllers/argocd --enable-helm | kubectl apply -f -
50+
kustomize build infrastructure/argocd --enable-helm | kubectl apply -f -
5151

5252
# 2. Wait for the ArgoCD CRDs to be established in the cluster
5353
# This command pauses until the Kubernetes API server recognizes the 'Application' resource type.
@@ -63,7 +63,7 @@ kubectl wait --for=condition=Available deployment/argocd-server -n argocd --time
6363
# Now that ArgoCD is running and its CRDs are ready, we can apply the 'root' application
6464
# to kickstart the self-managing GitOps loop.
6565
echo "Applying the root application..."
66-
kubectl apply -f infrastructure/controllers/argocd/root.yaml
66+
kubectl apply -f infrastructure/argocd/root.yaml
6767
```
6868
**That's it!** ArgoCD will now manage itself and deploy everything else automatically.
6969

@@ -75,20 +75,20 @@ ArgoCD projects define permissions and boundaries for applications. Our cluster
7575
- **monitoring**: Observability stack (Prometheus, Grafana, Loki, etc.)
7676
- **my-apps**: All user workloads (media, AI, dev, privacy, etc.)
7777

78-
These `AppProject` resources are defined in `infrastructure/controllers/argocd/apps/projects.yaml` and are managed automatically by the `root` ArgoCD application.
78+
These `AppProject` resources are defined in `infrastructure/argocd/apps/projects.yaml` and are managed automatically by the `root` ArgoCD application.
7979

8080
## 📱 ApplicationSet Management
8181

82-
We use **three simple ApplicationSets** that discover applications based on their directory structure. This follows a "convention over configuration" approach, eliminating the need for metadata files.
82+
We use **three simple ApplicationSets** that discover applications based on their directory structure. This follows a "convention over configuration" approach, eliminating the need for metadata files, and follows **2025 homelab best practices** with a flattened structure.
8383

8484
### 1. The "Directory as Application" Pattern
85-
Instead of relying on marker files, our `ApplicationSet`s discover applications by looking for directories that match a predefined path pattern. The application's name and target namespace are derived directly from this path. Each `ApplicationSet` is pointed to a specific path to discover its apps:
86-
- **Infrastructure:** `infrastructure/controllers/apps/*`
87-
- **Monitoring:** `monitoring/*`
88-
- **My Apps:** `my-apps/*/*`
85+
Instead of relying on marker files, our `ApplicationSet`s discover applications by looking for directories that match a predefined path pattern. The application's name and target namespace are derived directly from this path. Each `ApplicationSet` is co-located with its applications:
86+
- **Infrastructure:** `infrastructure/*` (defined in `infrastructure/infrastructure-appset.yaml`)
87+
- **Monitoring:** `monitoring/*` (defined in `monitoring/monitoring-appset.yaml`)
88+
- **My Apps:** `my-apps/*/*` (defined in `my-apps/my-apps-appset.yaml`)
8989

9090
### 2. ApplicationSet Configuration
91-
All `ApplicationSet`s live in `infrastructure/controllers/argocd/apps/appsets/` and follow the same pattern. Here is the `my-apps-appset.yaml` as an example:
91+
Each `ApplicationSet` is **co-located** with its applications, following peer-level organization. Here is the `my-apps-appset.yaml` as an example:
9292

9393
```yaml
9494
apiVersion: argoproj.io/v1alpha1
@@ -134,43 +134,48 @@ spec:
134134
135135
## 📂 Repository Structure
136136
137-
The repository structure is designed for clarity and to prevent recursive management loops.
137+
The repository structure follows **2025 homelab best practices** with a flattened, peer-level organization designed for clarity and to prevent recursive management loops.
138138
139139
```
140140
├── infrastructure/
141-
── controllers/
142-
├── argocd/ # <-- Manually bootstrapped, NOT in AppSet
143-
── apps/ # <-- ArgoCD's OWN config (Projects/AppSets)
144-
│ └── ...
145-
│ └── ...
146-
── apps/ # <-- Scanned by infrastructure-appset
147-
├── cert-manager/
148-
└── ...
141+
── argocd/ # <-- Manually bootstrapped, NOT in AppSet
142+
├── apps/ # <-- ArgoCD's OWN config (Projects/AppSets)
143+
── ...
144+
│ │ └── ...
145+
├── infrastructure-appset.yaml # <-- ApplicationSet co-located with apps
146+
── cert-manager/ # <-- Scanned by infrastructure-appset
147+
├── longhorn/ # <-- Scanned by infrastructure-appset
148+
│ └── ...
149149
├── monitoring/
150-
│ └── prometheus-stack/ # <-- Scanned by monitoring-appset
151-
│ └── ...
150+
│ ├── monitoring-appset.yaml # <-- ApplicationSet co-located with apps
151+
│ ├── prometheus-stack/ # <-- Scanned by monitoring-appset
152+
│ ├── loki-stack/ # <-- Scanned by monitoring-appset
153+
│ └── ...
152154
└── my-apps/
155+
├── my-apps-appset.yaml # <-- ApplicationSet co-located with apps
153156
└── development/
154157
└── nginx/ # <-- Scanned by my-apps-appset
155158
└── ...
156159
```
157160

158161
## ✅ Key Features
159162

160-
1. **Co-located & Self-Managing ArgoCD**:
161-
- ArgoCD's entire configuration lives logically within `infrastructure/controllers/argocd`.
163+
1. **Flattened & Self-Managing ArgoCD**:
164+
- ArgoCD's entire configuration lives within `infrastructure/argocd`.
162165
- The `root` application manages the projects and `ApplicationSet`s from its own `apps/` subdirectory.
163-
- **Crucially, ArgoCD's configuration is structurally isolated from other infrastructure apps, preventing recursive management loops.**
166+
- **ApplicationSets are co-located with their applications**, following 2025 homelab best practices.
167+
- **ArgoCD's configuration is structurally isolated from other infrastructure apps, preventing recursive management loops.**
164168

165-
2. **Enterprise Pattern**:
166-
- Clear separation of concerns with three `ApplicationSet`s.
167-
- Follows GitOps best practices used in production.
169+
2. **2025 Homelab Pattern**:
170+
- Flattened peer-level organization eliminates confusing nested structures.
171+
- Clear separation of concerns with three co-located `ApplicationSet`s.
172+
- Follows modern GitOps best practices optimized for homelab simplicity.
168173

169174
3. **Simple Directory Discovery**:
170175
- Applications are discovered automatically based on their directory structure. This is flexible, clear, and requires no boilerplate.
171176

172177
4. **Production Ready**:
173-
- The `ApplicationSet`s use `preserveResourcesOnDeletion: true` as a safety mechanism to prevent accidental mass-deletions.
178+
- The `ApplicationSet`s use automated sync policies with proper safety mechanisms.
174179

175180
## 🚀 Deployment Workflow
176181

@@ -185,7 +190,7 @@ The deployment is triggered by a merge to the `main` branch. The bootstrap is a
185190

186191
```bash
187192
# Bootstrap ArgoCD and the entire cluster
188-
kustomize build infrastructure/controllers/argocd --enable-helm | kubectl apply -f -
193+
kustomize build infrastructure/argocd --enable-helm | kubectl apply -f -
189194

190195
# Monitor deployment progress
191196
kubectl get applications -n argocd -w
@@ -203,9 +208,13 @@ kubectl get applications -n argocd -l argocd.argoproj.io/project=my-apps
203208

204209
The `ApplicationSet`s use the directory `path` to automatically generate the application name and target namespace. This creates a consistent and predictable naming scheme.
205210

206-
- **Application Name**: Combines the project (`my-apps`, `infrastructure`, `monitoring`) with the directory path.
207-
- `my-apps/development/nginx` -> `my-apps-nginx-development`
211+
- **Application Name**: Combines the project prefix with the directory path.
212+
- `infrastructure/cert-manager` -> `infra-cert-manager`
213+
- `monitoring/prometheus-stack` -> `monitoring-prometheus-stack`
214+
- `my-apps/development/nginx` -> `my-apps-nginx`
208215
- **Target Namespace**: Uses the final directory in the path.
216+
- `infrastructure/cert-manager` -> `cert-manager`
217+
- `monitoring/prometheus-stack` -> `prometheus-stack`
209218
- `my-apps/development/nginx` -> `nginx`
210219

211220
## Best Practices
@@ -232,10 +241,11 @@ kubectl describe application my-apps-nginx-development -n argocd
232241
### Common Issues
233242
| Issue | Solution |
234243
|-------|----------|
235-
| **ApplicationSet not generating apps** | Verify the directory structure matches the `path` pattern in the `ApplicationSet`. Check the `ApplicationSet` controller logs in the `argocd` namespace. Also ensure you are not accidentally excluding the path you want to deploy. |
236-
| **Recursive loop or Helm error on `infra-argocd`** | This error occurs if the `infrastructure-appset` is configured to scan a path that includes the `infrastructure/controllers/argocd` directory. The solution is to isolate discoverable applications into a dedicated subdirectory (e.g., `infrastructure/controllers/apps`) and point the ApplicationSet generator to that specific path, ensuring ArgoCD's own configuration is never discovered. |
237-
| **Applications stuck in sync** | Review application logs (`argocd app logs <app-name>`) and check for sync errors in the UI. |
238-
| **ArgoCD UI not accessible** | Check the `http-route.yaml` and the status of the `istio-ingressgateway` service. |
244+
| **ApplicationSet not generating apps** | Verify the directory structure matches the `path` pattern in the `ApplicationSet`. Check the `ApplicationSet` controller logs in the `argocd` namespace. Ensure directories have valid `kustomization.yaml` files. |
245+
| **Recursive loop or Helm error on `infra-argocd`** | This error occurs if the `infrastructure-appset` is configured to scan a path that includes the `infrastructure/argocd` directory. The ApplicationSet excludes `infrastructure/argocd` to prevent this issue. Verify the exclude patterns in `infrastructure/infrastructure-appset.yaml`. |
246+
| **Applications stuck in sync** | Review application logs (`argocd app logs <app-name>`) and check for sync errors in the UI. Check if Helm charts require `--enable-helm` flag. |
247+
| **ArgoCD UI not accessible** | Check the `http-route.yaml` and the status of the Gateway API or ingress controller. |
248+
| **Nested kustomization Helm issues** | The 2025 structure flattens nested kustomizations to avoid `--enable-helm` inheritance issues. If you see Helm chart errors, ensure the chart is defined at the ApplicationSet target level, not nested. |
239249

240250
### ArgoCD Self-Management
241251
```
File renamed without changes.

infrastructure/argocd/apps/kustomization.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1
22
kind: Kustomization
33
resources:
44
- projects.yaml
5-
- ../../../infrastructure/infrastructure-appset.yaml
6-
- ../../../monitoring/monitoring-appset.yaml
7-
- ../../../my-apps/my-apps-appset.yaml
5+
- infrastructure-appset.yaml
6+
- monitoring-appset.yaml
7+
- my-apps-appset.yaml
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)