CI/CD Pipeline¶
KanjiIQ uses Forgejo Actions for continuous integration and deployment. Forgejo Actions is compatible with GitHub Actions YAML syntax, running on self-hosted runners.
Workflow Structure¶
.forgejo/workflows/
├── deploy-frontend.yml # Build & deploy Flutter Web
├── deploy-backend.yml # Build & deploy Dart Frog API
└── deploy-docs.yml # Build & deploy documentation site
Each workflow follows the same pattern:
graph TD
A[Push to main] --> B{Path filter<br/>matches?}
B -->|Yes| C[Checkout code]
B -->|No| X[Skip]
C --> D[Login to Forgejo<br/>Container Registry]
D --> E[Docker build<br/>--no-cache]
E --> F[Push :latest +<br/>:COMMIT_SHA]
F --> G[kubectl set image]
G --> H[Wait for rollout<br/>timeout: 5m]
H --> I[Cleanup: logout]
Frontend Workflow¶
name: Deploy Frontend to k3s
on:
push:
branches: [main]
paths:
- 'frontend/**'
- 'Dockerfile.frontend'
- 'nginx.frontend.conf'
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to registry
run: echo "$FORGEJO_TOKEN" | docker login $REGISTRY_URL -u $REGISTRY_USER --password-stdin
- name: Build image
run: |
docker build --no-cache --pull \
--build-arg CACHEBUST=$(date +%s) \
-f Dockerfile.frontend \
-t <registry>/jlpt-kanji-frontend:latest \
-t <registry>/jlpt-kanji-frontend:$(git rev-parse --short HEAD) .
- name: Push & deploy
run: |
docker push <registry>/jlpt-kanji-frontend:latest
docker push <registry>/jlpt-kanji-frontend:$(git rev-parse --short HEAD)
kubectl set image deployment/jlpt-kanji \
frontend=<registry>/jlpt-kanji-frontend:$(git rev-parse --short HEAD) \
-n jlpt-kanji
kubectl rollout status deployment/jlpt-kanji -n jlpt-kanji --timeout=5m
Secrets¶
Workflows use a single secret:
| Secret | Purpose |
|---|---|
FORGEJO_TOKEN |
Authentication for container registry push and Kubernetes access |
The token is configured in Forgejo at Repository Settings > Secrets.
Image Registry¶
All images are stored in the Forgejo Container Registry:
<registry>/jlpt-kanji-frontend:latest
<registry>/jlpt-kanji-frontend:<commit-sha>
<registry>/jlpt-kanji-backend:latest
<registry>/jlpt-kanji-backend:<commit-sha>
<registry>/jlpt-kanji-docs:latest
<registry>/jlpt-kanji-docs:<commit-sha>
Rollout Verification¶
After kubectl set image, the workflow waits for the rollout to complete:
This blocks until:
- All new pods pass readiness probes, or
- The timeout expires (workflow fails, alerting the developer)
If a rollout fails, Kubernetes automatically stops rolling out and the previous version continues serving traffic.
Manual Rollback¶
To revert to a previous version: