Pilots behind the inspecting proxy cannot reliably build the frontend from source; npm's many small fetches get reset mid-install. Build the image once in CI on the clean runners and have pilots pull the finished channel image. One resumable image pull survives the proxy where hundreds of npm requests do not, and a pilot now needs only Docker.
93 lines
3.2 KiB
YAML
93 lines
3.2 KiB
YAML
# shopdb-flask PULL stack for dev workstations (stable / edge channels).
|
|
#
|
|
# WHY this exists: pilots behind an inspecting proxy cannot reliably BUILD the
|
|
# image from source (npm's many small fetches get reset mid-install). Instead
|
|
# CI (.github/workflows/publish-images.yml) builds the image on clean runners
|
|
# and publishes it to GHCR; this file just PULLS and RUNS it. One resumable
|
|
# image pull survives the proxy where hundreds of npm requests do not.
|
|
#
|
|
# Nothing is built here (no `build:`), mirroring docker-compose.airgap.yml:
|
|
# - api/migrate use `image:` (pulled from GHCR), never `build: .`.
|
|
# - NO ./plugins bind mount; the image carries every plugin baked in.
|
|
# - a one-shot `migrate` runs db upgrade + plugin upgrade-all + seed before
|
|
# api starts, so `up -d` alone brings up a working site.
|
|
#
|
|
# Driven by scripts/dev-bootstrap.ps1, which sets SHOPDB_IMAGE (the channel
|
|
# image ref), SHOPDB_ENV_LABEL, API_PORT and MYSQL_PORT per channel and picks a
|
|
# compose project name (-p shopdb-stable / -p shopdb-edge) so the two channels
|
|
# run side by side without colliding.
|
|
|
|
x-app-env: &app-env
|
|
FLASK_APP: wsgi.py
|
|
FLASK_ENV: production
|
|
DATABASE_URL: mysql+pymysql://shopdb:${MYSQL_PASSWORD}@db:3306/shopdb_flask?charset=utf8mb4
|
|
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY must be set}
|
|
JWT_SECRET_KEY: ${JWT_SECRET_KEY:?JWT_SECRET_KEY must be set}
|
|
CORS_ORIGINS: ${CORS_ORIGINS:?CORS_ORIGINS must be set}
|
|
LOG_LEVEL: ${LOG_LEVEL:-INFO}
|
|
# Empty on stable; 'DEV' on edge, which lights the sidebar badge.
|
|
SHOPDB_ENV_LABEL: ${SHOPDB_ENV_LABEL:-}
|
|
|
|
services:
|
|
db:
|
|
image: mysql:8.4
|
|
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
|
restart: unless-stopped
|
|
environment:
|
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD must be set}
|
|
MYSQL_DATABASE: shopdb_flask
|
|
MYSQL_USER: shopdb
|
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?MYSQL_PASSWORD must be set}
|
|
volumes:
|
|
- db_data:/var/lib/mysql
|
|
ports:
|
|
- "127.0.0.1:${MYSQL_PORT:-3306}:3306"
|
|
healthcheck:
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
# One-shot schema + seed. Runs to completion and exits; api waits for it.
|
|
# Every step is idempotent, so it is safe to run on every `up`.
|
|
migrate:
|
|
image: ${SHOPDB_IMAGE:?SHOPDB_IMAGE must be set to the channel image ref}
|
|
pull_policy: always
|
|
restart: "no"
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
<<: *app-env
|
|
command:
|
|
- sh
|
|
- -c
|
|
- >
|
|
flask db upgrade &&
|
|
flask plugin upgrade-all &&
|
|
flask seed permissions &&
|
|
flask seed settings &&
|
|
flask seed reference-data
|
|
volumes:
|
|
- instance_data:/app/instance
|
|
|
|
api:
|
|
image: ${SHOPDB_IMAGE:?SHOPDB_IMAGE must be set to the channel image ref}
|
|
pull_policy: always
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
migrate:
|
|
condition: service_completed_successfully
|
|
environment:
|
|
<<: *app-env
|
|
ports:
|
|
- "${API_PORT:-5001}:5001"
|
|
volumes:
|
|
- instance_data:/app/instance
|
|
|
|
volumes:
|
|
db_data:
|
|
instance_data:
|