The base compose file is the wilm/dev-be source build; stable and edge ship through the pull/airgap files. A raw source build is never a release, so default SHOPDB_ENV_LABEL to DEV here while leaving it overridable from .env.
127 lines
5.3 KiB
YAML
127 lines
5.3 KiB
YAML
# shopdb-flask single-site docker-compose template.
|
|
#
|
|
# Per ADR-004, each adopting facility runs its own stack. This template
|
|
# brings up MySQL + the API container and exposes the API on port 5001.
|
|
# The Vue frontend is served separately by the API in production builds
|
|
# (see register_frontend_routes in shopdb/__init__.py); for dev, run
|
|
# `npm run dev` in frontend/ on a separate port.
|
|
#
|
|
# Usage:
|
|
# cp .env.example .env
|
|
# # edit .env with site-specific secrets and origins
|
|
# docker compose up -d
|
|
#
|
|
# Refresh after pulling new code:
|
|
# docker compose build api
|
|
# docker compose up -d api
|
|
|
|
services:
|
|
db:
|
|
image: mysql:8.4
|
|
# utf8mb4 server-wide so the auto-created MYSQL_DATABASE is utf8mb4, not the
|
|
# image default. Keeps every site's schema on the same charset/collation.
|
|
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
|
|
# Bind MySQL to loopback only. The api container reaches db over the
|
|
# compose network regardless of this mapping; the published port is just
|
|
# for local admin tools (mysqldump, a client on the host). Exposing 3306
|
|
# on all interfaces would put the database on the facility network.
|
|
ports:
|
|
- "127.0.0.1:${MYSQL_PORT:-3306}:3306"
|
|
healthcheck:
|
|
# 127.0.0.1, not localhost: localhost means the unix socket, and the
|
|
# entrypoint's init pass answers on the socket while running the server
|
|
# with --skip-networking. A socket ping therefore reports healthy DURING
|
|
# init, and the api/migrate services start against a server that is about
|
|
# to restart. Over TCP the probe stays red until the real server listens.
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
api:
|
|
build: .
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
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}
|
|
ZABBIX_URL: ${ZABBIX_URL:-}
|
|
ZABBIX_TOKEN: ${ZABBIX_TOKEN:-}
|
|
COLLECTOR_API_KEY: ${COLLECTOR_API_KEY:-}
|
|
COLLECTOR_API_KEY_ENDPOINTS: ${COLLECTOR_API_KEY_ENDPOINTS:-}
|
|
# This file is the source-build dev stack (wilm/dev-be); stable and edge
|
|
# ship through the pull/airgap compose files, not this one. So default the
|
|
# badge label to DEV here - a raw source build is by definition not a
|
|
# release - while still allowing an override from .env.
|
|
SHOPDB_ENV_LABEL: ${SHOPDB_ENV_LABEL:-DEV}
|
|
ports:
|
|
- "${API_PORT:-5001}:5001"
|
|
# Terminate TLS in gunicorn with the mounted self-signed cert so the browser
|
|
# sees a secure context. navigator.clipboard and other secure-context-only
|
|
# web APIs refuse to run over plain http on a non-localhost origin, so the
|
|
# test box (accessed by FQDN) needs real https. A site swaps in its own cert
|
|
# under ./certs or fronts this with its IIS/nginx proxy.
|
|
command:
|
|
- gunicorn
|
|
- --bind
|
|
- 0.0.0.0:5001
|
|
- --workers
|
|
- "4"
|
|
- --timeout
|
|
- "60"
|
|
- --access-logfile
|
|
- "-"
|
|
- --error-logfile
|
|
- "-"
|
|
- --certfile
|
|
- /app/certs/server.crt
|
|
- --keyfile
|
|
- /app/certs/server.key
|
|
- wsgi:app
|
|
healthcheck:
|
|
# Match the TLS listener: probe over https and accept the self-signed cert
|
|
# (-k). The Dockerfile default probes http and would stay red once gunicorn
|
|
# only speaks TLS.
|
|
test: ["CMD", "curl", "--silent", "--insecure", "https://localhost:5001/api/auth/login",
|
|
"-X", "POST", "-H", "Content-Type: application/json", "-d", "{}"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
start_period: 10s
|
|
retries: 3
|
|
volumes:
|
|
- ./plugins:/app/plugins:ro
|
|
# Standalone operator scripts shipped inside generated bundles (the
|
|
# endpoint-agent uninstaller). Read-only, same pattern as plugins: the
|
|
# site-agent packaging route reads uninstall-shopdbagent.ps1 from here at
|
|
# download time, so it must be visible in the container.
|
|
- ./scripts:/app/scripts:ro
|
|
# Self-signed TLS material for the dev/test https listener. Read-only;
|
|
# generated on the host under ./certs and never baked into the image.
|
|
- ./certs:/app/certs:ro
|
|
# /app/instance is WRITTEN state, not code: plugins.json (which plugins
|
|
# this site has enabled), uploaded floor plans, branding, model and
|
|
# application images, employee photos, warranty proofs, slides,
|
|
# printed-part files, and the Dell OAuth token. Without this volume a
|
|
# `docker compose build api && up -d api` recreates the container and
|
|
# takes all of it with it, so the site comes back with its plugins
|
|
# disabled and MySQL rows pointing at files that no longer exist.
|
|
- instance_data:/app/instance
|
|
|
|
volumes:
|
|
db_data:
|
|
instance_data:
|