Skip to content

Deployment Overview

KanjiIQ uses a fully automated CI/CD pipeline that builds Docker images, pushes them to the Forgejo Container Registry, and deploys to the k3s cluster on every push to main.

Pipeline Flow

graph LR
    A[git push main] --> B[Forgejo Actions<br/>Triggered]
    B --> C[Docker Build<br/>Multi-stage]
    C --> D[Push to Registry<br/><registry>]
    D --> E[kubectl set image<br/>Rolling update]
    E --> F[Rollout Status<br/>Health check]

Path-Based Triggering

Each component has its own workflow, triggered only when relevant files change:

Workflow Trigger Paths Image
deploy-frontend.yml frontend/**, Dockerfile.frontend, nginx.frontend.conf jlpt-kanji-frontend
deploy-backend.yml backend/**, Dockerfile.backend jlpt-kanji-backend
deploy-docs.yml docs/**, mkdocs.yml, Dockerfile.docs jlpt-kanji-docs

This means changing a documentation page does not trigger a frontend or backend rebuild.

Deployment Strategy

KanjiIQ uses Kubernetes rolling updates:

  • New pods are created with the updated image
  • Readiness probes must pass before old pods are terminated
  • If the new version fails health checks, the rollout is automatically stopped
  • Zero-downtime deployments with 2 replicas

Environments

Environment Purpose URL
Production Live application kanjiiq.com
Staging Pre-release testing Local k8s namespace
Development Local development localhost:8080 / localhost:3000

The staging environment mirrors production manifests in a separate Kubernetes namespace (jlpt-kanji-staging) with its own PostgreSQL instance.

Image Tagging

Every build produces two tags:

  • :latest — Always points to the most recent build
  • :COMMIT_SHA — Immutable tag for traceability

Deployments use the commit SHA tag to ensure deterministic rollouts:

kubectl set image deployment/jlpt-kanji \
  frontend=<registry>/jlpt-kanji-frontend:abc1234 \
  -n jlpt-kanji