76 lines
6.0 KiB
Markdown
76 lines
6.0 KiB
Markdown
# 42 — Implemented deployment baseline
|
|
|
|
## Scope and status
|
|
|
|
Milestone 0 provides one multi-stage `Dockerfile`, a hardened production Compose reference, a Compose Watch development reference, and GitHub Actions gates. The production path was built and exercised on Unraid 7.2 with Docker 27.5.1 and Compose 2.40.3. Image build, container health, database degradation/recovery, migration replay, persisted restart, and backup/restore evidence are recorded in `docs/43-milestone-zero-host-validation.md`.
|
|
|
|
## Pinned runtime images
|
|
|
|
- Node.js `24.18.0` (`Krypton`, LTS): `node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d`
|
|
- PostgreSQL `17.9`: `postgres:17.9-bookworm@sha256:47f917f7409eacd22fc5dfb1dee634e1b55cf0c01d1a7eb701be2227a03e0641`
|
|
- pnpm `10.33.0`, activated by Corepack to match `package.json`
|
|
|
|
The Docker Hub API reported both digests as multi-platform manifest-list digests. That metadata was checked over HTTPS on 2026-07-27. Both images were pulled and exercised on the `linux/amd64` validation host. Final release evidence must still record the release application's image digests and scan results.
|
|
|
|
## Production setup
|
|
|
|
Use URL-safe random characters for `POSTGRES_PASSWORD`, because Compose embeds it in `DATABASE_URL`. Generate the other values with a cryptographically secure tool; do not reuse these commands' output across instances.
|
|
|
|
```bash
|
|
export POSTGRES_PASSWORD="replace-with-a-url-safe-random-password"
|
|
export SESSION_SECRET="replace-with-at-least-32-random-bytes"
|
|
export INTEGRATION_ENCRYPTION_KEY="replace-with-base64-of-exactly-32-random-bytes"
|
|
export BOOTSTRAP_TOKEN="replace-with-a-random-first-run-token"
|
|
export PUBLIC_BASE_URL="https://runbooks.example.com"
|
|
docker compose build
|
|
docker compose up -d
|
|
docker compose ps
|
|
```
|
|
|
|
Compose starts PostgreSQL, runs migrations as a one-shot prerequisite, and then starts independent web and worker targets. Only the web port is published. PostgreSQL remains internal. The 28 built-in playbooks remain immutable in the image at `/content/playbooks`, so an empty host volume cannot obscure them. `operator-content`, `artifacts`, and `postgres-data` persist independently of containers. `/operator-content` is reserved for the controlled operator-package import path; the current vertical slice does not consume it automatically.
|
|
|
|
The web and worker run as the image's unprivileged `node` user with all Linux capabilities dropped, `no-new-privileges`, a read-only root filesystem, and a bounded writable `/tmp`. Built-in and operator content are read-only to both runtime services. The artifact mount is writable. No Docker socket, privileged mode, host PID namespace, or application secret is included.
|
|
|
|
## Development setup
|
|
|
|
The development reference contains explicit local-only credentials and must not be exposed or promoted to production.
|
|
|
|
```bash
|
|
docker compose -f docker-compose.dev.yml up --build
|
|
# For synchronized source changes with Docker Compose 2.22+:
|
|
docker compose -f docker-compose.dev.yml watch
|
|
```
|
|
|
|
PostgreSQL binds only to loopback by default. Change `POSTGRES_DEV_PORT` or `DEVRUNBOOK_DEV_PORT` when those ports are occupied. Compose Watch synchronizes source while keeping installed container dependencies intact and rebuilds after a lockfile change.
|
|
|
|
## Unraid mapping
|
|
|
|
Create one stack with the three persistent volumes mapped to Unraid application data paths:
|
|
|
|
| Container path | Suggested host path | Purpose |
|
|
| --- | --- | --- |
|
|
| `/var/lib/postgresql/data` | `/mnt/user/appdata/devrunbook/postgres` | PostgreSQL data |
|
|
| `/operator-content` | `/mnt/user/appdata/devrunbook/content` | Operator-managed playbook packages |
|
|
| `/artifacts` | `/mnt/user/appdata/devrunbook/artifacts` | Generated artifacts |
|
|
|
|
Expose container port `3000` through the normal bridge network and configure the reverse proxy to the selected host port. Do not publish PostgreSQL. Do not mount over `/content`; doing so would hide the baked 28-package catalog. Map operator-managed packages to `/operator-content` instead. Set the WebUI URL to the configured `PUBLIC_BASE_URL`. The container health state comes from `/health/live`; readiness remains available at `/health/ready`.
|
|
|
|
## Upgrades, backup, and restore
|
|
|
|
Before an upgrade, stop write traffic, record the current image digest, create a PostgreSQL logical dump, and back up `operator-content` plus `artifacts`. Back up encryption keys separately in a secret store; losing an encryption key makes encrypted integration credentials unrecoverable. Pull/build the new pinned image, run migration status/preflight when implemented, run the one-shot migration service, and then start worker and web. Retain the prior application image until smoke checks pass. Database rollback is migration-specific and is not yet evidenced.
|
|
|
|
The Milestone 0 rehearsal restored a logical dump and artifact archive into empty isolated volumes, confirmed the catalog and historical run, and compared the artifact digest. A final release rehearsal must additionally include any integration-secret key versions and operator content that exist by that milestone.
|
|
|
|
## CI contract
|
|
|
|
`.github/workflows/ci.yml` uses Node `24.18.0` and pnpm `10.33.0`. It runs the root `pnpm verify` aggregate, PostgreSQL-backed migration/integration/security gates, and the canonical Playwright browser command. CI credentials are fixed, isolated test-only values. Browser diagnostics upload only after failure and are retained for seven days. Third-party actions are pinned to commit SHAs resolved from their official `v4` release branches on 2026-07-27.
|
|
|
|
No CI run is claimed by this document. Release evidence must still record the action SHAs actually executed and review any automated dependency-update proposal before merging it.
|
|
|
|
## Remaining release evidence
|
|
|
|
- Build and exercise final release images for every supported architecture; Milestone 0 proved `linux/amd64` only.
|
|
- Rehearse the final upgrade with migration-specific rollback analysis.
|
|
- Scan final images for vulnerabilities, secrets, licenses, and unexpected files.
|
|
- Record final application image digests and measured startup/resource behavior.
|