k8s-and-chill/CLAUDE.md
Felix Wolf c7bfd4953c feat: Wire ArgoCD to Forgejo for GitOps management
Configure myks with global repoURL pointing to Forgejo, in-cluster
destination, and disabled placeholder cluster Secret. Implement App of
Apps pattern with a root Application that syncs all child apps.

Add argocd-deploy-key-init Job that generates an ed25519 SSH keypair,
registers it as a deploy key via Forgejo API, and creates the ArgoCD
repository secret with insecure host key verification (avoids
chicken-and-egg with ArgoCD managing its own known hosts ConfigMap).

Additional changes:
- Ignore /status field diffs globally (K8s 1.32 compat)
- Add Replace=true sync option on Jobs (immutable resource compat)
- Switch job images from bitnami/kubectl to alpine/k8s
- Update CLAUDE.md with ArgoCD status and no-bitnami rule

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:09:50 +02:00

83 lines
3.6 KiB
Markdown

# k8s-and-chill
## Project Overview
GitOps-managed Kubernetes cluster on Hetzner Cloud running Talos Linux. Uses [myks](https://github.com/mykso/myks) for Helm chart rendering with ytt overlays, targeting ArgoCD for continuous deployment.
## Cluster
- **3 Talos control-plane nodes** (CAX11 ARM64, Hetzner Cloud Nuremberg)
- Node IPs: `195.201.219.111`, `195.201.140.75`, `195.201.219.17`
- `allowSchedulingOnControlPlanes: true` (no dedicated workers)
- All namespaces use `pod-security.kubernetes.io/enforce: privileged`
## Domain & DNS
- **Domain**: `tr1ceracop.de` (registered at INWX)
- **DNS**: Managed at INWX with wildcard A record `*.tr1ceracop.de` pointing to node IPs
- **Forgejo**: `https://git.tr1ceracop.de`
- **ArgoCD**: `https://argocd.tr1ceracop.de`
## Deployed Applications
| App | Namespace | Notes |
|-----|-----------|-------|
| traefik | traefik | Ingress controller, DaemonSet with hostPort 80/443 |
| cert-manager | cert-manager | Let's Encrypt HTTP-01 via ClusterIssuer `letsencrypt` |
| forgejo | forgejo | Git server, SQLite, local-path PVC |
| argocd | argocd | GitOps controller |
| local-path-provisioner | local-path-storage | Default StorageClass, installed via upstream manifest |
## myks Structure
```
prototypes/ # Application templates (helm values + ytt overlays)
argocd/
traefik/
cert-manager/
forgejo/
envs/
env-data.ytt.yaml # Global ArgoCD config
_env/ # Shared overlays (annotations, secrets)
production/
env-data.ytt.yaml # App list for production
_apps/{app}/app-data.ytt.yaml # Per-app overrides
rendered/
envs/production/{app}/ # kubectl-ready manifests
argocd/production/ # ArgoCD Application resources
talos/
controlplane.yaml # Talos machine config
talosconfig # Talos client config
kubeconfig # Cluster kubeconfig
```
### Prototype Pattern
Each prototype follows this structure:
- `app-data.ytt.yaml` — namespace declaration
- `vendir/vendir-data.ytt.yaml` — chart name, version, repository URL
- `vendir/base.ytt.yaml` — vendir config template (identical across all)
- `helm/{chart}.yaml` — Helm values overrides
- `ytt/ns.ytt.yaml` — Namespace resource + namespace overlay on all resources
### Key Commands
```bash
myks render # Render all apps
myks render production <app> # Render single app
kubectl apply -f rendered/envs/production/<app>/ --server-side # Deploy
```
## Kubeconfig & Talos
```bash
export KUBECONFIG=./talos/kubeconfig
export TALOSCONFIG=./talos/talosconfig
```
## Known Issues / TODOs
- **Forgejo admin password**: Hardcoded in rendered secrets (`r8sA8CPHD9!bt6d`). Move to external secret before pushing to git.
- **Namespace race condition**: First `kubectl apply` of a new app often fails because namespace isn't ready. Re-apply once.
- **Traefik DaemonSet updates**: Requires `updateStrategy.rollingUpdate.maxSurge: 0` because hostPort conflicts prevent surge.
- **Forgejo Ingress API version**: Chart renders `extensions/v1beta1`, fixed via `ytt/ingress-fix.ytt.yaml` overlay to `networking.k8s.io/v1`.
- **ArgoCD**: Fully wired to Forgejo via App of Apps. Root Application in `default` project syncs `rendered/argocd/production/`. Deploy key provisioned automatically by `argocd-deploy-key-init` Job in forgejo namespace.
## Container Images
- **Never use bitnami images.** Use `alpine/k8s` or plain `alpine` for utility Jobs instead.
## Secrets (not in git)
- `cert-manager/letsencrypt-account-key` — ACME account key (auto-generated)
- `argocd/argocd-initial-admin-secret` — ArgoCD admin password (auto-generated)