Compare commits

...

15 Commits

Author SHA1 Message Date
020b248bbe fix: force ServerSideApply on envoy-gateway Application
Gateway API CRDs (httproutes, envoyproxies) have schemas large enough that
client-side apply's last-applied-configuration annotation exceeds the
262144-byte annotation limit. SSA skips that annotation entirely.
2026-07-21 12:07:59 +07:00
fef69d587f fix: register envoy-gateway OCI repo declaratively in argocd values
ArgoCD only builds a helm-pull command for oci:// sources when the repo is
registered with enableOCI: true; otherwise it falls back to classic --repo
handling, which errors on an oci:// URL. Registered via configs.repositories
in argocd's own values.yaml (Git-managed), Application source updated to
the bare host/path form ArgoCD expects for OCI repos.
2026-07-21 12:02:02 +07:00
2a07b6decf fix: use OCI registry for envoy-gateway helm chart source
https://charts.gateway.envoyproxy.io no longer resolves (NXDOMAIN); chart is
now published at oci://docker.io/envoyproxy/gateway-helm.
2026-07-21 11:24:21 +07:00
7dda8715c1 fix: disable auto-sync on argocd Application
Allows manual Service edits (e.g. NodePort for temp access) without self-heal reverting them.
2026-07-21 10:41:20 +07:00
02b4f1f926 fix: ignore CRD status/caBundle drift on metallb Application
Prevents perpetual OutOfSync on bgppeers.metallb.io and other metallb CRDs caused by apiserver-populated .status fields not present in the Helm chart source.
2026-07-21 10:39:39 +07:00
2e5037d6f4 docs: trim README explanations, keep steps short 2026-07-14 19:35:34 +07:00
c2c265c898 docs: never store argocd admin password hash in git
Drop .env/envsubst/bake-hash-into-values.yaml flow entirely. Chart's
configs.secret block is removed for good, so the rendered manifest
never declares admin.password/admin.passwordMtime. Password hash is
set once directly on the live argocd-secret via kubectl patch, and
survives every self-heal sync since ArgoCD never owns those fields.
2026-07-14 18:52:46 +07:00
cffaa7449d fix argocd install + add root bootstrap Application manifest
- remove server.httproute from argocd values.yaml: helm install failed
  since Gateway API CRDs (installed by envoy-gateway, wave 2) don't
  exist yet; HTTPRoute is already applied manually in Phase 6
