Docker Compose for Development: Local Infrastructure

Docker Compose for local development: PostgreSQL, Redis, Authentik, networking, health checks, volume management, and environment-specific configurations for TypeScript monorepos.

E
ECOSIRE Research and Development Team
|19 मार्च 202610 मिनट पढ़ें2.1k शब्द|

विकास के लिए डॉकर कंपोज़: स्थानीय अवसंरचना

एक सुखद ऑनबोर्डिंग अनुभव ("क्लोन और रन pnpm dev:infra") और एक दर्दनाक अनुभव ("पहले PostgreSQL सेट करें, फिर Redis कॉन्फ़िगर करें, फिर...") के बीच का अंतर इस बात पर निर्भर करता है कि आपका डॉकर कंपोज़ सेटअप आपकी बुनियादी ढांचे की आवश्यकताओं को कितनी अच्छी तरह से पकड़ता है। एक अच्छी तरह से तैयार किया गया docker-compose.dev.yml किसी भी मशीन पर किसी भी डेवलपर को मिनटों में बिल्कुल वही बुनियादी ढांचा चलाने की सुविधा देता है।

यह मार्गदर्शिका उत्पादन-गुणवत्ता वाले स्थानीय विकास स्टैक के पैटर्न को कवर करती है: सेवा कॉन्फ़िगरेशन, स्वास्थ्य जांच, नेटवर्किंग, वॉल्यूम प्रबंधन, और आपके एप्लिकेशन के स्टार्टअप अनुक्रम के साथ एकीकरण।

मुख्य बातें

  • सिस्टम इंस्टॉलेशन के साथ टकराव से बचने के लिए स्थानीय रूप से PostgreSQL (5433) के लिए एक गैर-डिफ़ॉल्ट पोर्ट का उपयोग करें
  • सेवा निर्भरता पर स्वास्थ्य जांच "कनेक्शन अस्वीकृत" स्टार्टअप त्रुटियों को रोकती है
  • नामित वॉल्यूम कंटेनर पुनरारंभ के बीच डेटाबेस डेटा को बनाए रखते हैं - बाइंड माउंट विंडोज़ पर विश्वसनीय रूप से काम नहीं करते हैं
  • अपनी .env.local फ़ाइल से पर्यावरण चर को कंटेनर में लोड करने के लिए env_file का उपयोग करें
  • docker-compose.dev.yml को docker-compose.prod.yml से अलग करें - वे विभिन्न उद्देश्यों की पूर्ति करते हैं
  • depends_on.condition: service_healthy पैटर्न केवल कंटेनर प्रारंभ की नहीं, बल्कि वास्तविक तत्परता की प्रतीक्षा करता है
  • वैकल्पिक सेवाओं (ईमेल, मॉनिटरिंग) को ऑप्ट-इन करने के लिए profiles का उपयोग करें
  • docker compose (v2) चलाएँ, docker-compose (v1) नहीं - प्लगइन सिंटैक्स चालू है

संपूर्ण विकास ढेर

# infrastructure/docker-compose.dev.yml
name: ecosire-dev

