← Kursa Dön
📄 Text · 30 min

Compose Profilleri, Override ve Ortam Yönetimi

Bu bölümün son dersine geldik. Şimdiye kadar Compose ile projeler kurmayı ve docker-compose.yml anatomisini öğrendik. Ama gerçek hayatta bir proje sadece bir ortamda çalışmaz — development, staging, production, test... Her ortamın farklı ihtiyaçları var. Development'ta debug araçları lazım, production'da resource limitleri, test'te geçici veritabanı.

Peki aynı projeyi farklı ortamlarda nasıl çalıştırırsın? Her ortam için ayrı Compose dosyası mı yazarsın? İşte burada profiller ve override dosyaları devreye giriyor.

Bir oteli düşün. Standart oda herkese aynı: yatak, banyo, TV. Ama "business paketi" seçersen çalışma masası eklenir. "Spa paketi" seçersen jakuzi. Otel aynı, odalar aynı — aktif ettiğin profil ekstra ne alacağını belirler. Compose profilleri tam böyle çalışır.


Compose Profilleri — Opsiyonel Servisler

Profiller, servisleri gruplandırıp isteğe bağlı aktif etmeni sağlar. Profil tanımlanmayan servisler her zaman çalışır — bunlar projenin çekirdeği. Profilli servisler ise sadece o profil aktifken çalışır.

services:
  # Her zaman çalışanlar (profil yok)
  api:
    build: ./api
    ports:
      - "3000:3000"

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data

  # Debug profili
  adminer:
    image: adminer:latest
    ports:
      - "8080:8080"
    profiles:
      - debug

  mailhog:
    image: mailhog/mailhog
    ports:
      - "8025:8025"
      - "1025:1025"
    profiles:
      - debug

  # Monitoring profili
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    profiles:
      - monitoring

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3001:3000"
    profiles:
      - monitoring

  # Test profili
  test-runner:
    build:
      context: ./api
      target: test
    command: npm test
    depends_on:
      test-db: { condition: service_healthy }
    profiles:
      - test

  test-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
      POSTGRES_DB: testdb
    tmpfs:
      - /var/lib/postgresql/data  # RAM'de — hızlı, geçici
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U test"]
      interval: 5s
      timeout: 3s
      retries: 5
    profiles:
      - test

volumes:
  pgdata:

Kullanımı çok basit:

# Sadece temel servisler (api + db)
docker compose up -d
# adminer, mailhog, prometheus, grafana ÇALIŞMAZ

# Debug araçlarıyla birlikte
docker compose --profile debug up -d
# api + db + adminer + mailhog

# Monitoring ile birlikte
docker compose --profile monitoring up -d
# api + db + prometheus + grafana

# Her şeyi birden
docker compose --profile debug --profile monitoring up -d
# api + db + adminer + mailhog + prometheus + grafana

# Testleri çalıştır
docker compose --profile test run --rm test-runner

Test profili çok akıllıca tasarlanmış. test-db servisi tmpfs kullanıyor — veritabanı RAM'de çalışıyor, disk I/O yok, çok hızlı. Test bitince her şey silinir. Ve test-runner'ın depends_on'ı sayesinde test-db otomatik başlatılır.

Profili environment variable ile de aktifleştirebilirsin:

export COMPOSE_PROFILES=debug,monitoring
docker compose up -d

Ya da .env dosyasında:

COMPOSE_PROFILES=debug

Override Dosyaları — Ortam Bazlı Konfigürasyon

Override dosyaları, temel Compose dosyasının üzerine ek konfigürasyon "yamar." Aynı servis için farklı ayarları ortam bazında tanımlarsın.

Otomatik Override

docker-compose.override.yml adında bir dosya varsa, Compose onu otomatik yükler:

# docker-compose.yml (base — her ortamda geçerli)
services:
  api:
    build: ./api
    environment:
      NODE_ENV: production
  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:
# docker-compose.override.yml (development — OTOMATİK yüklenir)
services:
  api:
    build:
      target: development
    volumes:
      - ./api/src:/app/src
      - /app/node_modules
    ports:
      - "3000:3000"
      - "9229:9229"
    environment:
      NODE_ENV: development
      DEBUG: "app:*"
  db:
    ports:
      - "5432:5432"
# Override otomatik uygulanır
docker compose up -d
# api: development stage, hot reload, debug port

# Override'ı ATLAYARAK production ayarlarıyla başlat
docker compose -f docker-compose.yml up -d

Bu çok pratik — development'ta docker compose up demen yeter, override otomatik gelir.

Manuel Override Dosyaları

Farklı ortamlar için ayrı override dosyaları oluştur:

# docker-compose.staging.yml
services:
  api:
    build: { target: production }
    environment:
      NODE_ENV: staging
      LOG_LEVEL: debug
    deploy:
      resources:
        limits: { memory: 256M }
# docker-compose.prod.yml
services:
  api:
    build: { target: production }
    deploy:
      replicas: 3
      resources:
        limits: { memory: 512M, cpus: "1.0" }
    logging:
      driver: json-file
      options: { max-size: "50m", max-file: "10" }
# Staging
docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Override Birleştirme Kuralları

Bu kuralları bilmek önemli çünkü bazen beklenmedik sonuçlar üretir:

