blumeops/docs/how-to/immich/immich-cutover-and-decommission.md
Erich Blume b21d13fe20 C2(migrate-immich-to-ringtail): finalize chain — strip mikado frontmatter, add changelog
Immich is fully migrated off minikube-indri onto k3s-ringtail. All
six prerequisite cards plus the goal card converted to historical
documentation by removing status/branch/requires Mikado frontmatter.

Changelog fragment added at docs/changelog.d/migrate-immich-to-ringtail.infra.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:46:27 -07:00

103 lines
4.3 KiB
Markdown

---
title: Immich Cutover and Decommission
modified: 2026-05-13
last-reviewed: 2026-05-13
tags:
- how-to
- operations
- immich
- migration
---
# Immich Cutover and Decommission
The user-visible flip. By the time this card opens, the ringtail
stack has been proven against a copy of the data. This card does the
real cutover.
## Pre-cutover checklist
- [[immich-pg-data-migration]] dry-run succeeded; method is chosen.
- Ringtail immich stack has been brought up against the test pg,
pods healthy, UI loaded ([[immich-app-on-ringtail#Verification]]).
- Borgmatic just ran successfully (a fresh nightly archive is a
belt-and-suspenders fallback, on top of the live source pg).
- User has been told to stop uploading from the iOS app for the
cutover window.
## Cutover sequence
1. **Quiesce source.** `kubectl --context=minikube-indri -n immich
scale deploy/immich-server --replicas=0` and same for ML. Leave
valkey + pg running. Confirm no client traffic on the source pg
via `pg_stat_activity`.
2. **Tear down the minikube Tailscale ingress.** The `photos`
Tailscale device name must be freed before ringtail's ingress can
claim it (Tailscale enforces uniqueness across the tailnet).
`kubectl --context=minikube-indri -n immich delete ingress
immich-tailscale` and wait for the corresponding `tailscale`-LB
StatefulSet pod to terminate. Verify the `photos` device is gone:
`tailscale status | grep -i photos` from any tailnet host.
3. **Final sync.** Per chosen method in
[[immich-pg-data-migration]]:
- Option A: promote the ringtail replica.
- Option B: take final `pg_dump`, restore to ringtail
`immich-pg`.
4. **Verify.** Run the row-count and schema-diff checks from
[[immich-pg-data-migration#Verification on the real run]].
5. **Flip the ringtail ingress to `photos`.** Update
`argocd/manifests/immich-ringtail/ingress-tailscale.yaml`:
`tls.hosts: [photos]` (was `[photos-ringtail]` during staging per
[[immich-app-on-ringtail]]). Commit, `argocd app sync
immich-ringtail`. Wait for the `photos` device to register on the
tailnet again.
6. **Bring up ringtail immich** against the now-promoted pg
(`argocd app sync immich-ringtail`). Wait for Ready.
7. **Flip routing.** Update Caddy on indri
(`ansible/roles/caddy/defaults/main.yml`): `photos.ops.eblu.me`
upstream changes to the ringtail Tailscale ingress hostname
(`photos` — same MagicDNS name, now pointing to the ringtail
proxy). `mise run provision-indri -- --tags caddy`.
8. **Smoke test.** Open `photos.ops.eblu.me` in a browser. Sign in.
Scroll the timeline. Open an album. Trigger an ML search.
9. **Update borgmatic.** If the Tailscale hostname for pg changed,
update `borgmatic.cfg` on indri to point at the ringtail
`immich-pg-tailscale` service. Run a manual backup to verify.
## After cutover
- `argocd app set immich --revision <branch>` is no longer relevant;
the minikube `immich` app gets deleted entirely.
- Delete `argocd/apps/immich.yaml`, `argocd/manifests/immich/`, and
the minikube `argocd/manifests/databases/immich-pg.yaml` +
`external-secret-immich-borgmatic.yaml` +
`service-immich-pg-tailscale.yaml`.
- Rename `immich-ringtail` back to `immich` (the `-ringtail` suffix
was scaffolding for the dual-cluster window; once minikube is
empty of immich, the unsuffixed name is clean).
- Confirm the minikube `immich-pg` PVC is no longer used, then
delete it (the PV with `Retain` policy will persist — clean that
up too).
## Verification (definition of done)
- `photos.ops.eblu.me` works for a real session, including ML search.
- Source minikube has no `immich` pods, no `immich-pg`, no PVCs.
- Memory pressure on minikube has dropped (≥1.5 GiB reclaimed). Check
`docker stats minikube` on indri.
- Nightly borgmatic run after the cutover completes successfully,
with the immich-pg archive showing the new source.
## Rollback (within the cutover window)
If smoke test fails: flip Caddy back, scale ringtail immich to 0,
scale source immich back up. Source pg was never destroyed. File a
plan reset on the relevant prerequisite card and try again next
session.
## Out of scope
- Decommissioning all of minikube. This chain just removes immich.
Other tenants migrate in their own chains as part of the broader
indri-k8s decommission. See [[migrate-immich-to-ringtail]] for
context.