P4: Miniflux migration + PostgreSQL consolidation #33

Merged
eblume merged 8 commits from feature/p4-miniflux into main 2026-01-20 09:04:48 -08:00
Showing only changes of commit 0956e0ed2b - Show all commits

Update P4 plan with implementation notes and mark complete

Erich Blume 2026-01-19 21:44:32 -08:00

View file

@ -1,48 +1,125 @@
# Phase 4: Miniflux Migration
# Phase 4: Miniflux Migration to Kubernetes
**Goal**: Migrate Miniflux to k8s
**Goal**: Migrate Miniflux entirely off indri and onto k8s, retire brew PostgreSQL, rename k8s-pg to pg
**Status**: Pending
**Status**: Complete (2026-01-19)
**Prerequisites**: [Phase 3](P3_postgresql.md) complete
**Prerequisites**: [Phase 3](P3_postgresql.complete.md) complete
---
## Steps
## Overview
### 1. Deploy Miniflux
```yaml
image: ghcr.io/miniflux/miniflux:latest
env:
DATABASE_URL: from secret
RUN_MIGRATIONS: "1"
```
This phase completed the miniflux migration and retired brew PostgreSQL:
1. Deployed miniflux container in k8s via ArgoCD
2. Exposed via Tailscale Ingress at `feed.tail8d86e.ts.net`
3. Removed all miniflux infrastructure from indri (ansible role, brew service, Tailscale serve)
4. Retired brew PostgreSQL (no longer needed)
5. Renamed k8s-pg to pg (canonical Tailscale hostname)
6. Updated borgmatic to backup only `pg.tail8d86e.ts.net`
7. Updated all zk documentation
---
### 2. Configure Tailscale LoadBalancer
## New Files
Tag: `svc:feed`
| Path | Purpose |
|------|---------|
| `argocd/apps/miniflux.yaml` | ArgoCD Application definition |
| `argocd/manifests/miniflux/deployment.yaml` | Miniflux Deployment |
| `argocd/manifests/miniflux/service.yaml` | ClusterIP Service |
| `argocd/manifests/miniflux/ingress-tailscale.yaml` | Tailscale Ingress for `feed.tail8d86e.ts.net` |
| `argocd/manifests/miniflux/secret-db.yaml.tpl` | Database URL secret documentation |
| `argocd/manifests/miniflux/kustomization.yaml` | Kustomize configuration |
| `argocd/manifests/miniflux/README.md` | Setup instructions |
## Modified Files
| Path | Change |
|------|--------|
| `ansible/playbooks/indri.yml` | Removed miniflux and postgresql roles, simplified pre_tasks |
| `ansible/roles/tailscale_serve/defaults/main.yml` | Removed `svc:feed` and `svc:pg` entries |
| `ansible/roles/alloy/defaults/main.yml` | Removed miniflux and postgresql logs, disabled postgres metrics |
| `ansible/roles/borgmatic/defaults/main.yml` | Updated to backup only `pg.tail8d86e.ts.net` |
| `ansible/roles/borgmatic/tasks/main.yml` | Added .pgpass file management |
| `argocd/manifests/databases/service-tailscale.yaml` | Renamed hostname from k8s-pg to pg |
## Deleted Files
| Path | Reason |
|------|--------|
| `ansible/roles/miniflux/` | Entire role no longer needed |
| `ansible/roles/postgresql/` | Brew PostgreSQL no longer needed |
---
### 3. Update Alloy log collection
## Verification
Add k8s namespace
- [x] Miniflux pod healthy in k8s
- [x] https://feed.tail8d86e.ts.net accessible
- [x] User `eblume` can log in
- [x] Feeds visible and entries readable
- [x] `pg.tail8d86e.ts.net` resolves to k8s PostgreSQL
- [x] Old `k8s-pg` and `feed` devices removed from Tailscale
- [x] brew miniflux and postgresql services stopped
- [x] Tailscale serve entries cleared from indri
- [x] zk documentation updated
---
### 4. Verify
## Implementation Notes
- Login works
- Feeds refresh
- API works
*Lessons learned and issues encountered*
---
### CNPG-Generated Password vs 1Password
### 5. Stop brew miniflux
**Problem**: Initial secret template used 1Password for miniflux database password, but CNPG auto-generates the bootstrap owner password.
**Solution**: Reference the CNPG-generated password from `blumeops-pg-app` secret:
```bash
brew services stop miniflux
kubectl create secret generic miniflux-db -n miniflux \
--from-literal=url="$(kubectl -n databases get secret blumeops-pg-app -o jsonpath='{.data.uri}' | base64 -d)"
```
### Table Ownership Issue After P3 Restore
**Problem**: Miniflux pod crashed with "permission denied for table schema_version".
**Root cause**: P3 restore was run as the `eblume` superuser, so all tables were created owned by `eblume`, not `miniflux`.
**Solution**: Transfer ownership of all tables to miniflux:
```sql
DO $$
DECLARE r RECORD;
BEGIN
FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = 'public') LOOP
EXECUTE 'ALTER TABLE public.' || quote_ident(r.tablename) || ' OWNER TO miniflux';
END LOOP;
END$$;
```
### Tailscale Ingress Hostname Suffix
**Behavior**: When requesting a Tailscale hostname that's already taken, the operator adds a suffix (e.g., `feed-1`).
**Workflow**:
1. Deploy initially - gets `feed-1.tail8d86e.ts.net`
2. Clear old `svc:feed` from indri
3. Delete old `feed` device from Tailscale admin
4. Delete and recreate the Ingress - now claims `feed`
### Renaming Tailscale Service Hostname
**Problem**: Changing the `tailscale.com/hostname` annotation doesn't automatically update the Tailscale device.
**Solution**: Delete the service and let ArgoCD recreate it:
```bash
kubectl -n databases delete service blumeops-pg-tailscale
argocd app sync blumeops-pg
```
### .pgpass Management Migration
**Issue**: The postgresql role managed `~/.pgpass` for borgmatic. With postgresql role deleted, borgmatic couldn't authenticate.
**Solution**: Moved .pgpass management to the borgmatic role. Password is still fetched in playbook pre_tasks as `borgmatic_db_password`.