services:
  # ─── PostgreSQL ─────────────────────────────────────────────────
  postgres:
    image: postgres:17-alpine
    container_name: ecosire-postgres
    environment:
      POSTGRES_DB: ecosire_dev
      POSTGRES_USER: ecosire
      POSTGRES_PASSWORD: dev_password_change_in_prod
    ports:
      - "5433:5432"  # 5433 externally — avoids conflicts with system PostgreSQL
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init-scripts:/docker-entrypoint-initdb.d  # Run SQL on first start
    command: >
      postgres
        -c shared_buffers=256MB
        -c effective_cache_size=1GB
        -c work_mem=16MB
        -c maintenance_work_mem=128MB
        -c checkpoint_completion_target=0.9
        -c wal_buffers=16MB
        -c max_connections=100
        -c log_min_duration_statement=100
        -c log_statement=ddl
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ecosire -d ecosire_dev"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    restart: unless-stopped

  # ─── Redis ──────────────────────────────────────────────────────
  redis:
    image: redis:7-alpine
    container_name: ecosire-redis
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: >
      redis-server
        --maxmemory 512mb
        --maxmemory-policy allkeys-lru
        --appendonly yes
        --appendfsync everysec
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # ─── Authentik (Identity Provider) ──────────────────────────────
  authentik-server:
    image: ghcr.io/goauthentik/server:2024.12
    container_name: ecosire-authentik
    command: server
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_POSTGRESQL__HOST: postgres
      AUTHENTIK_POSTGRESQL__USER: ecosire
      AUTHENTIK_POSTGRESQL__PASSWORD: dev_password_change_in_prod
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_SECRET_KEY: dev-secret-key-change-in-production-32chars
      AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
      AUTHENTIK_DISABLE_STARTUP_ANALYTICS: "true"
    volumes:
      - authentik_media:/media
      - authentik_certs:/certs
    ports:
      - "9000:9000"  # HTTP
      - "9443:9443"  # HTTPS
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "ak healthcheck"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s  # Authentik takes time to initialize
    restart: unless-stopped

  authentik-worker:
    image: ghcr.io/goauthentik/server:2024.12
    container_name: ecosire-authentik-worker
    command: worker
    environment:
      AUTHENTIK_REDIS__HOST: redis
      AUTHENTIK_POSTGRESQL__HOST: postgres
      AUTHENTIK_POSTGRESQL__USER: ecosire
      AUTHENTIK_POSTGRESQL__PASSWORD: dev_password_change_in_prod
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_SECRET_KEY: dev-secret-key-change-in-production-32chars
    volumes:
      - authentik_media:/media
      - authentik_certs:/certs
      - /var/run/docker.sock:/var/run/docker.sock  # For Authentik's proxy
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped

  # ─── Mailpit (Email Testing) ─────────────────────────────────────
  mailpit:
    image: axllent/mailpit:latest
    container_name: ecosire-mailpit
    ports:
      - "1025:1025"  # SMTP
      - "8025:8025"  # Web UI
    environment:
      MP_MAX_MESSAGES: 200
      MP_SMTP_AUTH_ACCEPT_ANY: true
      MP_SMTP_AUTH_ALLOW_INSECURE: true
    restart: unless-stopped
    profiles:
      - email  # Optional — use `docker compose --profile email up`

  # ─── pgAdmin (Database GUI) ─────────────────────────────────────
  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: ecosire-pgadmin
    environment:
      PGADMIN_DEFAULT_EMAIL: [email protected]
      PGADMIN_DEFAULT_PASSWORD: admin
      PGADMIN_CONFIG_SERVER_MODE: "False"
      PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False"
    ports:
      - "5050:80"
    volumes:
      - pgadmin_data:/var/lib/pgadmin
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped
    profiles:
      - tools  # Optional

networks:
  default:
    name: ecosire-dev-network

volumes:
  postgres_data:
    name: ecosire-postgres-data
  redis_data:
    name: ecosire-redis-data
  authentik_media:
    name: ecosire-authentik-media
  authentik_certs:
    name: ecosire-authentik-certs
  pgadmin_data:
    name: ecosire-pgadmin-data

पैकेज.जेसन स्क्रिप्ट्स

डॉकर कंपोज़ कमांड को अपनी मोनोरेपो स्क्रिप्ट में वायर करें:

{
  "scripts": {
    "dev:infra": "docker compose -f infrastructure/docker-compose.dev.yml up -d",
    "dev:infra:down": "docker compose -f infrastructure/docker-compose.dev.yml down",
    "dev:infra:logs": "docker compose -f infrastructure/docker-compose.dev.yml logs -f",
    "dev:infra:reset": "docker compose -f infrastructure/docker-compose.dev.yml down -v && pnpm dev:infra",
    "dev:infra:email": "docker compose -f infrastructure/docker-compose.dev.yml --profile email up -d",
    "dev:infra:tools": "docker compose -f infrastructure/docker-compose.dev.yml --profile tools up -d"
  }
}

--profile ध्वज वैकल्पिक सेवाओं (मेलपिट के साथ ईमेल परीक्षण, पीजीएडमिन के साथ डेटाबेस जीयूआई) को स्पष्ट रूप से अनुरोध किए जाने तक निष्क्रिय रहने देता है।


डेटाबेस आरंभीकरण स्क्रिप्ट

SQL फ़ाइलों को infrastructure/init-scripts/ में रखें - वे पहले कंटेनर प्रारंभ पर चलते हैं:

-- infrastructure/init-scripts/01-create-databases.sql
-- Create all databases Authentik needs separately from the app DB
CREATE DATABASE authentik;
GRANT ALL PRIVILEGES ON DATABASE authentik TO ecosire;

