Ctrl K
ComunidadGuías…

docker-compose-combined.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# =============================================================================
# docker-compose-combined.yml - every topology in one stack.
#
# Demonstrates all three PDNS deployment shapes side-by-side so the admin
# UI shows them grouped under their backends + cluster:
#
#   1. Multi-primary cluster   - 3 peers sharing one MariaDB backend.
#   2. Standalone primary      - single PDNS, its own gsqlite3 store.
#   3. Primary + 3 Secondaries - classic AXFR replication, supermaster
#                                auto-secondary wiring.
#
# Plus 10 demo zones × 10 records each per topology = 30 zones / 300
# records seeded by the app's provisioning step (`demo_zones:` section in
# provisioning.combined.example.yaml).
#
# Network: shared `pdnsnet` /24 so the primary's `also-notify` + each
# secondary's `supermasters` row can use literal IPs. Cluster peers and
# the standalone don't need static IPs.
#
# Usage:
#   cp .env.example .env
#   # fill in APP_SECRET_KEY + APP_ENCRYPTION_KEY
#   docker compose -f docker-compose-combined.yml up -d
#   # app                       → http://localhost:3000
#   # cluster peer APIs         → http://localhost:8091, :8092, :8093
#   # standalone primary API    → http://localhost:8095
#   # primary+sec primary API   → http://localhost:8081
#   # primary+sec secondary APIs→ http://localhost:8082, :8083, :8084
# =============================================================================

networks:
  pdnsnet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.0.0/24
          # Dynamic addresses come only from the upper half. The primary and
          # secondaries pin .10-.13 (their IPs are baked into ALLOW-AXFR /
          # also-notify), and with two dozen containers dynamic allocation
          # from .2 upwards reached them first: an intermittent "Address
          # already in use" at start-up, depending on container order.
          ip_range: 172.30.0.128/25

name: powerdns-authadmin-combined

