3 changed files with 222 additions and 0 deletions
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
# Copy to .env.prod, fill in, then: set -a && source .env.prod && set +a |
||||
# Or use: export $(grep -v '^#' .env.prod | xargs) |
||||
|
||||
POSTGRES_HOST=postgres |
||||
POSTGRES_DB=gc_index_relay_prod |
||||
POSTGRES_USER=postgres |
||||
POSTGRES_PASSWORD=change-me |
||||
POSTGRES_RUNTIME_USER=gc_index_relay |
||||
POSTGRES_RUNTIME_PASSWORD=change-me-runtime |
||||
|
||||
SECRET_KEY_BASE=generate-with-mix-phx-gen-secret |
||||
PHX_HOST=gc-http-relay.imwald.eu |
||||
|
||||
# Optional: pin release image (default latest) |
||||
# TAG=0.2.0 |
||||
@ -0,0 +1,118 @@
@@ -0,0 +1,118 @@
|
||||
# Production stack: Apache (on the host) terminates TLS and proxies to 127.0.0.1:4000. |
||||
# |
||||
# Helper script: ./scripts/deploy_prod.sh --help |
||||
# |
||||
# --- Local: build and push --- |
||||
# cp .env.prod.example .env.prod && edit secrets |
||||
# export TAG=0.2.0 # optional; relay/migrator use :latest if unset |
||||
# docker login |
||||
# ./scripts/deploy_prod.sh build-push |
||||
# |
||||
# --- Remote: pull and run --- |
||||
# ./scripts/deploy_prod.sh deploy |
||||
# |
||||
# Images (repository: silberengel/gc-http-relay): |
||||
# :${TAG} — Phoenix release (relay + migrator) |
||||
# :setup — one-shot DB user bootstrap (tag is literal "setup") |
||||
|
||||
services: |
||||
postgres: |
||||
image: docker.io/apache/age:release_PG17_1.6.0 |
||||
restart: unless-stopped |
||||
user: 1000:1000 |
||||
volumes: |
||||
- pgdata:/var/lib/postgresql/data |
||||
environment: |
||||
POSTGRES_DB: ${POSTGRES_DB:?set POSTGRES_DB in .env.prod} |
||||
POSTGRES_USER: ${POSTGRES_USER:?set POSTGRES_USER in .env.prod} |
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env.prod} |
||||
command: > |
||||
postgres |
||||
healthcheck: |
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] |
||||
interval: 10s |
||||
timeout: 5s |
||||
retries: 5 |
||||
deploy: |
||||
resources: |
||||
limits: |
||||
cpus: "1.00" |
||||
memory: 1G |
||||
reservations: |
||||
cpus: "0.50" |
||||
memory: 512M |
||||
networks: |
||||
- internal |
||||
|
||||
setup: |
||||
image: docker.io/silberengel/gc-http-relay:setup |
||||
build: |
||||
context: . |
||||
dockerfile: ./docker/setup.Dockerfile |
||||
command: ["/usr/local/bin/usersetup.sh"] |
||||
restart: "no" |
||||
depends_on: |
||||
postgres: |
||||
condition: service_healthy |
||||
environment: |
||||
POSTGRES_HOST: ${POSTGRES_HOST:-postgres} |
||||
POSTGRES_USER: ${POSTGRES_USER:?set POSTGRES_USER in .env.prod} |
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env.prod} |
||||
POSTGRES_DB: ${POSTGRES_DB:?set POSTGRES_DB in .env.prod} |
||||
POSTGRES_RUNTIME_USER: ${POSTGRES_RUNTIME_USER:?set POSTGRES_RUNTIME_USER in .env.prod} |
||||
POSTGRES_RUNTIME_PASSWORD: ${POSTGRES_RUNTIME_PASSWORD:?set POSTGRES_RUNTIME_PASSWORD in .env.prod} |
||||
networks: |
||||
- internal |
||||
|
||||
migrator: |
||||
image: docker.io/silberengel/gc-http-relay:${TAG:-latest} |
||||
build: |
||||
context: . |
||||
dockerfile: ./docker/server.Dockerfile |
||||
command: ["/app/bin/migrate"] |
||||
restart: "no" |
||||
depends_on: |
||||
postgres: |
||||
condition: service_healthy |
||||
setup: |
||||
condition: service_completed_successfully |
||||
environment: |
||||
DATABASE_URL: "ecto://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST:-postgres}/${POSTGRES_DB}" |
||||
SECRET_KEY_BASE: ${SECRET_KEY_BASE:?set SECRET_KEY_BASE in .env.prod} |
||||
networks: |
||||
- internal |
||||
|
||||
relay: |
||||
image: docker.io/silberengel/gc-http-relay:${TAG:-latest} |
||||
build: |
||||
context: . |
||||
dockerfile: ./docker/server.Dockerfile |
||||
command: ["/app/bin/server"] |
||||
restart: unless-stopped |
||||
deploy: |
||||
resources: |
||||
limits: |
||||
cpus: "1.00" |
||||
memory: 1G |
||||
reservations: |
||||
cpus: "0.50" |
||||
memory: 512M |
||||
depends_on: |
||||
postgres: |
||||
condition: service_healthy |
||||
migrator: |
||||
condition: service_completed_successfully |
||||
ports: |
||||
- "127.0.0.1:4000:4000" |
||||
environment: |
||||
DATABASE_URL: "ecto://${POSTGRES_RUNTIME_USER}:${POSTGRES_RUNTIME_PASSWORD}@${POSTGRES_HOST:-postgres}/${POSTGRES_DB}" |
||||
SECRET_KEY_BASE: ${SECRET_KEY_BASE:?set SECRET_KEY_BASE in .env.prod} |
||||
PHX_HOST: ${PHX_HOST:?set PHX_HOST in .env.prod (public hostname, no scheme)} |
||||
networks: |
||||
- internal |
||||
|
||||
networks: |
||||
internal: |
||||
|
||||
volumes: |
||||
pgdata: |
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash |
||||
# Production Docker Compose helper — run ./scripts/deploy_prod.sh --help |
||||
|
||||
set -euo pipefail |
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
||||
cd "$ROOT" |
||||
|
||||
COMPOSE="${COMPOSE:-docker compose}" |
||||
COMPOSE_FILE="${COMPOSE_FILE:-compose.prod.yml}" |
||||
ENV_FILE="${ENV_FILE:-.env.prod}" |
||||
|
||||
APP_IMAGES=(setup relay migrator) |
||||
|
||||
usage() { |
||||
cat <<'EOF' |
||||
Production Docker Compose helper (compose.prod.yml). |
||||
|
||||
./scripts/deploy_prod.sh build build app images (setup, relay, migrator) |
||||
./scripts/deploy_prod.sh push push those images (run docker login first) |
||||
./scripts/deploy_prod.sh build-push build then push |
||||
./scripts/deploy_prod.sh pull pull images |
||||
./scripts/deploy_prod.sh up start stack (detached) |
||||
./scripts/deploy_prod.sh deploy pull then up -d (typical on server) |
||||
./scripts/deploy_prod.sh down stop stack |
||||
./scripts/deploy_prod.sh ps docker compose ps |
||||
./scripts/deploy_prod.sh logs [svc] follow logs (default: all services) |
||||
|
||||
Env: ENV_FILE (default .env.prod), COMPOSE_FILE, TAG, COMPOSE (default "docker compose") |
||||
EOF |
||||
exit "${1:-0}" |
||||
} |
||||
|
||||
require_env_file() { |
||||
if [[ ! -f "$ENV_FILE" ]]; then |
||||
echo "error: missing env file: $ENV_FILE" >&2 |
||||
echo " cp .env.prod.example .env.prod && edit, or set ENV_FILE=..." >&2 |
||||
exit 1 |
||||
fi |
||||
} |
||||
|
||||
compose() { |
||||
require_env_file |
||||
$COMPOSE --env-file "$ENV_FILE" -f "$COMPOSE_FILE" "$@" |
||||
} |
||||
|
||||
cmd="${1:-}" |
||||
[[ -z "$cmd" ]] && usage 1 |
||||
[[ "$cmd" == "-h" || "$cmd" == "--help" ]] && usage 0 |
||||
shift || true |
||||
|
||||
case "$cmd" in |
||||
help) |
||||
usage 0 |
||||
;; |
||||
build) |
||||
compose build "${APP_IMAGES[@]}" |
||||
;; |
||||
push) |
||||
compose push "${APP_IMAGES[@]}" |
||||
;; |
||||
build-push) |
||||
compose build "${APP_IMAGES[@]}" |
||||
compose push "${APP_IMAGES[@]}" |
||||
;; |
||||
pull) |
||||
compose pull |
||||
;; |
||||
up) |
||||
compose up -d |
||||
;; |
||||
deploy) |
||||
compose pull |
||||
compose up -d |
||||
;; |
||||
down) |
||||
compose down |
||||
;; |
||||
ps) |
||||
compose ps "$@" |
||||
;; |
||||
logs) |
||||
compose logs -f "$@" |
||||
;; |
||||
*) |
||||
echo "error: unknown command: $cmd" >&2 |
||||
usage 1 |
||||
;; |
||||
esac |
||||
Loading…
Reference in new issue