Add container image: two-stage uv build, non-root user, data volume

This commit is contained in:
Archibold committed 2026-11-07 15:02:24 +11:00
1 parent a39da9e615
commit f266bc5104
3 files changed
+118

No files matched your search

+36
View File
@@ -23,6 +23,42 @@ Development reload:
uv run uwudash-mk3 --reload
```
### Container
```bash
docker build -t uwudash-mk3 .
docker run -d -p 8000:8000 -v uwudash-data:/app/data uwudash-mk3
```
The image is two-stage: `uv build` produces the wheel from the `src/` layout, a
clean stage installs it into `/app/.venv`, and the entrypoint is the
`uwudash-mk3` console script. It runs as uid `10001` and binds `0.0.0.0:8000`
(`UWUDASH_HOST` / `UWUDASH_PORT` are baked in as `ENV` defaults - override both
the `--env` and the `-p` mapping if you change the port).
`/app/data` is a `VOLUME` holding `services.json` (and `users.json` once auth is
on): a named volume keeps your service list across restarts, a bind mount
(`-v ./data:/app/data`) seeds the container from the host file instead. `data/`
is in `.dockerignore`, so internal URLs and per-service `headers` tokens never
land in an image layer. With a bind mount the directory must be writable by uid
`10001` (`chown -R 10001 data`); a named volume inherits the image's ownership.
Sign-in from a container - secrets come from the environment, never the build
context (`.dockerignore` excludes `.secrets`, `.oauth_creds` and `start.sh`):
```bash
docker run -d -p 8000:8000 -v uwudash-data:/app/data \
--env UWUDASH_OIDC_ISSUER=https://id.example.com \
--env UWUDASH_OIDC_CLIENT_ID=uwudash \
--env UWUDASH_OIDC_CLIENT_SECRET=... \
--env UWUDASH_SESSION_SECRET="$(openssl rand -hex 32)" \
--env UWUDASH_PUBLIC_URL=https://dash.example.com \
uwudash-mk3
```
`HEALTHCHECK` polls `/health`, the one route that needs no session, so the
container stays `healthy` with auth on.
### Command line flags
| Flag | Default | Meaning |