From 356622d2b4b225fda2c6fae0064539bd7fc9391d Mon Sep 17 00:00:00 2001 From: Jose Henrique Date: Fri, 28 Aug 2026 14:42:07 -0300 Subject: [PATCH] initial sample --- README.md | 131 ++++++++++++++++++++ SETUP.md | 6 + apps/notepad/all-in-one.yaml | 95 ++++++++++++++ apps/root/kustomization.yaml | 7 ++ apps/root/notepad.yaml | 20 +++ bootstrap/argocd-install/kustomization.yaml | 7 ++ bootstrap/root-app.yaml | 20 +++ 7 files changed, 286 insertions(+) create mode 100644 README.md create mode 100644 SETUP.md create mode 100644 apps/notepad/all-in-one.yaml create mode 100644 apps/root/kustomization.yaml create mode 100644 apps/root/notepad.yaml create mode 100644 bootstrap/argocd-install/kustomization.yaml create mode 100644 bootstrap/root-app.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f8e430 --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +# GitOps on Haven — Deployment Draft + +> **Draft only.** Nothing below is applied to the cluster yet. Diagrams are +> [Excalidraw JSON] (import at https://excalidraw.com) — static previews included +> as PNG. Create the repo before running any commands. + +## 1. Decisions + +| Decision | Value | Why | +|---|---|---| +| Tool | **Argo CD** | Best UI (app dependency graph, live-vs-git diff, rollback). Flux's UI (Weave GitOps) is stalled post-Weaveworks; community alternative is Capacitor. | +| Git remote | **Gitea** `git.ivanch.me/ivanch/haven` | Repo you'll create. Gitea is a first-class Argo CD source. | +| Layout | **App-of-apps** | A single root Argo `Application` watches a folder of app manifests; each app manifests as a child `Application`. One place to add/remove apps. | +| Secrets | **No change.** Keep raw env in manifests initially, migrate to ESO/Vaultwarden later. | Argo CD can't write Secret contents itself — value must live in git or come from a controller. Never commit real secrets. | +| Access | Ingress `argocd.haven`, internal-only (nginx class, **no TLS/cert-manager**) + admin password via kubectl | Matches your internal-app convention (`notepad`, `openwebui`, etc.). | +| Repo structure | **New `gitops` repo** (clean, standalone). Your current spec folder stays untouched — migrate later if desired. | Avoids mixing with the `haven` folder used by Gitea Actions CI. | + +## 2. Repo layout (`gitops/`) + +``` +gitops/ +├── bootstrap/ +│ └── root-app.yaml # the app-of-apps (only file you apply manually, once) +├── apps/ +│ └── root/ +│ ├── kustomization.yaml # lists every child Application +│ ├── argocd.yaml # Argo CD managing itself (dogfood) +│ ├── notepad.yaml +│ └── ... +└── apps// # per-app dir + ├── kustomization.yaml + ├── deployment.yaml + ├── service.yaml + ├── ingress.yaml + └── pvc.yaml +``` + +`apps/root/kustomization.yaml` is the switchboard — adding a service = adding one +`Application` entry + one folder. + +## 3. Manual bootstrap (run once, by hand) + +```bash +# Install Argo CD — declarative kustomize install (no Helm CLI, no curl pipes). +# Renders 59 resources from the official argo-cd manifests repo, pinned via ?ref= +kubectl.exe --kubeconfig=C:\Users\ivanch\.kube\config apply -k bootstrap/argocd-install +# retrieve the initial admin password +kubectl.exe --kubeconfig=C:\Users\ivanch\.kube\config -n argocd get secret argocd-initial-admin-secret \ + -o jsonpath='{.data.password}' | base64 -d +# one-time: point the root app at Gitea (requires the repo to exist first) +kubectl.exe --kubeconfig=C:\Users\ivanch\.kube\config apply -f bootstrap/root-app.yaml +``` + +Version pinning: `?ref=stable` in `bootstrap/argocd-install/kustomization.yaml` +tracks the stable branch; pin a tag (`?ref=v3.1.0`) once settled. Component +customization goes through `patches:` in that same kustomization (example +commented in the file), not by editing rendered output. + +After that, **every** change is: `git push` → Argo syncs. kubectl only for debugging. + +## 4. Key manifests + +**`bootstrap/root-app.yaml`** +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: root + namespace: argocd + finalizers: [resources-finalizer.argocd.argoproj.io] +spec: + project: default + source: + repoURL: https://git.ivanch.me/ivanch/haven.git + targetRevision: main + path: apps/root + destination: + server: https://kubernetes.default.svc + namespace: argocd + syncPolicy: + automated: + prune: true + selfHeal: true +``` + +**`apps/root/argocd.yaml`** — Argo CD managing itself (standard dogfood pattern). +**Each child app** follows the same shape with `path: apps/` and +`destination.namespace` matching where it runs today (`default` for most of your +internal apps). + +## 5. Ingress (internal-only, per Haven convention) + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: argocd-server + namespace: argocd +spec: + ingressClassName: nginx + rules: + - host: argocd.haven + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: argocd-server + port: { number: 80 } +``` + +## 6. Diagrams (Excalidraw JSON) + +Two diagrams are included as `.excalidraw` files — open https://excalidraw.com +and drop the file onto the canvas to view/edit: + +- `excalidraw/haven-gitops-flow.excalidraw` — the flow: git push → Gitea → + Argo CD → k3s, with Gitea Actions CI reduced to image build/push only. +- `excalidraw/haven-gitops-tree.excalidraw` — the app-of-apps tree: root app → + child Applications (notepad, openwebui, paperless, vaultwarden, argocd itself, + and infra deferred to a later phase). + +## 7. Migration plan + +Phase 0 (this draft) → Phase 1: install Argo CD + root app, convert 1 pilot app +(suggest `notepad` — simple, stateless-ish, single PVC) → Phase 2: onboard the +rest of `default` ns → Phase 3: infra components (ingress-nginx, cert-manager, +ESO) — do these **last**; they're the ones that can break the cluster if a sync +goes wrong → Phase 4: delete the old `haven` spec folder once Argo is the source +of truth. diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..73c2322 --- /dev/null +++ b/SETUP.md @@ -0,0 +1,6 @@ +# Initial setup +```sh +kubectl create ns argocd +kubectl apply -k bootstrap/argocd-install +kubectl apply -f bootstrap/root-app.yaml +``` \ No newline at end of file diff --git a/apps/notepad/all-in-one.yaml b/apps/notepad/all-in-one.yaml new file mode 100644 index 0000000..4df4cb6 --- /dev/null +++ b/apps/notepad/all-in-one.yaml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: notepad-data + namespace: default + annotations: + nfs.io/storage-path: notepad-data +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: nfs-client +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: notepad + namespace: default + labels: + app: notepad +spec: + replicas: 1 + selector: + matchLabels: + app: notepad + # RWO PVC + single replica: Recreate avoids the two-ReplicaSet PVC fight + # on rollout (see homelab-deploy skill: single-writer state). + strategy: + type: Recreate + template: + metadata: + labels: + app: notepad + spec: + containers: + - name: notepad + image: jdreinhardt/minimalist-web-notepad:latest + imagePullPolicy: Always + command: + - sh + - -c + - mkdir -p /var/www/html/_tmp && cp -n /var/www/html/notes.htaccess /var/www/html/_tmp/.htaccess 2>/dev/null; exec docker-php-entrypoint apache2-foreground + ports: + - containerPort: 80 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi + volumeMounts: + - name: notepad-data + mountPath: /var/www/html/_tmp + volumes: + - name: notepad-data + persistentVolumeClaim: + claimName: notepad-data +--- +apiVersion: v1 +kind: Service +metadata: + name: notepad + namespace: default +spec: + type: ClusterIP + selector: + app: notepad + ports: + - port: 80 + targetPort: 80 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: notepad + namespace: default +spec: + ingressClassName: nginx + rules: + - host: notepad.haven + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: notepad + port: + number: 80 +# NOTE: the Argo Application manifest for notepad lives in apps/root/notepad.yaml +# (watched by the root app-of-apps). Do not add Application objects to this +# directory — this path is what the Application itself watches. diff --git a/apps/root/kustomization.yaml b/apps/root/kustomization.yaml new file mode 100644 index 0000000..1aa528f --- /dev/null +++ b/apps/root/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - notepad.yaml + # - argocd.yaml # enable once Argo CD itself is onboarded (self-managed) + # - openwebui.yaml # future apps: one Application file each, listed here + # - paperless.yaml diff --git a/apps/root/notepad.yaml b/apps/root/notepad.yaml new file mode 100644 index 0000000..259fc79 --- /dev/null +++ b/apps/root/notepad.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: notepad + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + source: + repoURL: https://git.ivanch.me/ivanch/haven-ops.git + targetRevision: main + path: apps/notepad + destination: + server: https://kubernetes.default.svc + namespace: default + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/bootstrap/argocd-install/kustomization.yaml b/bootstrap/argocd-install/kustomization.yaml new file mode 100644 index 0000000..5253db8 --- /dev/null +++ b/bootstrap/argocd-install/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: argocd + +resources: + - https://github.com/argoproj/argo-cd.git/manifests/cluster-install?ref=stable diff --git a/bootstrap/root-app.yaml b/bootstrap/root-app.yaml new file mode 100644 index 0000000..acdba5c --- /dev/null +++ b/bootstrap/root-app.yaml @@ -0,0 +1,20 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: root + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + source: + repoURL: https://git.ivanch.me/ivanch/haven-ops.git + targetRevision: main + path: apps/root + destination: + server: https://kubernetes.default.svc + namespace: argocd + syncPolicy: + automated: + prune: true + selfHeal: true