Merge remote-tracking branch 'origin/wilm' into wj
This commit is contained in:
12
Dockerfile
12
Dockerfile
@@ -17,6 +17,13 @@
|
||||
# docker build -t shopdb-flask .
|
||||
# Run (with .env):
|
||||
# docker run --env-file .env -p 5001:5001 shopdb-flask
|
||||
#
|
||||
# Note: this image does not migrate its own database on start. A plain
|
||||
# `docker run` expects the schema to already be current; run the same sequence
|
||||
# the compose `migrate` service does first:
|
||||
# flask db upgrade && ./scripts/bootstrap-plugins.sh && flask plugin upgrade-all
|
||||
# && flask seed permissions && flask seed settings && flask seed reference-data
|
||||
# The supported path is `docker compose up`, which runs that for you.
|
||||
|
||||
# ---- Stage 1: build the Vue frontend ----
|
||||
FROM node:20-slim AS frontendbuild
|
||||
@@ -142,7 +149,10 @@ USER shopdb
|
||||
|
||||
EXPOSE 5001
|
||||
|
||||
# Entrypoint runs migrations and bootstraps plugins on first deployment
|
||||
# Entrypoint waits for the database, then execs the CMD. Migrations, plugin
|
||||
# bootstrap and seeds are NOT run here - they belong to the `migrate` service
|
||||
# in the compose files so they happen exactly once per deployment rather than
|
||||
# on every container restart.
|
||||
ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"]
|
||||
|
||||
# Probe the public health route, not the login endpoint. Probing POST
|
||||
|
||||
@@ -46,12 +46,67 @@ services:
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Schema, plugin bootstrap and seed data all happen here, not in the api
|
||||
# container. One place, one ordering, and a failure stops the rollout instead
|
||||
# of being retried forever: restart "no" means a bad migration exits once and
|
||||
# leaves the error as the last thing in the log. The api service below will
|
||||
# not start at all until this exits 0, so `up -d api` still migrates first -
|
||||
# compose honours service_completed_successfully even when a single service
|
||||
# is named on the command line.
|
||||
migrate:
|
||||
build: .
|
||||
restart: "no"
|
||||
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}
|
||||
# Required even though this service never serves a request: create_app()
|
||||
# runs config validation before any CLI command dispatches, and the
|
||||
# production config refuses to build without an explicit CORS allowlist.
|
||||
CORS_ORIGINS: ${CORS_ORIGINS:?CORS_ORIGINS must be set}
|
||||
LOG_LEVEL: ${LOG_LEVEL:-INFO}
|
||||
# Chained with && so the first failure stops the rest. Ordering is
|
||||
# load-bearing: plugin tables cannot be created before the plugins are
|
||||
# installed, and seedscopes only links permissions that already exist as
|
||||
# rows, so the seeds run last.
|
||||
#
|
||||
# The seeds are all create-if-missing (see shopdb/cli/__init__.py), so
|
||||
# running them on every start is a no-op once the site is current. They run
|
||||
# here rather than only on first deploy because a patch that adds a
|
||||
# permission or a default setting has to reach an existing site on the
|
||||
# upgrade it already performs - that is the whole point of this service.
|
||||
# No entrypoint override: the image entrypoint now only waits for the
|
||||
# database and execs, which is exactly the preamble this service wants.
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- >
|
||||
flask db upgrade &&
|
||||
/app/scripts/bootstrap-plugins.sh &&
|
||||
flask plugin upgrade-all &&
|
||||
flask seed permissions &&
|
||||
flask seed settings &&
|
||||
flask seed reference-data
|
||||
volumes:
|
||||
- ./plugins:/app/plugins:ro
|
||||
- ./scripts:/app/scripts:ro
|
||||
# plugins.json is written here by bootstrap-plugins.sh, so this service
|
||||
# needs the same instance volume the api uses. They never run at the same
|
||||
# time, so the shared mount is not contended.
|
||||
- instance_data:/app/instance
|
||||
|
||||
api:
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
FLASK_ENV: production
|
||||
DATABASE_URL: mysql+pymysql://shopdb:${MYSQL_PASSWORD}@db:3306/shopdb_flask?charset=utf8mb4
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
#!/bin/bash
|
||||
# Docker container entrypoint for ShopDB Flask.
|
||||
# Runs migrations, bootstraps plugins on first deployment, then starts the app.
|
||||
# Waits for the database to answer, then starts whatever it was given.
|
||||
#
|
||||
# This deliberately does NOT run migrations, plugin bootstrap or seeds. That
|
||||
# sequence lives in the `migrate` service in docker-compose.yml (and its
|
||||
# equivalents in the pull/airgap compose files) so there is exactly one place
|
||||
# it happens. Running it here as well would mean every api restart re-attempted
|
||||
# schema work, and a failing migration under `restart: unless-stopped` would
|
||||
# crash-loop and bury the original error under retry noise.
|
||||
#
|
||||
# `up -d api` is still safe on its own: compose honours the
|
||||
# service_completed_successfully dependency even when a single service is
|
||||
# named, so the migrate service runs to completion first.
|
||||
|
||||
set -e
|
||||
|
||||
echo "==> ShopDB Flask Container Starting"
|
||||
|
||||
# Wait for database to be ready (optional, useful with docker-compose)
|
||||
# Wait for database to be ready. Kept here because it is about this container's
|
||||
# own readiness to serve, not about schema state. `flask db current` is a cheap
|
||||
# round-trip that proves the connection works.
|
||||
if [ -n "$DATABASE_URL" ]; then
|
||||
echo "==> Waiting for database..."
|
||||
for i in {1..30}; do
|
||||
@@ -19,23 +32,5 @@ if [ -n "$DATABASE_URL" ]; then
|
||||
done
|
||||
fi
|
||||
|
||||
# Run migrations
|
||||
echo "==> Running database migrations"
|
||||
flask db upgrade || {
|
||||
echo "ERROR: Database migrations failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Bootstrap plugins on first deployment
|
||||
echo "==> Checking plugin installation"
|
||||
/app/scripts/bootstrap-plugins.sh
|
||||
|
||||
# Run plugin migrations after bootstrap (creates tables for enabled plugins)
|
||||
# Safe to run even if no plugins are enabled - it will just do nothing
|
||||
echo "==> Running plugin migrations"
|
||||
flask plugin upgrade-all || {
|
||||
echo "WARNING: Plugin migrations failed - some features may not work"
|
||||
}
|
||||
|
||||
echo "==> Starting application"
|
||||
exec "$@"
|
||||
|
||||
Reference in New Issue
Block a user