Tek değerler (image, command, entrypoint) → Override üzerine yazar. Map'ler (environment, labels) → Aynı key üzerine yazar, yeni key eklenir. Listeler (ports, volumes) → Override'daki öğeler eklenir (replace etmez!).

Örnek:

# Base:
services:
  api:
    ports: ["3000:3000"]
    environment:
      NODE_ENV: production
      LOG_LEVEL: warn

# Override:
services:
  api:
    ports: ["9229:9229"]        # EKLENIR (replace değil!)
    environment:
      NODE_ENV: development     # ÜZERINE YAZAR
      DEBUG: "*"                # YENİ — eklenir

Sonuç: ports → ["3000:3000", "9229:9229"], environment → {NODE_ENV: development, LOG_LEVEL: warn, DEBUG: "*"}.

Final konfigürasyonu görmek için:

docker compose -f docker-compose.yml -f docker-compose.prod.yml config

Makefile ile Kısayollar

Her seferinde uzun docker compose -f ... -f ... komutları yazmak yorucu. Makefile ile kısayollar oluştur:

.PHONY: dev staging prod test logs clean

COMPOSE = docker compose -f docker-compose.yml

dev:
	$(COMPOSE) -f docker-compose.override.yml up -d
	@echo "Dev: http://localhost:3000"

staging:
	$(COMPOSE) -f docker-compose.staging.yml --env-file .env.staging up -d --build

prod:
	$(COMPOSE) -f docker-compose.prod.yml --env-file .env.production up -d --build

test:
	$(COMPOSE) --profile test run --rm test-runner

logs:
	$(COMPOSE) logs -f $(SVC)

shell:
	$(COMPOSE) exec $(SVC) sh

migrate:
	$(COMPOSE) run --rm api node scripts/migrate.js

clean:
	$(COMPOSE) down -v --rmi local

status:
	$(COMPOSE) ps

Kullanımı:

make dev          # Development ortamını başlat
make prod         # Production deploy
make test         # Testleri çalıştır
make logs SVC=api # API loglarını izle
make shell SVC=db # Veritabanı shell'i aç
make migrate      # Migration çalıştır

Compose Watch — Dosya İzleme (v2.22+)

Modern Docker Compose'un çok kullanışlı bir özelliği: dosya değişikliğini otomatik algılayıp uygun aksiyonu almak.

services:
  api:
    build: ./api
    develop:
      watch:
        - action: sync
          path: ./api/src
          target: /app/src
          ignore: ["**/*.test.js"]

        - action: rebuild
          path: ./api/package.json

        - action: sync+restart
          path: ./api/config
          target: /app/config
docker compose watch

Bu modda:

  • src/server.js değişti → dosyayı container'a sync et (rebuild yok, çok hızlı)

  • package.json değişti → image'ı rebuild et, container'ı yeniden oluştur

  • config/app.yml değişti → dosyayı sync et ve container'ı restart et

Bind mount'a alternatif olarak watch daha akıllı — her dosya değişikliği için farklı aksiyon tanımlayabiliyorsun.


COMPOSE_FILE Environment Variable

# Her seferinde -f yazmak yerine
export COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml
docker compose up -d

# .env dosyasında da tanımlayabilirsin
COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml
COMPOSE_PROJECT_NAME=myapp  # Volume ve network prefix'i
COMPOSE_PROFILES=monitoring

Gerçek Dünya Ortam Yapısı

project/
├── docker-compose.yml              # Base config
├── docker-compose.override.yml     # Dev (otomatik)
├── docker-compose.staging.yml      # Staging
├── docker-compose.prod.yml         # Production
├── .env                            # Dev variables
├── .env.example                    # Template (git'e commit)
├── .env.production                 # Prod variables (commit ETME)
├── Makefile                        # Kısayollar
└── .gitignore
# .gitignore
.env
.env.production
.env.staging
!.env.example
docker-compose.override.yml  # Her developer kendi override'ını yazsın

Yaygın Hatalar

Override otomatik yükleniyor: Production sunucusunda docker-compose.override.yml varsa otomatik yüklenir ve debug araçları açılır! Çözüm: Production'da açıkça dosya belirt veya override dosyasını gitignore'a ekle.

Host env, .env'yi override eder: export DB_PASS=old yaptıysan ve .env'de DB_PASS=new varsa, old değeri kullanılır. Host environment her zaman önce gelir. unset DB_PASS ile temizle.

Profilli bağımlılık: Profil'siz bir servis, profilli bir servise depends_on ile bağlanamaz — profil aktif edilmeden o servis başlatılamaz.


Bu Derste Ne Öğrendik?

  • Profiller ile servisleri grupla: --profile debug, --profile monitoring, --profile test.

  • Override dosyaları ile ortam bazlı konfigürasyon: base + dev/staging/prod.

  • docker-compose.override.yml otomatik yüklenir — production'da dikkatli ol.

  • Override'da listeler eklenir (replace etmez), map'lerdeki aynı key üzerine yazılır.

  • Makefile ile günlük komutlara kısayol oluştur.

  • Compose Watch ile development'ta dosya değişikliklerini akıllıca yönet.

  • Host env > --env-file > .envöncelik sırasını bil.

Bu, Docker Compose bölümünün son dersiydi. Artık birden fazla container'ı profesyonelce yönetmeyi biliyorsun. Sonraki bölümde Docker image'larını optimize etmeyi öğreneceğiz — multi-stage builds, layer caching ve image boyut küçültme.