Migrate devpi from minikube to indri (launchd) #341

Merged
eblume merged 5 commits from migrate-devpi-to-indri into main 2026-04-29 13:38:38 -07:00
Owner

Summary

Devpi was crash-looping under memory pressure on the minikube StatefulSet, breaking the Python toolchain across the repo (mise run docs-mikado, prek, every uv pip install). It moves to indri as a native LaunchAgent.

What changed

  • New ansible role ansible/roles/devpi/: installs devpi-server + devpi-web into a uv-managed venv, initializes the server-dir on first run via 1Password root password, runs as a LaunchAgent (mcquack.eblume.devpi) bound to 127.0.0.1:3141. Bootstraps from upstream PyPI (so devpi can install itself on a fresh box).
  • Caddy: pypi.ops.eblu.me now proxies to http://localhost:3141.
  • Playbook: indri.yml gains pre_tasks for the root password and the new role.
  • service-versions.yaml: devpi flipped from type: argocd to type: ansible.
  • ArgoCD: removed apps/devpi.yaml and manifests/devpi/. The in-cluster Application, namespace, and PVC have been deleted.
  • Docs: new how-to docs/how-to/operations/devpi-on-indri.md; restart-indri.md lists devpi in the LaunchAgent stop list.

Already deployed (live on indri)

  • Service running: launchctl list mcquack.eblume.devpi → PID 53888
  • curl https://pypi.ops.eblu.me/+api returns 200
  • mise run docs-mikado works again
  • 1.0G of cached PyPI data was migrated from the PVC to ~erichblume/devpi/server-dir/
  • Minikube namespace and PVC fully reclaimed

Test plan

  • mise run services-check (after merge)
  • CI workflows that use devpi succeed
  • No regressions in tools that depend on pypi.ops.eblu.me (prek, uv-script tasks, dagger pipelines)

Context

This is the C1 prelude to a planned C2 chain (mikado/retire-minikube-indri) to retire minikube on indri entirely. Doing devpi as a standalone C1 was the right call because (a) it was urgent — it was breaking the toolchain — and (b) it shakes out the migration recipe before we commit to a multi-leaf chain.

## Summary Devpi was crash-looping under memory pressure on the minikube StatefulSet, breaking the Python toolchain across the repo (`mise run docs-mikado`, `prek`, every `uv pip install`). It moves to indri as a native LaunchAgent. ## What changed - **New ansible role** `ansible/roles/devpi/`: installs `devpi-server` + `devpi-web` into a uv-managed venv, initializes the server-dir on first run via 1Password root password, runs as a LaunchAgent (`mcquack.eblume.devpi`) bound to `127.0.0.1:3141`. Bootstraps from upstream PyPI (so devpi can install itself on a fresh box). - **Caddy**: `pypi.ops.eblu.me` now proxies to `http://localhost:3141`. - **Playbook**: `indri.yml` gains pre_tasks for the root password and the new role. - **service-versions.yaml**: devpi flipped from `type: argocd` to `type: ansible`. - **ArgoCD**: removed `apps/devpi.yaml` and `manifests/devpi/`. The in-cluster Application, namespace, and PVC have been deleted. - **Docs**: new how-to `docs/how-to/operations/devpi-on-indri.md`; `restart-indri.md` lists devpi in the LaunchAgent stop list. ## Already deployed (live on indri) - Service running: `launchctl list mcquack.eblume.devpi` → PID 53888 - `curl https://pypi.ops.eblu.me/+api` returns 200 ✅ - `mise run docs-mikado` works again ✅ - 1.0G of cached PyPI data was migrated from the PVC to `~erichblume/devpi/server-dir/` - Minikube namespace and PVC fully reclaimed ## Test plan - [ ] `mise run services-check` (after merge) - [ ] CI workflows that use devpi succeed - [ ] No regressions in tools that depend on `pypi.ops.eblu.me` (prek, uv-script tasks, dagger pipelines) ## Context This is the C1 prelude to a planned C2 chain (`mikado/retire-minikube-indri`) to retire minikube on indri entirely. Doing devpi as a standalone C1 was the right call because (a) it was urgent — it was breaking the toolchain — and (b) it shakes out the migration recipe before we commit to a multi-leaf chain.
End-state doc describing devpi as a native LaunchAgent on indri,
replacing the minikube StatefulSet. Covers layout, deploy, verify,
and version bumps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New ansible role ansible/roles/devpi installs devpi-server +
  devpi-web into a uv-managed venv at ~erichblume/devpi/venv,
  initializes the server-dir on first run (via 1Password root
  password fetched in playbook pre_tasks), and runs as a LaunchAgent
  bound to 127.0.0.1:3141.
- Caddy: switch the pypi.ops.eblu.me backend from the tailscale
  ingress to http://localhost:3141.
- Playbook indri.yml: add pre_tasks to fetch the devpi root
  password from 1Password and include the new role.

The minikube StatefulSet has been scaled to 0 to free memory; the
ArgoCD app + manifests will be removed in a follow-up commit once
the launchd service is verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove argocd/apps/devpi.yaml and argocd/manifests/devpi/ — the
  in-cluster Application + namespace + PVC are already deleted.
- service-versions.yaml: flip devpi from type: argocd to type: ansible.
- ansible/roles/devpi/tasks: install with --index-url https://pypi.org/simple/
  to avoid devpi-installs-itself-from-itself bootstrap loop;
  add changed_when: true on the init task to satisfy ansible-lint.
- restart-indri.md: include devpi in the LaunchAgent stop list and
  link to the new how-to (also satisfies wiki-link orphan check).
- changelog fragment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The blackbox probe was pointing at the in-cluster devpi service,
which no longer exists. Probe https://pypi.ops.eblu.me/+api instead;
the cluster reaches it via Tailscale + Caddy on indri.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- docs/reference/services/devpi.md: rewrite for the new launchd
  layout (no more namespace/PVC/ArgoCD/image/ExternalSecret) and
  link to the new how-to.
- docs/reference/infrastructure/tailscale.md: drop tag:devpi from
  the per-service Ingress tag list.
- docs/reference/storage/backups.md: clarify the devpi-cache row
  to call out the new on-indri path.
- docs/how-to/operations/rebuild-minikube-cluster.md: trim the
  "Devpi cold cache after rebuild" section — devpi is no longer in
  minikube — keep a brief note for the still-possible cold-cache
  race after fresh devpi init.
- docs/how-to/operations/devpi-on-indri.md: correct the Backup
  section — server-dir is NOT in borgmatic_source_directories.
- pulumi/tailscale: remove now-dead tag:devpi ACL rule, tagOwner,
  and __main__.py comment. Will need `pulumi up` to apply.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eblume merged commit 14ca0160ba into main 2026-04-29 13:38:38 -07:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
eblume/blumeops!341
No description provided.