-- Create test database for CI
CREATE DATABASE ecosire_test;
GRANT ALL PRIVILEGES ON DATABASE ecosire_test TO ecosire;
-- infrastructure/init-scripts/02-extensions.sql
-- Enable PostgreSQL extensions
\c ecosire_dev;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";  -- Trigram search
CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- Composite GIN indexes

\c ecosire_test;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

आरंभीकरण स्क्रिप्ट वर्णमाला क्रम में चलती हैं। \c database_name psql मेटाकमांड सक्रिय डेटाबेस को स्विच करता है।


पर्यावरण चर एकीकरण

आपका एप्लिकेशन मोनोरेपो रूट में .env.local से पढ़ता है। डॉकर सेवाओं को यह जानना आवश्यक है कि सेवा नामों का उपयोग करके एक-दूसरे से कैसे जुड़ा जाए (localhost नहीं):

# .env.local (monorepo root)

# PostgreSQL — use 5433 externally (host) or 5432 internally (container network)
DATABASE_URL=postgresql://ecosire:dev_password_change_in_prod@localhost:5433/ecosire_dev

# Redis
REDIS_URL=redis://localhost:6379

# Authentik — use 9000 for external calls from your dev machine
AUTHENTIK_URL=http://localhost:9000
# Use service name for server-to-server calls within Docker network
AUTHENTIK_INTERNAL_URL=http://authentik-server:9000

# Email (Mailpit SMTP)
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_SECURE=false

# Application
NODE_ENV=development

डॉकर के अंदर चल रहे एप्लिकेशन के लिए जिन्हें अन्य सेवाओं से बात करने की आवश्यकता है, सेवा नामों का उपयोग करें। आपके होस्ट मशीन (डेव मोड में NestJS, Next.js) पर चलने वाले एप्लिकेशन के लिए, होस्ट-मैप किए गए पोर्ट के साथ localhost का उपयोग करें।


स्वास्थ्य जांच गहन गोता

स्वास्थ्य जांच व्यापक स्टार्टअप विफलताओं को रोकती है। depends_on.condition: service_healthy वास्तविक तैयारी की प्रतीक्षा करता है, न कि केवल कंटेनर प्रारंभ की:

# Without health checks — can fail because PostgreSQL isn't ready
depends_on:
  - postgres

# With health checks — waits for PostgreSQL to accept connections
depends_on:
  postgres:
    condition: service_healthy

आपकी अपनी सेवाओं के लिए कस्टम स्वास्थ्य जांच:

// apps/api/src/health/health.controller.ts
@Get()
@Public()
@HealthCheck()
async check() {
  return this.health.check([
    () => this.db.isHealthy('database'),
    () => this.redis.isHealthy('redis'),
  ]);
}
# If your API is also dockerized
api:
  image: ecosire-api:latest
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
    interval: 30s
    timeout: 10s
    retries: 3
    start_period: 30s

वॉल्यूम प्रबंधन

नामित वॉल्यूम पुनरारंभ के बीच डेटा बनाए रखते हैं। समझें कि प्रत्येक वॉल्यूम प्रकार का उपयोग कब करना है:

प्रकारदृढ़ताप्रदर्शनके लिए उपयोग करें
नामित मात्राहाँउत्कृष्टडेटाबेस डेटा
बाइंड माउंटहाँअच्छा (लिनक्स), ख़राब (मैकओएस)स्रोत कोड हॉट-रीलोड
tmpfsनहींउत्कृष्टअस्थायी फ़ाइलें, रहस्य
# Use bind mounts for source code (enables hot reload)
volumes:
  - ./apps/api/src:/app/src  # Code changes reflected immediately

# Use named volumes for data
volumes:
  - postgres_data:/var/lib/postgresql/data

# Use tmpfs for ephemeral data
volumes:
  - type: tmpfs
    target: /tmp

डॉकर डेस्कटॉप के साथ macOS पर, बाइंड माउंट्स gRPC FUSE का उपयोग करते हैं जो लिनक्स की तुलना में काफी धीमा है। NestJS और Next.js डेव सर्वर के लिए, मूल फ़ाइल सिस्टम प्रदर्शन प्राप्त करने के लिए उन्हें सीधे अपने होस्ट मशीन पर चलाएं (डॉकर में नहीं)।


