add argocd documentation
This commit is contained in:
18
README.md
18
README.md
@@ -12,6 +12,7 @@ A self-hosted homelab running on Docker Compose, built and maintained on an Ubun
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||
|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
@@ -46,7 +47,7 @@ This is a real, running homelab — not a demo. It's deployed on a home Ubuntu s
|
|||||||
| **Custom CI images** | `docker-compose/gitlab/ci-images-reference/` | Self-built, minimal Docker images for CI pipelines, stored in a self-hosted Container Registry, rebuilt biweekly — see [Custom CI Runner Images](docs/CI-Custom-Images.md) |
|
| **Custom CI images** | `docker-compose/gitlab/ci-images-reference/` | Self-built, minimal Docker images for CI pipelines, stored in a self-hosted Container Registry, rebuilt biweekly — see [Custom CI Runner Images](docs/CI-Custom-Images.md) |
|
||||||
| **Voting app CI/CD** | `voting-app-monorepo` (self-hosted GitLab, referenced here) | Full pipeline: build, test, vulnerability scan, 3-environment deploy with rollback, load test, DB backup to MinIO — see [Voting App — Mono-Repo](docs/Voting-App-Monorepo.md) |
|
| **Voting app CI/CD** | `voting-app-monorepo` (self-hosted GitLab, referenced here) | Full pipeline: build, test, vulnerability scan, 3-environment deploy with rollback, load test, DB backup to MinIO — see [Voting App — Mono-Repo](docs/Voting-App-Monorepo.md) |
|
||||||
| **Object storage** | `docker-compose/minio/` | Self-hosted MinIO (S3-compatible), `-cpuv1` release tag for CPU compatibility — backup target for the voting app's Postgres dumps |
|
| **Object storage** | `docker-compose/minio/` | Self-hosted MinIO (S3-compatible), `-cpuv1` release tag for CPU compatibility — backup target for the voting app's Postgres dumps |
|
||||||
| **K3s cluster** | `kubernetes/` | Single-node K3s cluster running alongside the Docker Compose stack, fronted by the same reverse proxy via NodePort, monitored through the same Prometheus/Grafana/Loki stack — see [K3s](docs/K3s.md) |
|
| **K3s cluster** | `kubernetes/` | Single-node K3s cluster running alongside the Docker Compose stack, fronted by the same reverse proxy via NodePort on ingress-nginx, managed via **Argo CD** GitOps (applications/ and argocd-apps/ folders) — monitored through the same Prometheus/Grafana/Loki stack — see [K3s](docs/K3s.md) and [ArgoCD](docs/argocd.md) |
|
||||||
|
|
||||||
## Learning labs (not always-on)
|
## Learning labs (not always-on)
|
||||||
|
|
||||||
@@ -191,6 +192,7 @@ homelab/
|
|||||||
│ ├── Architecture-and-Hardware.md
|
│ ├── Architecture-and-Hardware.md
|
||||||
│ ├── Monitoring-Stack.md
|
│ ├── Monitoring-Stack.md
|
||||||
│ ├── K3s.md
|
│ ├── K3s.md
|
||||||
|
│ ├── ArgoCD.md
|
||||||
│ ├── Network-Services.md
|
│ ├── Network-Services.md
|
||||||
│ ├── Media-Automation.md
|
│ ├── Media-Automation.md
|
||||||
│ ├── Workflow-Automation.md
|
│ ├── Workflow-Automation.md
|
||||||
@@ -209,6 +211,18 @@ homelab/
|
|||||||
├── kubernetes/
|
├── kubernetes/
|
||||||
│ ├── alloy-rbac/
|
│ ├── alloy-rbac/
|
||||||
│ │ └── alloy-rbac.yaml
|
│ │ └── alloy-rbac.yaml
|
||||||
|
│ ├── apps/
|
||||||
|
│ │ ├── README.md
|
||||||
|
│ │ └── homepage/
|
||||||
|
│ │ ├── configmap.yaml
|
||||||
|
│ │ ├── deployment.yaml
|
||||||
|
│ │ ├── ingress.yaml
|
||||||
|
│ │ ├── kustomization.yaml
|
||||||
|
│ │ └── service.yaml
|
||||||
|
│ ├── argocd-apps/
|
||||||
|
│ │ ├── README.md
|
||||||
|
│ │ └── homepage/
|
||||||
|
│ │ └── homepage-app.yaml
|
||||||
│ ├── kube-state-metrics/
|
│ ├── kube-state-metrics/
|
||||||
│ │ ├── kube-state-metrics.yaml
|
│ │ ├── kube-state-metrics.yaml
|
||||||
│ │ └── prometheus-rbac.yaml
|
│ │ └── prometheus-rbac.yaml
|
||||||
@@ -245,6 +259,8 @@ docker compose up -d
|
|||||||
|
|
||||||
Rather than pulling and recreating manually, every always-on stack has a matching Ansible playbook that pulls the latest images, recreates containers, verifies they're healthy, and prunes unused images — run through Semaphore's web UI. See [Ansible Playbooks](docs/AnsiblePlaybooks.md) for details on how the shared role works.
|
Rather than pulling and recreating manually, every always-on stack has a matching Ansible playbook that pulls the latest images, recreates containers, verifies they're healthy, and prunes unused images — run through Semaphore's web UI. See [Ansible Playbooks](docs/AnsiblePlaybooks.md) for details on how the shared role works.
|
||||||
|
|
||||||
|
For the K3s cluster, updates are GitOps-driven rather than Ansible-driven: Kubernetes manifests live in `kubernetes/apps/`, one folder per app with a `kustomization.yaml`, and [Argo CD](docs/argocd.md) continuously syncs the cluster to match whatever is on `main` — no manual `kubectl apply` after the initial setup. New apps are added by dropping the manifests in `kubernetes/apps/<name>/` and the corresponding `Application` in `kubernetes/argocd-apps/<name>/`.
|
||||||
|
|
||||||
## Security notes
|
## Security notes
|
||||||
|
|
||||||
- All `.env` files, runtime config directories, and databases are excluded via `.gitignore` — only deployment definitions (`docker-compose.yml`) and `.env.example` placeholders are tracked.
|
- All `.env` files, runtime config directories, and databases are excluded via `.gitignore` — only deployment definitions (`docker-compose.yml`) and `.env.example` placeholders are tracked.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ Documentation for a self-hosted homelab running entirely on Docker Compose. This
|
|||||||
- [Monitoring Stack](Monitoring-Stack.md)
|
- [Monitoring Stack](Monitoring-Stack.md)
|
||||||
- [Alerting](Alerting.md)
|
- [Alerting](Alerting.md)
|
||||||
- [K3s](K3s.md)
|
- [K3s](K3s.md)
|
||||||
|
- [ArgoCD](ArgoCD.md)
|
||||||
- [Network Services](Network-Services.md)
|
- [Network Services](Network-Services.md)
|
||||||
- [Media Automation](Media-Automation.md)
|
- [Media Automation](Media-Automation.md)
|
||||||
- [Workflow Automation](Workflow-Automation.md)
|
- [Workflow Automation](Workflow-Automation.md)
|
||||||
@@ -41,7 +42,7 @@ Documentation for a self-hosted homelab running entirely on Docker Compose. This
|
|||||||
| **Registry** | **Nexus3** (Docker Hub pull-through cache + artifact repo) |
|
| **Registry** | **Nexus3** (Docker Hub pull-through cache + artifact repo) |
|
||||||
| **Passwords** | **Vaultwarden** (Bitwarden-compatible, 30+ char passwords) |
|
| **Passwords** | **Vaultwarden** (Bitwarden-compatible, 30+ char passwords) |
|
||||||
| **CI/CD** | Self-hosted **GitLab** (Omnibus) + Docker-executor **Runner** |
|
| **CI/CD** | Self-hosted **GitLab** (Omnibus) + Docker-executor **Runner** |
|
||||||
| **Orchestration (K8s)** | Single-node **K3s** cluster, monitored via the same Prometheus/Grafana/Loki stack |
|
| **Orchestration (K8s)** | Single-node **K3s** cluster, fronted by **Traefik** via ingress-nginx NodePort, managed via **Argo CD** GitOps (manifests in `kubernetes/apps/`, watched by `kubernetes/argocd-apps/`), monitored via the same Prometheus/Grafana/Loki stack |
|
||||||
|
|
||||||
This is a running system, not a demo — screenshots throughout this wiki are from the live dashboards.
|
This is a running system, not a demo — screenshots throughout this wiki are from the live dashboards.
|
||||||
|
|
||||||
|
|||||||
19
docs/K3s.md
19
docs/K3s.md
@@ -22,9 +22,24 @@ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server \
|
|||||||
- **`--flannel-backend=vxlan`** — explicit rather than relying on the default, and chosen over `host-gw` since VXLAN works across nodes that aren't on the same L2 segment, keeping the door open for a future worker node.
|
- **`--flannel-backend=vxlan`** — explicit rather than relying on the default, and chosen over `host-gw` since VXLAN works across nodes that aren't on the same L2 segment, keeping the door open for a future worker node.
|
||||||
- **`--write-kubeconfig-mode=644`** — makes `/etc/rancher/k3s/k3s.yaml` world-readable so a personal, non-root kubeconfig copy can be made without repeated `sudo`.
|
- **`--write-kubeconfig-mode=644`** — makes `/etc/rancher/k3s/k3s.yaml` world-readable so a personal, non-root kubeconfig copy can be made without repeated `sudo`.
|
||||||
|
|
||||||
## Exposure pattern: NPM in front, NodePort behind
|
## Exposure pattern: Traefik → ingress-nginx → Ingress
|
||||||
|
|
||||||
Rather than running a second ingress controller inside the cluster (which would mean two reverse proxies stacked for no benefit), each service gets a `Service` of `type: NodePort`. The existing reverse proxy adds one more proxy host pointing at `homeserver:<nodeport>` — identical to how it already fronts every Docker container. From the proxy's perspective, a K8s pod behind a NodePort is indistinguishable from a Docker container; same TLS setup, same cert renewal flow, zero new moving parts in the HTTPS chain.
|
K3s is fronted by the existing Docker-side Traefik reverse proxy, which already owns ports 80/443 (see [Reverse Proxy](Reverse-Proxy.md)). Because K3s itself can't bind those ports, the current standard for exposing an in-cluster service is:
|
||||||
|
|
||||||
|
```
|
||||||
|
Client → Traefik (:80/:443) → ingress-nginx NodePort → Ingress → Service → Pod
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Traefik** (Docker container) terminates TLS (`*.home.server` via mkcert) and routes by `Host` header, same as every Docker Compose service.
|
||||||
|
2. **ingress-nginx** runs inside K3s. Its `Service` is exposed as a **NodePort** on the host, giving Traefik a stable `homeserver:<nodeport>` target to forward to — no new ports on the K3s side, no port conflicts with the host's Traefik.
|
||||||
|
3. **ingress-nginx** (the in-cluster Ingress controller) matches the request against `Ingress` resources in the cluster and forwards to the right `Service`.
|
||||||
|
4. **Service → Pod** as normal Kubernetes routing.
|
||||||
|
|
||||||
|
This keeps a single TLS termination layer and a single DNS entry point (`*.home.server` via Pi-hole), while letting in-cluster `Ingress` resources carry the routing logic as code alongside the workloads they protect. Any app deployed via [Argo CD](ArgoCD.md) follows this pattern — its `Ingress` (e.g., `kubernetes/apps/homepage/ingress.yaml`) is served by ingress-nginx behind the NodePort.
|
||||||
|
|
||||||
|
### Legacy NodePort-only services
|
||||||
|
|
||||||
|
The earlier kube-state-metrics deployment was exposed as a standalone `Service` of `type: NodePort` without an in-cluster Ingress — a simpler approach used before ingress-nginx was introduced. Services still using that legacy pattern (direct NodePort, no Ingress object) continue to work the same way: Traefik forwards to `homeserver:<nodeport>` and the Service routes to Pods directly. New work should use the ingress-nginx path above unless a service genuinely has no need for `Host`-based routing.
|
||||||
|
|
||||||
## Namespace and resource governance
|
## Namespace and resource governance
|
||||||
|
|
||||||
|
|||||||
112
docs/argocd.md
Normal file
112
docs/argocd.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# ArgoCD — GitOps for K3s
|
||||||
|
|
||||||
|
[Argo CD](https://argoproj.github.io/cd/) is a declarative continuous delivery tool for Kubernetes. In this homelab it's the bridge between this repo and the K3s cluster: **git is the source of truth**, and Argo CD continuously watches the git repository, reconciling the cluster to match whatever manifests are tracked on `main`.
|
||||||
|
|
||||||
|
Add a Deployment, change a resource limit, delete an Ingress — commit it, and Argo CD pulls the change into the cluster automatically, no manual `kubectl apply` required. It's Kubernetes-as-GitOps rather than Kubernetes-as-state-you-manually-maintain.
|
||||||
|
|
||||||
|
## Repo layout
|
||||||
|
|
||||||
|
Argo CD apps in this repo follow a split structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
kubernetes/
|
||||||
|
├── apps/
|
||||||
|
│ └── homepage/
|
||||||
|
│ ├── deployment.yaml
|
||||||
|
│ ├── service.yaml
|
||||||
|
│ ├── configmap.yaml
|
||||||
|
│ ├── ingress.yaml
|
||||||
|
│ └── kustomization.yaml
|
||||||
|
└── argocd-apps/
|
||||||
|
└── homepage/
|
||||||
|
└── homepage-app.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`kubernetes/apps/<name>/`** — the actual Kubernetes workload manifests for each app. Bundled with `kustomization.yaml` (Kustomize), so common operations like renaming a namespace or swapping an image tag can be done via patches rather than editing every YAML. See [`kubernetes/apps/README.md`](../kubernetes/apps/README.md) for details.
|
||||||
|
- **`kubernetes/argocd-apps/<name>/<name>-app.yaml`** — the Argo CD `Application` object that tells Argo CD "watch this git path, deploy it into this namespace." These live one level up, deliberately separate from `kubernetes/apps/`, so Argo CD never watches its own Application definitions and can't recurse.
|
||||||
|
|
||||||
|
The first app managed this way is the **Homepage** dashboard — see `kubernetes/apps/homepage/` for the manifests and `kubernetes/argocd-apps/homepage/homepage-app.yaml` for the Application.
|
||||||
|
|
||||||
|
## Application manifest
|
||||||
|
|
||||||
|
Each app gets a thin `Application` manifest. The Homepage one looks like:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: homepage
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: https://github.com/rezayaghobi-dev/homelab
|
||||||
|
targetRevision: main
|
||||||
|
path: kubernetes/apps/homepage
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: homepage
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
```
|
||||||
|
|
||||||
|
- `path` points at the `kubernetes/apps/<name>/` directory — Argo CD treats the `kustomization.yaml` there as the entry point.
|
||||||
|
- `automated.prune = true` — anything deleted from git gets deleted from the cluster.
|
||||||
|
- `automated.selfHeal = true` — if someone edits the live cluster out-of-band, Argo CD notices the drift and corrects it.
|
||||||
|
- `CreateNamespace=true` — the destination namespace is created automatically if it doesn't exist.
|
||||||
|
|
||||||
|
This is the current state of the cluster's GitOps control loop: Argo CD is the reconciler, this repo is the spec, and the cluster state is the realized output.
|
||||||
|
|
||||||
|
## How traffic reaches an app
|
||||||
|
|
||||||
|
K3s itself doesn't own ports 80/443 — the Docker-side Traefik reverse proxy already binds them (see [Traefik](Traefik.md)). So the exposure pattern for an Argo CD-managed app is:
|
||||||
|
|
||||||
|
```
|
||||||
|
Client → Traefik (:443) → ingress-nginx NodePort → Ingress → Service → Pod
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Traefik** (Docker container, `network_mode`-adjacent to the host) terminates TLS (`*.home.server` via mkcert) and routes based on `Host` header.
|
||||||
|
2. **ingress-nginx** runs *inside* the K3s cluster. Its `Service` is exposed as a **NodePort** on the host, giving Traefik a stable `homeserver:<nodeport>` target to forward to — the same pattern used for pre-ArgoCD K3s workloads (see [K3s — Exposure pattern](K3s.md#Exposure-pattern)).
|
||||||
|
3. **ingress-nginx** (the in-cluster Ingress controller) receives the request, matches it against `Ingress` resources in the cluster, and forwards to the right `Service`.
|
||||||
|
4. **Service** → **Pod** as normal Kubernetes routing.
|
||||||
|
|
||||||
|
This keeps a single TLS termination layer (Traefik) and a single DNS entry point (`*.home.server` via Pi-hole), while letting in-cluster Ingress resources carry the routing logic as code alongside the workloads they protect.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Adding a new app
|
||||||
|
|
||||||
|
1. **Create the workload manifests.**
|
||||||
|
```bash
|
||||||
|
mkdir kubernetes/apps/<name>
|
||||||
|
```
|
||||||
|
Drop your `deployment.yaml`, `service.yaml`, `configmap.yaml`, `ingress.yaml` (if any), and a `kustomization.yaml` listing them as resources. The `kustomization.yaml` is required — Argo CD uses it as the entry point for the `path`.
|
||||||
|
|
||||||
|
2. **Create the Application manifest.**
|
||||||
|
```bash
|
||||||
|
mkdir kubernetes/argocd-apps/<name>
|
||||||
|
```
|
||||||
|
Copy `kubernetes/argocd-apps/homepage/homepage-app.yaml` as a template into `kubernetes/argocd-apps/<name>/<name>-app.yaml`. Update the three fields that vary:
|
||||||
|
- `metadata.name` → the new app's name
|
||||||
|
- `spec.source.path` → `kubernetes/apps/<name>`
|
||||||
|
- `spec.destination.namespace` → the namespace the app runs in
|
||||||
|
|
||||||
|
3. **Apply the Application once.**
|
||||||
|
```bash
|
||||||
|
kubectl apply -f kubernetes/argocd-apps/<name>/<name>-app.yaml
|
||||||
|
```
|
||||||
|
Argo CD picks it up immediately and creates the app. After this initial `kubectl apply`, **all** future changes — including edits to the manifests, resource changes, even namespace recreation — flow through git alone. Argo CD's `selfHeal` and `prune` will keep the cluster in sync with whatever is on `main`.
|
||||||
|
|
||||||
|
4. **Point Traefik at it.** The app's Ingress will typically be served by the in-cluster ingress-nginx behind a NodePort. Add or reuse a Traefik router (Docker labels on the ingress-nginx Service itself, or a `dynamic/` file-provider entry if the Service isn't on `web_net`) so `<name>.home.server` resolves to the right NodePort.
|
||||||
|
|
||||||
|
That's it — commit, push, and Argo CD handles the rest. No manual `kubectl` on the cluster; no drift between what's running and what's in git.
|
||||||
|
|
||||||
|
## Why this matters
|
||||||
|
|
||||||
|
On a single-node learning cluster this matters less for HA and more for discipline: writing a `Deployment` that actually ships is different from applying one manually and calling it done. GitOps forces the manifests and the running cluster to be the same thing — the diff in the Argo CD UI is an honest report of "what happens if I merge this PR," not a best-effort guess at what `kubectl apply` did last time.
|
||||||
|
|
||||||
|
[← Back to Home](Home.md)
|
||||||
43
kubernetes/apps/README.md
Normal file
43
kubernetes/apps/README.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Kubernetes Apps
|
||||||
|
|
||||||
|
This folder holds the actual Kubernetes workload manifests for every app managed via Argo CD's GitOps flow. Each subfolder is one application, named after the app itself:
|
||||||
|
|
||||||
|
```
|
||||||
|
kubernetes/apps/
|
||||||
|
├── README.md ← you are here
|
||||||
|
├── homepage/
|
||||||
|
│ ├── deployment.yaml
|
||||||
|
│ ├── service.yaml
|
||||||
|
│ ├── configmap.yaml
|
||||||
|
│ ├── ingress.yaml
|
||||||
|
│ └── kustomization.yaml
|
||||||
|
├── <name>/ ← new apps go here
|
||||||
|
│ ├── ...
|
||||||
|
│ └── kustomization.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## What lives here
|
||||||
|
|
||||||
|
- **Workload manifests** — `Deployment`, `Service`, `ConfigMap`, `Ingress`, `Secret`, etc. These describe the pods, networking, and config that Argo CD applies to the cluster.
|
||||||
|
- **`kustomization.yaml`** — the Kustomize entry point for the app. Argo CD watches the path this file declares, so every app folder must include one and list every sibling manifest under `resources:`.
|
||||||
|
|
||||||
|
These are the files that end up running in the cluster. This is "what runs."
|
||||||
|
|
||||||
|
## What does *not* live here
|
||||||
|
|
||||||
|
- **Argo CD `Application` objects.** Those live in the sibling [`../argocd-apps/`](../argocd-apps/README.md) folder, deliberately kept separate so Argo CD never watches its own definitions.
|
||||||
|
- **Namespace-scoped governance objects.** The cluster-level `LimitRange` and `ResourceQuota` live in [`../resource-limits/`](../resource-limits/resource-limits.yaml), applied once at cluster setup rather than per-app.
|
||||||
|
|
||||||
|
## Relationship to the rest of the repo
|
||||||
|
|
||||||
|
Every always-on Docker Compose service in this repo (see [`docker-compose/`](../../docker-compose/)) has a self-contained folder with its own `docker-compose.yml`. The Kubernetes side mirrors that convention — one folder per app, fully self-contained — so the structure on both sides is parallel and easy to navigate.
|
||||||
|
|
||||||
|
## Adding a new app
|
||||||
|
|
||||||
|
See [ArgoCD](docs/argocd.md#adding-a-new-app) for the full walkthrough. In short:
|
||||||
|
|
||||||
|
1. Create `kubernetes/apps/<name>/` with manifests + `kustomization.yaml`.
|
||||||
|
2. Create the matching `kubernetes/argocd-apps/<name>/<name>-app.yaml` Application manifest pointing at that path.
|
||||||
|
3. `kubectl apply` the Application once — future changes flow through git.
|
||||||
|
|
||||||
|
[← Back to Home](../../docs/Home.md)
|
||||||
69
kubernetes/argocd-apps/README.md
Normal file
69
kubernetes/argocd-apps/README.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Argo CD Application Manifests
|
||||||
|
|
||||||
|
This folder holds the **Argo CD `Application` objects** — the manifests that tell Argo CD which Git path to watch and which cluster/namespace to deploy into. Each subfolder corresponds to one app, matching the name used under [`../apps/`](../apps/README.md):
|
||||||
|
|
||||||
|
```
|
||||||
|
kubernetes/argocd-apps/
|
||||||
|
├── README.md ← you are here
|
||||||
|
├── homepage/
|
||||||
|
│ └── homepage-app.yaml
|
||||||
|
└── <name>/
|
||||||
|
└── <name>-app.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## What lives here
|
||||||
|
|
||||||
|
- **One `Application` YAML per app**, named `<name>-app.yaml`. This is the Argo CD control plane entry point — it sets the source repo, target revision, git `path`, destination server and namespace, and sync policy (automated with `prune` and `selfHeal`).
|
||||||
|
|
||||||
|
Example (from `homepage/homepage-app.yaml`):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: homepage
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: https://github.com/rezayaghobi-dev/homelab
|
||||||
|
targetRevision: main
|
||||||
|
path: kubernetes/apps/homepage
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: homepage
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
```
|
||||||
|
|
||||||
|
## What does *not* live here
|
||||||
|
|
||||||
|
- **Workload manifests** (`Deployment`, `Service`, `Ingress`, etc.). Those live in the sibling [`../apps/`](../apps/README.md) folder. This separation is deliberate: Argo CD should never watch its own `Application` definitions, otherwise a recursive sync loop becomes possible.
|
||||||
|
|
||||||
|
## Why this separation matters
|
||||||
|
|
||||||
|
Keeping "what tells Argo CD to run" (`<name>-app.yaml`) and "what actually runs" (the manifests in `../apps/<name>/`) in different folders means:
|
||||||
|
|
||||||
|
- **No accidental self-watch.** Argo CD watches `kubernetes/apps/`, not `kubernetes/argocd-apps/`. An Application manifest changing its own `path` would have no effect — it'd be out of the watched tree entirely.
|
||||||
|
- **Independent lifecycle.** The Application object is applied once via `kubectl`; everything after that — the Deployments, Services, Ingresses it ultimately creates — flows from git through Argo CD's reconciliation loop.
|
||||||
|
- **One job per file.** Adding an app means adding one file here (the Application) and one directory there (the manifests). Easy to audit, easy to delete.
|
||||||
|
|
||||||
|
## Applying a new Application
|
||||||
|
|
||||||
|
After creating `kubernetes/argocd-apps/<name>/<name>-app.yaml`, apply it once:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f kubernetes/argocd-apps/<name>/<name>-app.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Argo CD picks it up immediately, creates the app in its UI, and begins syncing. After this single `kubectl` call, **all** future changes flow through git — modifying the Application manifest itself is rarely needed once it's running.
|
||||||
|
|
||||||
|
## Relationship to the rest of the repo
|
||||||
|
|
||||||
|
The folder structure mirrors [`../apps/`](../apps/README.md) one-to-one: each app under `kubernetes/argocd-apps/` has a matching folder under `kubernetes/apps/`. This isn't strictly enforced by Argo CD, but keeping the two trees parallel makes it trivial to trace "which Application watches which manifests."
|
||||||
|
|
||||||
|
[← Back to Home](../../docs/Home.md)
|
||||||
Reference in New Issue
Block a user