diff --git a/K8S.md b/K8S.md index 5eb1c6d8..754c2622 100644 --- a/K8S.md +++ b/K8S.md @@ -4,7 +4,8 @@ Redis, a volume for uploaded media, and an Ingress. PostgreSQL 18 is **not** included: use your own database and point the app at it. -> Not tested on a cluster. The image itself is tested with `docker compose` (see [DOCKER.md](DOCKER.md)). +> Tested on a local `kind` cluster with a scratch Postgres (migrate Job, then web and the admin +> answer 200). Not tested on your cluster, ingress controller or real data. ## Steps @@ -29,26 +30,30 @@ own database and point the app at it. ```sh kubectl create secret generic dynamicweb --from-env-file= ``` -4. **Edit the manifest:** your image name (it appears twice) and the Ingress hosts (one rule for - each domain, with `www.` variants). Set `ingressClassName` to your controller. -5. **Deploy:** +4. **Edit the manifest:** your image name (it appears three times) and the Ingress hosts (one rule + for each domain, with `www.` variants). Set `ingressClassName` to your controller. +5. **Migrate, then start.** If you have old data, restore it into the empty database first (for + example `psql -h -U < dump.sql`). Then: ```sh kubectl apply -f k8s/dynamicweb.yaml + kubectl logs -f job/dynamicweb-migrate # takes a few minutes; ends when the Job completes + kubectl rollout restart deploy/dynamicweb-web kubectl logs -f deploy/dynamicweb-web # ready at "Listening at" ``` - The first start runs the database migrations, so it takes a few minutes. + The `dynamicweb-migrate` Job runs the migrations once. The web pods don't migrate, so restart + them after the Job completes (a web pod that started earlier serves errors until you do). 6. **Check:** `curl -I -H 'Host: ungleich.ch' http:///en-us/` returns 200. Admin is at `/en-us/admin/login/` on any site's address. ## Good to know -- **Run one web replica first.** Each web pod migrates the database when it starts. After the first - start you can scale (`kubectl scale deploy/dynamicweb-web --replicas=2`), with the media volume - changed to `ReadWriteMany` so every pod sees the same uploads. +- **Scaling:** `kubectl scale deploy/dynamicweb-web --replicas=2`, with the media volume changed + to `ReadWriteMany` so every pod sees the same uploads. - **Ingress must keep the original `Host` header** (the default). The site is chosen from the host, and every domain must be in `UNGLEICH_SITE_CONFIGS` and in `ALLOWED_HOSTS` (`dynamicweb/settings/prod.py` lists the current ones). -- **Updating:** push a new image tag, change the image in the manifest and apply it again. +- **Updating:** push a new image tag, change the image in the manifest, delete the old Job + (`kubectl delete job dynamicweb-migrate`) and apply again, then restart web. - **Logs:** `kubectl logs deploy/dynamicweb-web` and `kubectl logs deploy/dynamicweb-celery`. -- **Optional hardening:** run the migrations once as a Job instead of in every pod. Use a Job with - `env: ROLE=migrate`, and add `RUN_MIGRATIONS=False` to the web Deployment. +- **Don't name a Service `postgres` without `enableServiceLinks: false`.** Kubernetes would inject + `POSTGRES_PORT=tcp://...` and the app crashes. The manifest already sets it on every pod.