प्रोडक्शन डॉकर कंपोज़

उत्पादन कंपोज़ फ़ाइल संरचनात्मक रूप से भिन्न है - कोई स्थानीय पोर्ट नहीं, पुनरारंभ नीतियां, उत्पादन संसाधन सीमाएँ:

# infrastructure/docker-compose.prod.yml
name: ecosire-prod

services:
  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    # No port mapping — only accessible within Docker network
    restart: always
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 512M

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 1gb
    volumes:
      - redis_data:/data
    restart: always
    # No port mapping — internal only

volumes:
  postgres_data:
  redis_data:

उत्पादन बाहरी रूप से बंदरगाहों को उजागर नहीं करता है - एप्लिकेशन आंतरिक डॉकर नेटवर्क के माध्यम से जुड़ते हैं। Nginx बाहरी ट्रैफ़िक को संभालता है।


सामान्य नुकसान और समाधान

नुकसान 1: सिस्टम सेवाओं के साथ पोर्ट का टकराव

PostgreSQL, Redis और अन्य सेवाएँ अक्सर सिस्टम सेवाओं के रूप में चलती हैं। विकास में हमेशा गैर-मानक बंदरगाहों पर मैप करें:

  • PostgreSQL: 5433:5432 (5432:5432 नहीं)
  • रेडिस: 6379:6379 रखें (शायद ही कभी टकराव)
  • डिफ़ॉल्ट पोर्ट का उपयोग क्या कर रहा है यह जांचने के लिए lsof -i :5432 चलाएँ

नुकसान 2: Linux पर वॉल्यूम अनुमति संबंधी समस्याएँ

लिनक्स पर डॉकर वॉल्यूम डिफ़ॉल्ट रूप से रूट स्वामित्व का उपयोग करते हैं। यदि आपका कंटेनर उपयोगकर्ता गैर-रूट है, तो सही स्वामित्व सेट करें:

postgres:
  image: postgres:17-alpine
  user: "999:999"  # postgres user's UID:GID
  # Or use init container to fix permissions

नुकसान 3: प्रामाणिक आरंभीकरण में 60+ सेकंड लगते हैं

ऑथेंटिक पहली शुरुआत में डेटाबेस माइग्रेशन चलाता है। स्वास्थ्य जांच में start_period: 60s इसे समय देता है। यदि ऑथेंटिक तैयार होने से पहले आश्रित सेवाएँ शुरू हो जाती हैं, तो वे विफल हो जाएँगी। service_healthy शर्त का उपयोग करें और इसे पर्याप्त start_period दें।

नुकसान 4: मैक पर डॉकर डेस्कटॉप संसाधन सीमा

डिफ़ॉल्ट डॉकर डेस्कटॉप 2 सीपीयू और 2 जीबी रैम आवंटित करता है - पोस्टग्रेएसक्यूएल + रेडिस + ऑथेंटिक को एक साथ चलाने के लिए पर्याप्त नहीं है। डॉकर डेस्कटॉप सेटिंग्स> संसाधनों में कम से कम 4 सीपीयू और 6 जीबी रैम तक वृद्धि।

नुकसान 5: docker-compose बनाम docker compose

पुराना docker-compose (v1, पायथन में लिखा गया) अप्रचलित है। docker compose (v2, प्लगइन) का उपयोग करें। अपना संस्करण जांचें: docker compose version। यदि आपको Docker Compose version v2.x.x दिखाई देता है, तो आप v2 का उपयोग कर रहे हैं।


अक्सर पूछे जाने वाले प्रश्न

क्या मुझे विकास के दौरान डॉकर में अपनी एप्लिकेशन सेवाएं (NestJS, Next.js) चलानी चाहिए?

आम तौर पर नहीं - सक्रिय विकास के लिए, तेज़ हॉट-रीलोड और आसान डिबगिंग के लिए अपनी एप्लिकेशन सेवाओं को अपने होस्ट मशीन पर चलाएं। डॉकर का उपयोग केवल बुनियादी सुविधाओं (डेटाबेस, कैश, पहचान प्रदाता) के लिए करें जो स्थिर हैं और जिन्हें बार-बार पुनरारंभ करने की आवश्यकता नहीं है। अपवाद यह है कि यदि आपके एप्लिकेशन में मूल निर्भरताएं हैं जो आपके विकास ओएस और उत्पादन वातावरण के बीच भिन्न हैं।

