chore: add CLAUDE.md, kubectl notes, and settings/gitignore tweaks

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>
This commit is contained in:
2026-07-09 00:05:56 +02:00
parent b62b37542b
commit ed10cc837a
4 changed files with 125 additions and 1 deletions

View File

@@ -4,7 +4,11 @@
"Bash(for f:*)", "Bash(for f:*)",
"Bash(do echo:*)", "Bash(do echo:*)",
"Read(//Users/jan.novak/srv/personal/home-kubernetes/**)", "Read(//Users/jan.novak/srv/personal/home-kubernetes/**)",
"Bash(done)" "Bash(done)",
"Bash(ssh docker-30 *)",
"Bash(git add *)",
"WebSearch",
"WebFetch(domain:cert-manager.io)"
] ]
} }
} }

1
.gitignore vendored
View File

@@ -11,4 +11,5 @@ tmp/
vms/utility-101-shadow/docker/monitoring/smtp_password vms/utility-101-shadow/docker/monitoring/smtp_password
docker-30/zot/sync-credentials.json docker-30/zot/sync-credentials.json
vms-home/docker-30/zot/sync-credentials.json
kubernetes-kvm-terraform/gke_gcloud_auth_plugin_cache kubernetes-kvm-terraform/gke_gcloud_auth_plugin_cache

105
CLAUDE.md Normal file
View File

@@ -0,0 +1,105 @@
# 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/)
```bash
cd kubernetes-kvm-terraform
tofu init
tofu plan
tofu apply
tofu destroy
```
### Flux GitOps
```bash
# 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
```bash
export KUBECONFIG=kubernetes-kvm-terraform/kubeconfig
kubectl get nodes
kubectl get pods -A
kubectl get secrets -A
```
### Docker Compose (docker-30/ services)
```bash
# 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 alias `kvm-beelink` for 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` + `CiliumLoadBalancerIPPool` for bare-metal load-balancer IPs (defined in `gitops/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 a `Kustomization` entry in `flux-system/extra-kustomizations.yaml` with appropriate `dependsOn`.
- **Helm apps**: use a `HelmRepository` + `HelmRelease` pair; pin chart versions explicitly.
- **Secrets**: add an `ExternalSecret` CR 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/kubeconfig` is 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.

14
docs/kubernetes-extras.md Normal file
View File

@@ -0,0 +1,14 @@
## kubectl
```bash
# condensed -o wide
kubectl get pods -A -o wide --watch | awk '
/NOMINATED NODE/ { sub(/[[:space:]]+NOMINATED NODE[[:space:]]+READINESS GATES[[:space:]]*$/,""); print; fflush(); next }
{ sub(/[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]*$/,""); print; fflush() }
'
# condensed -o wide
kubectl get pods -A --watch -o custom-columns=\
'NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase,RESTARTS:.status.containerStatuses[0].restartCount,IP:.status.podIP,NODE:.spec.nodeName'
```