MkDocs Documentation Site on k3s¶
This documentation site itself runs on k3s! Here's how it's deployed and how to work with it.
Overview¶
- Framework: MkDocs with Material theme
- Hosting: Kubernetes Deployment + nginx
- URL:
doc.serlo.lu - Build: Docker multi-stage build bakes the static site
Architecture¶
graph LR
A["docs/ folder<br/>(Markdown)"] -->|Build| B["Docker Image<br/>(builder)"]
B -->|Multi-stage| C["nginx:alpine<br/>(runtime)"]
C -->|Deploy| D["k8s Deployment"]
D -->|Service| E["Traefik Ingress"]
E -->|DNS| F["doc.serlo.lu"] Building the Image Locally¶
Prerequisites¶
pip install mkdocs mkdocs-material
View Changes Locally¶
cd /path/to/homelab
mkdocs serve
# Open http://localhost:8000
Build Docker Image¶
# Build (reads mkdocs.yml + docs/ folder)
docker build -t ghcr.io/your-org/homelab-mkdocs:latest -f docs/docker/Dockerfile .
# Test locally
docker run -p 8000:80 ghcr.io/your-org/homelab-mkdocs:latest
# Open http://localhost:8000
Deploying to k3s¶
Method 1: Push to Registry + Deploy¶
# Push image
docker push ghcr.io/your-org/homelab-mkdocs:latest
# Deploy to cluster
kubectl apply -k apps/base/mkdocs
Method 2: ConfigMap (Build in CI)¶
Build in CI, create ConfigMap from static output:
# Build locally
mkdocs build -d site/
# Create ConfigMap manifest
kubectl -n mkdocs create configmap mkdocs-site --from-file=site --dry-run=client -o yaml > mkdocs-cm.yaml
# Apply
kubectl apply -f mkdocs-cm.yaml
kubectl apply -f docs/k8s/mkdocs/deployment.yaml
kubectl apply -f docs/k8s/mkdocs/service.yaml
kubectl apply -f docs/k8s/mkdocs/ingress.yaml
Kubernetes Manifests¶
apps/base/mkdocs/
├── kustomization.yaml
├── deployment.yaml
├── service.yaml
└── ingress.yaml
docs/k8s/mkdocs/
├── namespace.yaml
├── deployment.yaml
├── service.yaml
└── ingress.yaml
Uses the built Docker image; update image tag to deploy new versions.
- Replicas: 2 (load-balanced)
- Node selector:
kubernetes.io/hostname: oracle(set to your node) - Resources: 50m CPU, 64Mi RAM (request); 200m CPU, 256Mi RAM (limit)
- Host:
doc.serlo.lu - TLS: Managed by cert-manager
- Ingress class: Traefik
Updating Documentation¶
Workflow¶
- Edit markdown in
docs/folder (locally or via git) - Commit & push to repository
- Build image (manually or in CI) and push to registry
- Deploy via
kubectl apply -k apps/base/mkdocsor wait for Flux
Fast iteration (local)¶
# Terminal 1: Watch for changes
mkdocs serve
# Terminal 2: Edit docs/index.md, docs/apps/..., etc
# Changes appear instantly at http://localhost:8000
Production deployment (CI)¶
Scaffold a workflow in .github/workflows/deploy-docs.yml that: - Builds the Docker image - Pushes to registry - Updates apps/base/mkdocs/kustomization.yaml image tag - Commits changes (Flux detects & reconciles)
Similar pipeline using .gitlab-ci.yml
Customization¶
Change Theme Colors¶
Edit mkdocs.yml:
theme:
palette:
- scheme: default
primary: indigo # Change to: blue, teal, green, etc.
accent: indigo # Change accent color
Add Navigation Sections¶
Edit mkdocs.yml nav:
nav:
- Home: index.md
- New Section:
- Page 1: path/to/page1.md
- Page 2: path/to/page2.md
Use Material Theme Features¶
Examples:
!!! info "Title"
Content here
=== "Tab 1"
Content
=== "Tab 2"
Other content
\`\`\`yaml
key: value # (1)
\`\`\`
1. Explanation here
Monitoring & Logs¶
Check deployment status¶
# View pod status
kubectl -n mkdocs get pods
kubectl -n mkdocs describe deployment mkdocs-site
# Stream logs
kubectl -n mkdocs logs -f deployment/mkdocs-site
# Check ingress
kubectl -n mkdocs get ingress mkdocs
Access the site¶
# Via ingress (requires DNS + TLS setup)
https://doc.serlo.lu
# Via port-forward (local testing)
kubectl -n mkdocs port-forward svc/mkdocs 8000:80
# Then: http://localhost:8000
Troubleshooting¶
"image pull backoff"¶
# Verify image exists in registry
docker pull ghcr.io/your-org/homelab-mkdocs:latest
# Check pod events
kubectl -n mkdocs describe pod <pod-name>
"Ingress not working"¶
# Verify ingress is created
kubectl -n mkdocs get ingress -o wide
# Check Traefik is routing to service
kubectl -n mkdocs get svc mkdocs
# Verify DNS
nslookup doc.serlo.lu
"Page returns 404"¶
- Ensure
mkdocs buildwas run locally (generatessite/folder) - Verify image contains the correct
site/output - Check nginx logs:
kubectl -n mkdocs logs <pod>