Document the repo for Claude Code, note a couple of handy kubectl one-liners, allow a few more Bash/WebFetch/WebSearch permissions used during this session, and ignore the relocated zot sync-credentials.json. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Repository Purpose
Home Kubernetes lab infrastructure-as-code. Manages VM provisioning (Terraform/KVM), Kubernetes cluster configuration, and application deployments via Flux GitOps — all pointing at a self-hosted Gitea instance.
Common Commands
Terraform (kubernetes-kvm-terraform/)
cd kubernetes-kvm-terraform
tofu init
tofu plan
tofu apply
tofu destroy
Flux GitOps
# Check reconciliation status
kubectl get kustomizations -A
kubectl get helmreleases -A
# Force reconcile
flux reconcile kustomization flux-system --with-source
flux reconcile helmrelease <name> -n <namespace>
# Watch logs
flux logs --follow
# Check source sync
flux get sources git
kubectl — common ops
export KUBECONFIG=kubernetes-kvm-terraform/kubeconfig
kubectl get nodes
kubectl get pods -A
kubectl get secrets -A
Docker Compose (docker-30/ services)
# These run on 192.168.0.30 (docker-30), accessed via SSH
ssh novakj@192.168.0.30
cd /path/to/service && docker compose up -d
docker compose logs -f
Architecture
Infrastructure Layer
- Hypervisors: homer (192.168.0.7) and beelink (192.168.0.6) run KVM/libvirt
- Terraform provider: primary
qemu+ssh://novakj@192.168.0.7/system, secondary aliaskvm-beelinkfor 192.168.0.6 - Kubernetes master: kube-master-31 @ 192.168.0.31:6443, bootstrapped via kubeadm
- OS: Ubuntu 24.04 Noble cloud images, network bridge
br0, subnet 192.168.0.0/24
GitOps Layer (gitops/home-kubernetes/)
Flux syncs from Gitea (https://gitea.home.hrajfrisbee.cz, main branch, every 10 minutes). The reconciliation order is enforced via dependsOn in flux-system/extra-kustomizations.yaml:
00-crds → 00-rbac → cilium → cert-manager → external-secrets → everything else
Each application lives in its own subdirectory under gitops/home-kubernetes/ and is referenced as a Flux Kustomization resource. Prune is enabled — removing a manifest from git removes it from the cluster.
Secrets Flow
Vault (docker-30) → External-Secrets controller (in-cluster) → Kubernetes Secret objects. Applications reference ExternalSecret CRs that pull from Vault paths. Do not put real secrets in git.
Networking
- CNI: Cilium 1.19.x with Gateway API and Hubble UI enabled
- L2 LB: Cilium
CiliumL2AnnouncementPolicy+CiliumLoadBalancerIPPoolfor bare-metal load-balancer IPs (defined ingitops/home-kubernetes/cilium/) - Ingress: ingress-nginx for HTTP(S) workloads; Gateway API for newer apps
- TLS: cert-manager issues wildcard cert (
*.home.hrajfrisbee.cz) referenced by apps
Storage
- democratic-CSI: iSCSI volumes backed by FreeNAS at 192.168.0.40
- Longhorn: configured but disabled in Flux (directory present, not in
extra-kustomizations.yaml)
Supporting Services on docker-30 (192.168.0.30)
All managed with Docker Compose:
- Gitea — Git server + act_runner (GitHub Actions-compatible CI)
- Vault — secrets backend for External Secrets
- Zot — private OCI/container registry
- Kanidm — identity management / OIDC provider
- nginx — reverse proxy for docker-30 services
Key Conventions
- New application: create a directory under
gitops/home-kubernetes/<app-name>/, add aKustomizationentry influx-system/extra-kustomizations.yamlwith appropriatedependsOn. - Helm apps: use a
HelmRepository+HelmReleasepair; pin chart versions explicitly. - Secrets: add an
ExternalSecretCR pointing to the Vault path; never commit actual secret values. - Terraform state:
kubernetes-kvm-terraform/terraform.tfstate*is gitignored/sensitive; treat it carefully. - kubeconfig:
kubernetes-kvm-terraform/kubeconfigis gitignored; obtain it from the master node after provisioning.
Plans
When Claude Code's plan mode is used, save the plan file inside the repo at
docs/plans/YYYY-MM-DD-HHMM-<slug>.md instead of the default ~/.claude/plans/
location. Get the timestamp with date "+%Y-%m-%d-%H%M" (matches the changelog
convention). The <slug> should be a short kebab-case summary of the plan's topic.