docker-compose-multi-primary.yml
Rama main · réplica de lectura del repositorio original.
# =============================================================================
# docker-compose-multi-primary.yml - full demo stack with a 3-peer
# multi-primary PowerDNS cluster.
#
# Topology:
# * One MariaDB container hosts the gmysql backend tables (the PDNS
# schema is dropped into /docker-entrypoint-initdb.d so it runs once
# on first boot).
# * Three PDNS containers all point at the SAME MariaDB - they're
# equivalent peers. A write via any peer's HTTP API is visible to the
# other peers' APIs on the next read (no replication lag because the
# backend is shared).
# * The app provisions a `pdns_clusters` row + three peer servers
# belonging to it. Operators see the cluster in /admin/pdns-clusters
# and writes routed to `?cluster=<slug>` are dispatched via the
# cluster's write strategy (round_robin / lowest_latency / random /
# least_load).
#
# For real production use, swap the single shared MariaDB for a replicated
# topology (Galera, MariaDB Cluster, Postgres logical replication, etc.).
# The app's expected-serial source-of-truth machinery is what masks the
# brief convergence gap in that case; in this demo, the gap is zero.
#
# Usage:
# cp .env.example .env
# # fill in APP_SECRET_KEY + APP_ENCRYPTION_KEY
# docker compose -f docker-compose-multi-primary.yml up -d
# # app → http://localhost:3000
# # peer-1 API → http://localhost:8091 (X-API-Key: peer-1-changeme)
# # peer-2 API → http://localhost:8092 (X-API-Key: peer-2-changeme)
# # peer-3 API → http://localhost:8093 (X-API-Key: peer-3-changeme)
# =============================================================================
networks:
pdnsnet:
driver: bridge
name: powerdns-authadmin-multi-primary
services:
# ---- Shared MariaDB backend ------------------------------------------
mariadb:
image: mariadb:11
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: pdns-root-pw
MARIADB_DATABASE: pdns
MARIADB_USER: pdns
MARIADB_PASSWORD: pdns-pw
volumes:
- mariadb-data:/var/lib/mysql
- ./docker/pdns/schema.mysql.sql:/docker-entrypoint-initdb.d/01-pdns-schema.sql:ro
networks:
- pdnsnet
healthcheck:
# Over TCP, not the socket: on first boot the image runs a socket-only
# temporary server while it loads the schema, and a socket check passes
# against it before PowerDNS can connect over the network.
test: ["CMD-SHELL", "mariadb -h 127.0.0.1 -updns -ppdns-pw -e 'SELECT 1' pdns"]
interval: 5s
timeout: 5s
retries: 20
# ---- App-side infrastructure -----------------------------------------
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: pdns
POSTGRES_PASSWORD: pdns
POSTGRES_DB: powerdns_authadmin
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- pdnsnet
healthcheck:
test: ["CMD-SHELL", "pg_isready -U pdns -d powerdns_authadmin"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- pdnsnet
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
# ---- PDNS peers (×3) -------------------------------------------------
pdns-peer-1:
image: powerdns/pdns-auth-49:latest
restart: unless-stopped
depends_on:
mariadb:
condition: service_healthy
ports:
- "8091:8081"
networks:
- pdnsnet
volumes:
- ./docker/pdns/peer.conf:/etc/powerdns/pdns.conf:ro
command: ["--api-key=peer-1-changeme"]
healthcheck:
# `pdns_control rping` returns success once pdns_server is running.
# Doesn't depend on the HTTP API being up or the API key being right,
# so it's the simplest reliable liveness signal.
test: ["CMD", "pdns_control", "rping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
pdns-peer-2:
image: powerdns/pdns-auth-49:latest
restart: unless-stopped
depends_on:
mariadb:
condition: service_healthy
ports:
- "8092:8081"
networks:
- pdnsnet
volumes:
- ./docker/pdns/peer.conf:/etc/powerdns/pdns.conf:ro
command: ["--api-key=peer-2-changeme"]
healthcheck:
test: ["CMD", "pdns_control", "rping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
pdns-peer-3:
image: powerdns/pdns-auth-49:latest
restart: unless-stopped
depends_on:
mariadb:
condition: service_healthy
ports:
- "8093:8081"
networks:
- pdnsnet
volumes:
- ./docker/pdns/peer.conf:/etc/powerdns/pdns.conf:ro
command: ["--api-key=peer-3-changeme"]
healthcheck:
test: ["CMD", "pdns_control", "rping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
# ---- The app ---------------------------------------------------------
app:
build:
context: .
dockerfile: Dockerfile
target: runner
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
pdns-peer-1:
condition: service_healthy
pdns-peer-2:
condition: service_healthy
pdns-peer-3:
condition: service_healthy
ports:
- "3000:3000"
networks:
- pdnsnet
volumes:
- ./provisioning.multi-primary.example.yaml:/etc/powerdns-authadmin/provisioning.yaml:ro
environment:
NODE_ENV: ${NODE_ENV:-production}
PORT: 3000
APP_URL: ${APP_URL:-http://localhost:3000}
LOG_LEVEL: ${LOG_LEVEL:-info}
DATABASE_URL: postgres://pdns:pdns@postgres:5432/powerdns_authadmin
REDIS_URL: redis://redis:6379
APP_SECRET_KEY: ${APP_SECRET_KEY:?must be set; generate with openssl rand -base64 32}
APP_ENCRYPTION_KEY: ${APP_ENCRYPTION_KEY:?must be set; generate with openssl rand -base64 32}
BOOTSTRAP_ADMIN_EMAIL: ${BOOTSTRAP_ADMIN_EMAIL:-admin@example.com}
BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:-bootstrap-admin-pw-changeme}
LOCAL_AUTH_ENABLED: "true"
APP_PDNS_ALLOW_PRIVATE_NETWORKS: "true"
MIGRATE_ON_BOOT: ${MIGRATE_ON_BOOT:-true}
SEED_ON_BOOT: ${SEED_ON_BOOT:-true}
PROVISIONING_FILE: /etc/powerdns-authadmin/provisioning.yaml
PROVISION_ON_BOOT: ${PROVISION_ON_BOOT:-true}
# Demo peers expose only http:// - explicit opt-out of the
# https-in-production scheme check. APP_PDNS_ALLOW_PRIVATE_NETWORKS
# above still governs the IP-range guard.
APP_PDNS_ALLOW_INSECURE_HTTP: ${APP_PDNS_ALLOW_INSECURE_HTTP:-true}
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://localhost:3000/healthz').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))",
]
interval: 15s
timeout: 5s
retries: 5
start_period: 30s
volumes:
postgres-data:
redis-data:
mariadb-data: