Mana Archive Platform

I rebuilt this project from the ground up to force understanding instead of relying on a messy “it works somehow” setup. The result is a reproducible workflow: local app runtime, containerization, image publishing, Kubernetes delivery, ingress routing, and persistent data.

How I verified the system

  • Inserted data into SQLite → deleted Pod → confirmed persistence via PVC
  • Verified ingress routing behavior using Host-based rules (mana.local)
  • Confirmed CI pipeline builds and publishes images to GHCR on push

What I built

Client
  ↓
Traefik Ingress (host: mana.local)
  ↓
Service (ClusterIP :80 → targetPort 8501)
  ↓
Pod
  ↓
Container (Streamlit app on 8501)
  ↓
PersistentVolumeClaim mounted at /app/data
  • The app runs as a single containerized Streamlit workload
  • Images are built locally and automatically in CI, then published to GHCR
  • Kubernetes pulls the image and runs it in a Deployment
  • Traefik routes requests by hostname through an Ingress rule
  • SQLite data persists across Pod replacement via a PVC
Mana Archive App Screenshot

Containerization

Containerized the app with Podman and aligned the runtime to Streamlit’s actual behavior, including correct port exposure and bind address.

Registry workflow

Published images to GitHub Container Registry so build and runtime concerns stay separated. The cluster pulls images instead of building them locally.

Kubernetes delivery

Implemented a minimal, explainable stack: Deployment, Service, and Ingress—without unnecessary sidecars or internal reverse proxies.

Persistence

Mounted a PVC at /app/data so the SQLite database survives Pod recreation. Verified by inserting data, deleting the Pod, and confirming the records remained.

CI/CD

Added GitHub Actions to automatically build and push images to GHCR on pushes to main, creating a real image pipeline instead of a manual-only process.

Debugging

Diagnosed ingress 404 behavior by understanding that Traefik matched on the Host header. Direct IP access failed until the hostname matched the Ingress rule.

What this project taught me

  • Kubernetes does not redeploy a running workload just because an image in the registry changed; the Deployment spec must change or the Pods must restart.
  • Ingress routing depends on the Host header, not just the raw node IP address.
  • PersistentVolume mounts replace the target path inside the container and do not migrate pre-existing in-container data automatically.
  • Keeping development, build, and runtime boundaries clean makes debugging dramatically easier.