SQP Kanban — The Deployment Process
This is the second post about containerising SQP Kanban. Here’s how the actual process went.
Step 1 — Dockerfile
Straightforward. Alpine-based Node image, copy package.json first (so npm install gets cached), then copy the app code. The main lesson was getting the layer order right for efficient rebuilds.
Step 2 — Manual Docker Run
Before Docker Compose, I ran everything manually to understand what each piece does:
docker network create sqp-network
docker run -d --name sqp-mongo --network sqp-network -v sqp-mongo-data:/data/db mongo:8
docker build -t sqp-kanban .
docker run -d --name sqp-kanban --network sqp-network -p 4000:4000 -e MONGO_URI=mongodb://sqp-mongo:27017/sqp-kanban sqp-kanban
Four commands. Each one taught me something — networks, volumes, port mapping, environment variables. Worth doing manually at least once before reaching for Compose.
Step 3 — Docker Compose
Replaced those four commands with a single docker-compose.yml. One gotcha — I’m on Fedora Cosmic (immutable), which uses Podman instead of Docker. The shorthand build: . syntax didn’t work with podman-compose, so I had to use the expanded form with context, dockerfile, and an explicit image name. Volumes also needed driver: local declared explicitly. Both fixes are compatible with Docker too, so one file works everywhere.
Step 4 — Self-hosted Runner
My homelab server (Bitfrost, Ubuntu) can’t be reached from GitHub’s cloud, so GitHub-hosted runners were out. I installed a self-hosted runner on Bitfrost instead — it connects outbound to GitHub and waits for jobs. No port forwarding needed.
Since the repo is public, I also set the fork PR policy to require approval for all external contributors. Without this, anyone could fork the repo and run code on my server.
Step 5 — GitHub Actions Workflow
The workflow file is minimal — trigger on push to main, check out the code, run docker compose up -d --build. The first run failed because Bitfrost had Docker Compose v1 (uses a hyphen: docker-compose) instead of v2 (uses a space: docker compose). A quick apt install docker-compose-plugin fixed it.
Step 6 — Testing the Pipeline
The dev workflow: work on dev branch, push, create a PR to main, merge. GitHub Actions picks it up and deploys to Bitfrost automatically. Tested by stopping containers, merging a PR, and confirming the app came back up with data intact.
Takeaway
The whole setup took an afternoon. Most of the time was spent debugging — not writing config. The config files are simple; the errors along the way are where the real learning happens.