services:
  # ===========================================================================
  # App-side: Postgres + Redis + the Next.js app
  # ===========================================================================
  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

  # ===========================================================================
  # Topology 1: Multi-primary cluster (3 peers + shared MariaDB)
  # ===========================================================================
  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

  pdns-peer-1:
    image: ${PDNS_AUTH_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:
      test: ["CMD", "pdns_control", "rping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  pdns-peer-2:
    image: ${PDNS_AUTH_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: ${PDNS_AUTH_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

  # ===========================================================================
  # Topology 2: Standalone primary (single PDNS, no replication)
  # ===========================================================================
  pdns-single-init:
    image: alpine:3.20
    restart: "no"
    command:
      - sh
      - -c
      - |
        set -eu
        apk add --no-cache sqlite >/dev/null
        sh /init.sh
        chown -R 953:953 /var/lib/powerdns
        chmod -R u+rwX /var/lib/powerdns
    environment:
      DB: /var/lib/powerdns/pdns.sqlite
      SCHEMA: /schema.sqlite3.sql
    volumes:
      - single-data:/var/lib/powerdns
      - ./docker/pdns/init-primary.sh:/init.sh:ro
      - ./docker/pdns/schema.sqlite3.sql:/schema.sqlite3.sql:ro
    networks:
      - pdnsnet

  pdns-single:
    image: ${PDNS_AUTH_IMAGE:-powerdns/pdns-auth-49:latest}
    restart: unless-stopped
    depends_on:
      pdns-single-init:
        condition: service_completed_successfully
    ports:
      - "5310:53"
      - "5310:53/udp"
      - "8095:8081"
    networks:
      - pdnsnet
    volumes:
      - single-data:/var/lib/powerdns
      - ./docker/pdns/single.conf:/etc/powerdns/pdns.conf:ro
    command: ["--api-key=single-changeme"]
    healthcheck:
      test: ["CMD", "pdns_control", "rping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  # ===========================================================================
  # Topology 3: Primary + 3 Secondaries (NOTIFY + AXFR replication)
  # ===========================================================================
  pdns-ps-primary-init:
    image: alpine:3.20
    restart: "no"
    command:
      - sh
      - -c
      - |
        set -eu
        apk add --no-cache sqlite >/dev/null
        sh /init.sh
        chown -R 953:953 /var/lib/powerdns
        chmod -R u+rwX /var/lib/powerdns
    environment:
      DB: /var/lib/powerdns/pdns.sqlite
      SCHEMA: /schema.sqlite3.sql
    volumes:
      - ps-primary-data:/var/lib/powerdns
      - ./docker/pdns/init-primary.sh:/init.sh:ro
      - ./docker/pdns/schema.sqlite3.sql:/schema.sqlite3.sql:ro
    networks:
      - pdnsnet

  pdns-ps-primary:
    image: ${PDNS_AUTH_IMAGE:-powerdns/pdns-auth-49:latest}
    restart: unless-stopped
    depends_on:
      pdns-ps-primary-init:
        condition: service_completed_successfully
    ports:
      - "5300:53"
      - "5300:53/udp"
      - "8081:8081"
    networks:
      pdnsnet:
        ipv4_address: 172.30.0.10
    volumes:
      - ps-primary-data:/var/lib/powerdns
      - ./docker/pdns/primary.conf:/etc/powerdns/pdns.conf:ro
    command: ["--api-key=ps-primary-changeme"]
    healthcheck:
      test: ["CMD", "pdns_control", "rping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  pdns-ps-secondary-1-init:
    image: alpine:3.20
    restart: "no"
    command:
      - sh
      - -c
      - |
        set -eu
        apk add --no-cache sqlite >/dev/null
        sh /init.sh
        chown -R 953:953 /var/lib/powerdns
        chmod -R u+rwX /var/lib/powerdns
    environment:
      DB: /var/lib/powerdns/pdns.sqlite
      SCHEMA: /schema.sqlite3.sql
      PRIMARY_IPS: "172.30.0.10"
      # PDNS auto-secondary verifies the supermasters row's `nameserver`
      # column against the NS records the Primary advertises for the
      # zone. Each Secondary registers itself under its own container
      # hostname so the verification doesn't reject the auto-create.
      SELF_NS: "pdns-ps-secondary-1"
    volumes:
      - ps-secondary-1-data:/var/lib/powerdns
      - ./docker/pdns/init-secondary.sh:/init.sh:ro
      - ./docker/pdns/schema.sqlite3.sql:/schema.sqlite3.sql:ro
    networks:
      - pdnsnet

  pdns-ps-secondary-1:
    image: ${PDNS_AUTH_IMAGE:-powerdns/pdns-auth-49:latest}
    restart: unless-stopped
    depends_on:
      pdns-ps-secondary-1-init:
        condition: service_completed_successfully
    ports:
      - "5301:53"
      - "5301:53/udp"
      - "8082:8081"
    networks:
      pdnsnet:
        ipv4_address: 172.30.0.11
    volumes:
      - ps-secondary-1-data:/var/lib/powerdns
      - ./docker/pdns/secondary.conf:/etc/powerdns/pdns.conf:ro
    command: ["--api-key=ps-secondary-1-changeme"]
    healthcheck:
      test: ["CMD", "pdns_control", "rping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  pdns-ps-secondary-2-init:
    image: alpine:3.20
    restart: "no"
    command:
      - sh
      - -c
      - |
        set -eu
        apk add --no-cache sqlite >/dev/null
        sh /init.sh
        chown -R 953:953 /var/lib/powerdns
        chmod -R u+rwX /var/lib/powerdns
    environment:
      DB: /var/lib/powerdns/pdns.sqlite
      SCHEMA: /schema.sqlite3.sql
      PRIMARY_IPS: "172.30.0.10"
      SELF_NS: "pdns-ps-secondary-2"
    volumes:
      - ps-secondary-2-data:/var/lib/powerdns
      - ./docker/pdns/init-secondary.sh:/init.sh:ro
      - ./docker/pdns/schema.sqlite3.sql:/schema.sqlite3.sql:ro
    networks:
      - pdnsnet

  pdns-ps-secondary-2:
    image: ${PDNS_AUTH_IMAGE:-powerdns/pdns-auth-49:latest}
    restart: unless-stopped
    depends_on:
      pdns-ps-secondary-2-init:
        condition: service_completed_successfully
    ports:
      - "5302:53"
      - "5302:53/udp"
      - "8083:8081"
    networks:
      pdnsnet:
        ipv4_address: 172.30.0.12
    volumes:
      - ps-secondary-2-data:/var/lib/powerdns
      - ./docker/pdns/secondary.conf:/etc/powerdns/pdns.conf:ro
    command: ["--api-key=ps-secondary-2-changeme"]
    healthcheck:
      test: ["CMD", "pdns_control", "rping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  pdns-ps-secondary-3-init:
    image: alpine:3.20
    restart: "no"
    command:
      - sh
      - -c
      - |
        set -eu
        apk add --no-cache sqlite >/dev/null
        sh /init.sh
        chown -R 953:953 /var/lib/powerdns
        chmod -R u+rwX /var/lib/powerdns
    environment:
      DB: /var/lib/powerdns/pdns.sqlite
      SCHEMA: /schema.sqlite3.sql
      PRIMARY_IPS: "172.30.0.10"
      SELF_NS: "pdns-ps-secondary-3"
    volumes:
      - ps-secondary-3-data:/var/lib/powerdns
      - ./docker/pdns/init-secondary.sh:/init.sh:ro
      - ./docker/pdns/schema.sqlite3.sql:/schema.sqlite3.sql:ro
    networks:
      - pdnsnet

  pdns-ps-secondary-3:
    image: ${PDNS_AUTH_IMAGE:-powerdns/pdns-auth-49:latest}
    restart: unless-stopped
    depends_on:
      pdns-ps-secondary-3-init:
        condition: service_completed_successfully
    ports:
      - "5303:53"
      - "5303:53/udp"
      - "8084:8081"
    networks:
      pdnsnet:
        ipv4_address: 172.30.0.13
    volumes:
      - ps-secondary-3-data:/var/lib/powerdns
      - ./docker/pdns/secondary.conf:/etc/powerdns/pdns.conf:ro
    command: ["--api-key=ps-secondary-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
      pdns-single:
        condition: service_healthy
      pdns-ps-primary:
        condition: service_healthy
      pdns-ps-secondary-1:
        condition: service_healthy
      pdns-ps-secondary-2:
        condition: service_healthy
      pdns-ps-secondary-3:
        condition: service_healthy
    ports:
      - "3000:3000"
    networks:
      - pdnsnet
    volumes:
      - sqlite-data:/data
      - ./provisioning.combined.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}
      # Postgres-backed: the integration suite (host-side vitest) connects to
      # this same Postgres over the published 5432 to reset state, so the app
      # must use it (an in-container SQLite file isn't reachable from the host).
      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}
      # This is the public demo stack: lock the shared admin's login so a
      # visitor can't change the password/email/MFA or delete it out from under
      # everyone. Override BOOTSTRAP_ADMIN_RO=false for a private deployment.
      BOOTSTRAP_ADMIN_RO: ${BOOTSTRAP_ADMIN_RO:-true}
      LOCAL_AUTH_ENABLED: "true"
      APP_PDNS_ALLOW_PRIVATE_NETWORKS: "true"
      # Enable the background poller so the dashboard's PDNS-statistics tab
      # (per-backend query rate / latency / cache / response charts) renders -
      # it's hidden when polling is off. Also what the demo graph backfill
      # (scripts/demo-seed-graphs.ts) populates.
      PDNS_BACKGROUND_POLLING: ${PDNS_BACKGROUND_POLLING:-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}
      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:
  single-data:
  ps-primary-data:
  ps-secondary-1-data:
  ps-secondary-2-data:
  ps-secondary-3-data:
  sqlite-data: