Merge pull request 'deploy: split build into docker-compose.dev.yml (prod compose pulls only)' (#55) from deploy/compose-dev-prod-split into main
All checks were successful
Build container images / build (push) Successful in 1m1s

Reviewed-on: UOM/website#55
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
This commit is contained in:
2026-07-11 23:45:41 +00:00
3 changed files with 45 additions and 23 deletions

View File

@@ -92,8 +92,10 @@ UOMSITE/
### Option A — Docker Compose (full stack)
The simplest way to run everything. The image installs server deps, **builds the React client**,
and Express serves it; MariaDB runs in its own container; tables + defaults + the first admin are
`docker-compose.yml` is **production-shaped**: it *pulls* the prebuilt `app` and `bot` images from
the Gitea container registry (published by `.gitea/workflows/build-images.yml` on every merge to
`main`) — it never builds. Each image already bundles the server deps and the built React client,
which Express serves. MariaDB runs in its own container; tables + defaults + the first admin are
created automatically on first boot.
```bash
@@ -103,7 +105,9 @@ cp .env.example .env
# JWT_SECRET (a long random string)
# ADMIN_USERNAME, ADMIN_PASSWORD (your first admin login)
docker compose up -d --build
docker compose pull && docker compose up -d # IMAGE_TAG defaults to `latest`
# pin a specific build (reproducible deploy / rollback):
IMAGE_TAG=sha-042a151 docker compose pull && docker compose up -d
```
- App: **http://localhost:3000** (binds `0.0.0.0`)
@@ -111,19 +115,15 @@ docker compose up -d --build
- Logs: `docker compose logs -f app` (and `./logs/app.log` on the host)
- Stop: `docker compose down` (add `-v` to also wipe the database + uploads volumes)
**Deploy prebuilt images (no local build).** Every merge to `main` publishes the
`app` and `bot` images to the Gitea container registry
(`.gitea/workflows/build-images.yml`), so on the server you can pull instead of
building:
**Build the images locally instead of pulling** (offline, or to test an unmerged change) — overlay
the dev file, which adds `build:` back:
```bash
docker compose pull && docker compose up -d # IMAGE_TAG defaults to `latest`
# pin a specific build (reproducible deploy / rollback):
IMAGE_TAG=sha-042a151 docker compose pull && docker compose up -d
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
```
`build:` is kept in `docker-compose.yml`, so `docker compose up -d --build` still
works if you'd rather build locally.
Keeping `build:` out of the base file means a production host can only ever pull — it can never
accidentally build.
### Option B — Local development (hot reload)

24
docker-compose.dev.yml Normal file
View File

@@ -0,0 +1,24 @@
# Development overlay — build the app + bot images locally instead of pulling the
# prebuilt ones from the Gitea registry.
#
# The base docker-compose.yml is production-shaped (image: only, no build:), so a
# production host can never accidentally build — it only pulls. Use this overlay
# EXPLICITLY for local work (it is not auto-loaded like docker-compose.override.yml
# would be):
#
# docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
#
# Production stays:
#
# docker compose pull && docker compose up -d
#
# The `image:` tags inherited from the base file double as the local build tags,
# so a built image and a pulled one are interchangeable.
services:
app:
build: .
bot:
build:
context: .
dockerfile: bot/Dockerfile

View File

@@ -21,14 +21,14 @@ services:
# - "3306:3306"
app:
# Pull the prebuilt image from the Gitea registry (published by
# .gitea/workflows/build-images.yml on every merge to main). `build:` is kept
# so a local `docker compose build`/`up --build` still works; on the server,
# `docker compose pull && up -d` uses the registry image and never builds.
# IMAGE_TAG defaults to `latest`; pin a specific build for reproducible
# deploys / rollback, e.g. IMAGE_TAG=sha-042a151 (see .env / .env.example).
# Prebuilt image from the Gitea registry (published by
# .gitea/workflows/build-images.yml on every merge to main). This file is
# production-shaped — image only, NO build: — so a production host can only
# ever pull, never accidentally build. IMAGE_TAG defaults to `latest`; pin a
# specific build for a reproducible deploy / rollback, e.g.
# IMAGE_TAG=sha-042a151 (see .env / .env.example). To build locally instead,
# overlay docker-compose.dev.yml (see README).
image: gitea.whitlocktech.com/uom/website-app:${IMAGE_TAG:-latest}
build: .
restart: unless-stopped
env_file: .env
environment:
@@ -51,11 +51,9 @@ services:
- "3000:3000"
bot:
# Same as app: pull the prebuilt bot image; IMAGE_TAG pins the build.
# Same as app: prebuilt bot image, pulled in production. Build locally via
# docker-compose.dev.yml.
image: gitea.whitlocktech.com/uom/website-bot:${IMAGE_TAG:-latest}
build:
context: .
dockerfile: bot/Dockerfile
restart: unless-stopped
env_file: .env
environment: