- Nix 32.5%
- Jinja 21.5%
- Python 17.9%
- Shell 11.8%
- Go 8.1%
- Other 8.2%
## Summary
C2 Mikado chain to move the entire Immich stack (server, ML, valkey,
postgres) off `minikube-indri` and onto `k3s-ringtail`. Immich is the
largest single tenant on minikube (~1.5 GiB resident) and minikube is
currently memory-saturated (97% RAM, swapping). This is the first
concrete chain in the broader indri-k8s decommission effort.
This PR contains the planning layer only — 7 cards (1 goal + 6
prerequisites). Implementation cycles follow per the Mikado Branch
Invariant.
## Goal end-state
- Immich `server`, `machine-learning`, `valkey` on ringtail.
- ML pod uses ringtail's RTX 4080 (performance win — currently
CPU-only).
- CNPG `immich-pg` (PG17 + VectorChord) runs on ringtail.
- Library still on sifaka NFS — ringtail mounts the same path.
- `photos.ops.eblu.me` reroutes through Caddy → ringtail ingress.
- Minikube `immich` and `immich-pg` are removed.
## Cards
| Card | Depends on |
|---|---|
| `migrate-immich-to-ringtail` (goal) | all six below |
| `cnpg-on-ringtail` | — |
| `immich-pg-on-ringtail` | cnpg-on-ringtail |
| `immich-pg-data-migration` | immich-pg-on-ringtail |
| `sifaka-nfs-from-ringtail` | — |
| `immich-app-on-ringtail` | immich-pg-on-ringtail, sifaka-nfs-from-ringtail |
| `immich-cutover-and-decommission` | immich-pg-data-migration, immich-app-on-ringtail |
## Key constraints
- **No data loss.** Downtime is acceptable; data loss is not. Two
surfaces matter: postgres (ML embeddings, face data — slow to
re-derive) and the library files (don't move, but NFS access from
ringtail must be verified).
- **Migration method:** Option A is a CNPG `externalCluster`
basebackup → promote. Option B is `pg_dump`/`pg_restore` as a
documented fallback. Either way, dry-run against a scratch
cluster first.
- **Why pg moves too** (not cross-cluster): keeping pg on minikube
would block the whole decommission, and Immich is chatty with pg
so tailnet round-trips would hurt.
## Test plan
- [ ] Plan review — does the dependency graph make sense?
- [ ] `mise run docs-mikado migrate-immich-to-ringtail` shows the
chain correctly.
- [ ] Per-card implementation cycles land separately (commit
convention enforced by hook).
Reviewed-on: #356
|
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| .github | ||
| ansible | ||
| argocd | ||
| containers | ||
| docs | ||
| fly | ||
| mise-tasks | ||
| nixos/ringtail | ||
| pulumi | ||
| src/blumeops | ||
| utils/qart | ||
| .ansible-lint | ||
| .gitattributes | ||
| .gitignore | ||
| .yamllint.yaml | ||
| AGENTS.md | ||
| Brewfile | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| compensating-controls.yaml | ||
| dagger.json | ||
| LICENSE | ||
| mise.toml | ||
| prek.toml | ||
| pyproject.toml | ||
| README.md | ||
| service-versions.yaml | ||
| towncrier.toml | ||
| uv.lock | ||
blumeops
aka "Blue Mops"
Tools and configuration for Erich Blume's personal infrastructure, orchestrated across a Tailscale tailnet.
This is a homelab, but it's also a testing ground for AI-assisted infrastructure development. Much of this codebase was initially co-authored with Claude Code, and the repo places heavy emphasis on documentation, process, and change classification to make that collaboration work well. I don't know entirely how I feel about LLMs in our current era (there are real concerns about how training data is sourced and energy subsidy) but it felt important to learn how to work with these tools.
The full documentation is published at docs.eblu.me
and lives in the docs/ directory, structured around the
Diataxis framework and designed to be compatible with
Obsidian/Obsidian.nvim.
What runs here
Services are a mix of Kubernetes pods (managed by ArgoCD), macOS LaunchAgent services (managed by Ansible), and NixOS systemd services (managed by Nix flakes), all connected via Tailscale:
- Indri (Mac Mini M1) - primary server. Most services run in Minikube via ArgoCD; Forgejo, Caddy, and others run natively as LaunchAgent services via Ansible.
- Ringtail (NixOS desktop, RTX 4080) - GPU workloads (Frigate NVR, Authentik SSO) on k3s, plus NixOS systemd services.
- Sifaka (Synology NAS) - backup target and bulk storage.
Notable services include Grafana/Prometheus/Loki observability, Immich photos, Jellyfin media, Forgejo git forge, a Zot container registry, and more. Public access is routed through a Fly.io proxy; everything else is tailnet-only.
Project structure
ansible/ Ansible playbooks and roles (indri, sifaka)
argocd/apps/ ArgoCD Application definitions
argocd/manifests/ Kubernetes manifests per service
containers/ Custom container builds (Dockerfile + Nix)
docs/ Diataxis documentation (published at docs.eblu.me)
fly/ Fly.io public proxy configuration
mise-tasks/ Operational scripts run via mise
nixos/ NixOS configuration for ringtail
pulumi/ Pulumi IaC (Tailscale ACLs, Gandi DNS)
.dagger/ Dagger CI pipelines
.forgejo/ Forgejo Actions CI/CD workflows
Getting started
You'll need Homebrew and mise:
brew bundle # install CLI tools (argocd, tea, flyctl, etc.)
mise install # install managed toolchains (ansible, pulumi, dagger, etc.)
prek install # set up git hooks
Git hooks (via prek) enforce secret scanning
(TruffleHog), linting, formatting, and custom checks like doc link validation
and the Mikado branch invariant. They run automatically on git commit.
Operational tasks are driven through mise. Run mise tasks to see what's
available. Key examples:
mise run provision-indri # deploy to indri via Ansible
mise run services-check # verify service health
mise run container-list # list tracked container images
AI-assisted development
This repo is designed to be worked on by both humans and AI agents. The
AGENTS.md file provides shared instructions for agentic tools, and the
docs/tutorials/ai-assistance-guide.md
explains the full workflow.
Changes are classified before starting work:
- C0 - quick fixes, committed directly to main
- C1 - feature branch + PR, documentation written before code
- C2 - multi-phase work using the Mikado method for dependency tracking
See the agent change process for details.