Kubernetes deployment
The site runs on the personal k3s cluster in the personal-site namespace and is served at
https://jesseinit.dev (www. redirects to the apex). TLS comes from cert-manager (letsencrypt-prod).
How deploys work
.github/workflows/deploy.yml (run by Gitea Actions) on every push to master:
- Build site:
npm ci && npm run build, and renders the kustomization to catch manifest errors. - Build and push image:
tea.jesseinit.dev/jesseinit/personal-site:sha-<commit>and:latest. - Deploy: pins
newTaginkustomization.yamltosha-<commit>, runskubectl apply -k k8s/, waits for the rollout, and rolls back automatically if it fails.
Pull requests run step 1 only. Old images are cleaned up by the nightly gitea-package-prune cronjob.
Required secrets (repo or production environment in Gitea)
| Secret | Value |
|---|---|
REGISTRY_TOKEN |
Gitea token with write:package for jesseinit |
KUBE_CONFIG |
base64-encoded kubeconfig for the personal cluster |
Files
namespace.yaml:personal-sitenamespacedeployment.yaml: 2 replicas, zero-downtime rolling updates, non-root, health checksservice.yaml: ClusterIP on port 80 → container port 3000ingress.yaml: nginx ingress + TLS forjesseinit.dev/www.jesseinit.devconfigmap.yaml: optional environment variableskustomization.yaml: ties it together and sets the image
Manual operations
kubectl --context personal-cluster -n personal-site get pods,ingress,certificate
kubectl --context personal-cluster -n personal-site logs -l app=jesseinit-portfolio -f
kubectl --context personal-cluster -n personal-site rollout undo deployment/jesseinit-portfolio
# Deploy by hand (uses :latest)
kubectl --context personal-cluster apply -k k8s/