- add bootstrap-app.yaml as the Git-committed root/seed Application,
  replacing ad-hoc UI creation (GitOps anti-pattern: apps not stored
  in Git can't be recreated)
2026-07-14 17:50:06 +07:00
1432e9e114 docs: add missing argocd wave -1 to README 2026-07-14 17:27:47 +07:00
4c214a9928 add git ignore 2026-07-10 16:30:27 +07:00
e10c72a34f add argocd self-managed Application (sync-wave -1) 2026-06-14 18:30:21 +07:00
fd769794f9 use envsubst to inject password hash from .env into values.yaml at install time 2026-06-14 18:17:05 +07:00
b6af771fd9 move password hash to values.yaml, simplify helm install command 2026-06-14 18:14:55 +07:00
40d7f794aa store bcrypt hash in .env, pass to helm via --set at install time 2026-06-14 18:10:39 +07:00
73b35bfd14 add .env for argocd admin password, update install command to set bcrypt hash 2026-06-14 18:09:16 +07:00
7 changed files with 85 additions and 50 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.env
# OS/editor
.DS_Store
*.swp
CLAUDE.md

View File

@@ -10,6 +10,7 @@ Git repo (cluster-bootstrap)
└── ArgoCD watches bootstrap/apps/ → syncs all Applications └── ArgoCD watches bootstrap/apps/ → syncs all Applications
Bootstrap order (sync waves): Bootstrap order (sync waves):
Wave -1 → argocd (self-managed, once bootstrapped)
Wave 0 → metallb (LoadBalancer IPs) Wave 0 → metallb (LoadBalancer IPs)
Wave 1 → metallb-config (IPAddressPool + L2Advertisement) Wave 1 → metallb-config (IPAddressPool + L2Advertisement)
Wave 2 → envoy-gateway (HTTP gateway controller) Wave 2 → envoy-gateway (HTTP gateway controller)
@@ -45,35 +46,13 @@ helm version
--- ---
## Phase 2 — Fill in NFS details ## Phase 2 — Install tools
Edit `manifests/nfs-provisioner/values.yaml` before pushing — replace the two placeholders:
```bash ```bash
git clone https://gitea.fireflylab.cc/duynguyen/cluster-bootstrap.git sudo dnf install -y httpd-tools
``` ```
```bash `htpasswd` generates the admin password hash used in Phase 3.1.
cd cluster-bootstrap
```
Open `manifests/nfs-provisioner/values.yaml` and set:
- `nfs.server` — xpen NAS IP address
- `nfs.path` — NFS export path (e.g. `/volume1/k8s`)
Then commit and push:
```bash
git add manifests/nfs-provisioner/values.yaml
```
```bash
git commit -m "set nfs server and path"
```
```bash
git push origin main
```
--- ---
@@ -89,50 +68,45 @@ helm repo add argo https://argoproj.github.io/argo-helm
helm repo update helm repo update
``` ```
Install ArgoCD: Install ArgoCD (`values.yaml` has no `configs.secret` block — chart auto-generates a random admin password):
```bash ```bash
helm install argocd argo/argo-cd -n argocd --create-namespace -f manifests/argocd/values.yaml helm install argocd argo/argo-cd -n argocd --create-namespace -f manifests/argocd/values.yaml
``` ```
Wait for ArgoCD to be ready: Wait for ready:
```bash ```bash
kubectl wait --for=condition=available deployment/argocd-server -n argocd --timeout=120s kubectl wait --for=condition=available deployment/argocd-server -n argocd --timeout=120s
``` ```
Get initial admin password: (Optional) inspect manually: `kubectl port-forward svc/argocd-server -n argocd 8080:443``https://localhost:8080`. Not needed for bootstrap.
### 3.1 Set admin password on the Secret
Patched directly on `argocd-secret`, never in `values.yaml`/Git — keeps `configs.secret` absent so self-heal (wave -1) never touches it, password stays stable forever:
```bash ```bash
kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath='{.data.password}' | base64 -d read -s -p "ArgoCD admin password: " PW; echo
HASH=$(htpasswd -nbBC 12 "" "$PW" | tr -d ':\n' | sed 's/$2y/$2a/')
kubectl patch secret argocd-secret -n argocd --type merge -p \
"{\"stringData\":{\"admin.password\":\"$HASH\",\"admin.passwordMtime\":\"$(date -u +%FT%TZ)\"}}"
unset PW HASH
``` ```
Port-forward to access UI (MetalLB + Envoy not running yet): Rotate: repeat with new hash + new `admin.passwordMtime` (required for ArgoCD to accept the change).
```bash
kubectl port-forward svc/argocd-server -n argocd 8080:443
```
Open `https://localhost:8080` — login with `admin` and the password above.
--- ---
## Phase 4 — Create bootstrap app in ArgoCD UI ## Phase 4 — Apply the root bootstrap Application
In ArgoCD UI, create a new Application: `bootstrap-app.yaml` (repo root) is the seed manifest, committed to Git — not created via UI/CLI. Only manifest ever applied by hand:
| Field | Value | ```bash
|-------|-------| kubectl apply -f bootstrap-app.yaml
| Application Name | `bootstrap` | ```
| Project | `default` |
| Sync Policy | Automated (enable Prune + Self Heal) |
| Repository URL | `https://gitea.fireflylab.cc/duynguyen/cluster-bootstrap.git` |
| Revision | `main` |
| Path | `bootstrap/apps` |
| Cluster URL | `https://kubernetes.default.svc` |
| Namespace | `argocd` |
Click **Create**. ArgoCD syncs all child Applications in wave order automatically. ArgoCD syncs all child Applications in wave order automatically, including self-managing itself (`bootstrap/apps/argocd.yaml`, wave -1).
Monitor progress: Monitor progress:
@@ -265,8 +239,10 @@ All Applications should be `Synced` / `Healthy`.
``` ```
cluster-bootstrap/ cluster-bootstrap/
├── README.md ├── README.md
├── bootstrap-app.yaml # root seed Application — the only manifest applied by hand
├── bootstrap/ ├── bootstrap/
│ └── apps/ # ArgoCD Application CRDs │ └── apps/ # ArgoCD Application CRDs
│ ├── argocd.yaml # wave -1 — self-managed ArgoCD
│ ├── metallb.yaml # wave 0 — Helm chart │ ├── metallb.yaml # wave 0 — Helm chart
│ ├── metallb-config.yaml # wave 1 — IPAddressPool + L2Advertisement │ ├── metallb-config.yaml # wave 1 — IPAddressPool + L2Advertisement
│ ├── envoy-gateway.yaml # wave 2 — Helm chart │ ├── envoy-gateway.yaml # wave 2 — Helm chart

18
bootstrap-app.yaml Normal file
View File

@@ -0,0 +1,18 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: bootstrap
namespace: argocd
spec:
project: default
source:
repoURL: https://gitea.fireflylab.cc/duynguyen/cluster-bootstrap.git
targetRevision: main
path: bootstrap/apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true

View File

@@ -0,0 +1,22 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: argocd
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "-1"
spec:
project: default
sources:
- repoURL: https://argoproj.github.io/argo-helm
chart: argo-cd
targetRevision: "7.8.26"
helm:
valueFiles:
- $values/manifests/argocd/values.yaml
- repoURL: https://gitea.fireflylab.cc/duynguyen/cluster-bootstrap.git
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: argocd

View File

@@ -8,7 +8,7 @@ metadata:
spec: spec:
project: default project: default
sources: sources:
- repoURL: https://charts.gateway.envoyproxy.io - repoURL: docker.io/envoyproxy
chart: gateway-helm chart: gateway-helm
targetRevision: "v1.7.1" targetRevision: "v1.7.1"
helm: helm:
@@ -26,3 +26,4 @@ spec:
selfHeal: true selfHeal: true
syncOptions: syncOptions:
- CreateNamespace=true - CreateNamespace=true
- ServerSideApply=true

View File

@@ -26,3 +26,9 @@ spec:
selfHeal: true selfHeal: true
syncOptions: syncOptions:
- CreateNamespace=true - CreateNamespace=true
ignoreDifferences:
- group: apiextensions.k8s.io
kind: CustomResourceDefinition
jsonPointers:
- /status
- /spec/conversion/webhook/clientConfig/caBundle

View File

@@ -18,6 +18,12 @@ global:
configs: configs:
params: params:
server.insecure: true # TLS terminated at Envoy Gateway server.insecure: true # TLS terminated at Envoy Gateway
repositories:
envoy-gateway-oci:
url: docker.io/envoyproxy
name: envoy-gateway-oci
type: helm
enableOCI: "true"
server: server:
replicas: 1 replicas: 1