मैं डॉकर कंपोज़ वर्कफ़्लो में डेटाबेस माइग्रेशन को कैसे प्रबंधित करूं?

इन्फ्रास्ट्रक्चर शुरू करने के बाद अपनी होस्ट मशीन से माइग्रेशन चलाएँ: pnpm dev:infra && pnpm db:migrate। विकास के दौरान डॉकर कंटेनर के अंदर माइग्रेशन न चलाएं - आप प्रकार की जांच और आईडीई एकीकरण खो देते हैं जो ड्रिज़ल माइग्रेशन को सुरक्षित बनाता है। प्रारंभिक डेटाबेस निर्माण के लिए, डॉकर की initdb.d स्क्रिप्ट का उपयोग करें।

मैं अपने स्थानीय डॉकर वॉल्यूम का बैकअप और पुनर्स्थापित कैसे करूं?

बैकअप लेने के लिए docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres-backup.tar.gz /data का उपयोग करें। tar xzf का उपयोग करके उसी दृष्टिकोण से पुनर्स्थापित करें। विकास के लिए, आप pg_dump के साथ डंप भी कर सकते हैं और psql के साथ पुनर्स्थापित कर सकते हैं क्योंकि आपके पास पोर्ट खुला है।

मैं डॉकर कंपोज़ स्थिति को टीम के अन्य सदस्यों के साथ कैसे साझा करूं?

डॉकर कंपोज़ फ़ाइल git के माध्यम से साझा की जाती है, लेकिन वॉल्यूम में डेटा स्थानीय है। प्रत्येक डेवलपर एक खाली डेटाबेस से शुरू करता है और इसे भरने के लिए माइग्रेशन/बीज चलाता है। सुसंगत परीक्षण डेटा बनाने के लिए बीज स्क्रिप्ट (रेपो के लिए प्रतिबद्ध) का उपयोग करें। साझा docker-compose.dev.yml सुनिश्चित करता है कि हर कोई समान सेवा संस्करण और कॉन्फ़िगरेशन का उपयोग करता है।

विकास में वास्तविक ईमेल के बजाय मेलपिट का उपयोग क्यों करें?

मेलपिट एक स्थानीय एसएमटीपी सर्वर है जो सभी आउटगोइंग ईमेल को कैप्चर करता है और उन्हें देखने के लिए एक वेब यूआई प्रदान करता है। यह विकास के दौरान वास्तविक उपयोगकर्ताओं को गलती से वास्तविक ईमेल भेजने से रोकता है, एसएमटीपी क्रेडेंशियल्स की आवश्यकता नहीं होती है, और आपको अपने इनबॉक्स की जांच किए बिना ईमेल टेम्पलेट्स को सत्यापित करने देता है। SMTP_HOST=localhost SMTP_PORT=1025 का उपयोग करने के लिए अपने ऐप को कॉन्फ़िगर करें और कैप्चर किए गए ईमेल देखने के लिए http://localhost:8025 पर जाएं।


अगले चरण

स्थानीय विकास के लिए एक अच्छी तरह से तैयार किया गया डॉकर कंपोज़ सेटअप एक निवेश है जो हर बार एक नए डेवलपर के शामिल होने या आपके द्वारा एक नई मशीन तैयार करने पर लाभांश का भुगतान करता है। ECOSIRE पूरी टीम में स्थानीय विकास के लिए डॉकर कंपोज़ में PostgreSQL 17, Redis 7 और ऑथेंटिक चलाता है।

क्या आपको अपने स्थानीय विकास बुनियादी ढांचे को डिजाइन करने या उत्पादन के लिए अपने एप्लिकेशन को कंटेनरीकृत करने में सहायता की आवश्यकता है? हमारी DevOps सेवाओं का अन्वेषण करें यह देखने के लिए कि हम कैसे मदद कर सकते हैं।

शेयर करें:
E

लेखक

ECOSIRE Research and Development Team

ECOSIRE में एंटरप्राइज़-ग्रेड डिजिटल उत्पाद बना रहे हैं। Odoo एकीकरण, ई-कॉमर्स ऑटोमेशन, और AI-संचालित व्यावसायिक समाधानों पर अंतर्दृष्टि साझा कर रहे हैं।

WhatsApp पर चैट करें