DEVOPS // DOCKERD::02 BAŞLANGIÇ+
20m READCOMPLETION: 85%ID::DOP-101

DOCKER İLE KONTEYNERİZASYON TEMELLERİ

Dockerfile, multi-stage build ve container networking

Konteyner teknolojisi, "bende çalışıyor" sorununu kökünden çözdü. Docker, uygulamanı ve tüm bağımlılıklarını izole bir ortama paketler; geliştirme, test ve prodüksiyon ortamları birebir aynı davranır. Bu derste Docker'ın temel kavramlarını öğrenip gerçek bir uygulama konteynerize edeceksin.

Konteyner vs Sanal Makine

// PLAINTEXT //
Sanal Makine:          Konteyner:
┌─────────────┐        ┌─────────────┐
│   App A     │        │   App A     │
├─────────────┤        ├─────────────┤
│ Guest OS    │        │             │
├─────────────┤        │  Container  │
│ Hypervisor  │        │   Runtime   │
├─────────────┤        ├─────────────┤
│  Host OS    │        │   Host OS   │
└─────────────┘        └─────────────┘
  ~GB boyut               ~MB boyut
  ~dakika başlangıç       ~saniye başlangıç

Konteynerler OS kernel'i paylaşır, bu yüzden çok daha hafif ve hızlıdır.

Docker Kurulum ve İlk Adımlar

// BASH //
# Versiyon kontrol
docker --version
docker compose version
 
# İlk konteyner — Ubuntu shell'i
docker run -it ubuntu:24.04 bash
 
# Arka planda çalıştır
docker run -d --name web nginx:alpine
 
# Logları takip et
docker logs -f web
 
# Konteyneri durdur ve sil
docker stop web && docker rm web

Dockerfile: Uygulama Paketleme

// DOCKERFILE //
# Node.js API için Dockerfile
# Aşama 1: Bağımlılıkları kur (önbellek katmanı)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
 
# Aşama 2: Uygulamayı derle
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
 
# Aşama 3: Prodüksiyon imajı (küçük boyut)
FROM node:20-alpine AS runner
WORKDIR /app
 
# Güvenlik: root olmayan kullanıcı
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
 
COPY --from=deps    /app/node_modules ./node_modules
COPY --from=builder /app/dist        ./dist
 
USER appuser
EXPOSE 3000
 
# Healthcheck — konteyner sağlık durumunu raporlar
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
  CMD wget -qO- http://localhost:3000/health || exit 1
 
CMD ["node", "dist/main.js"]

.dockerignore

// PLAINTEXT //
node_modules
dist
.env
.env.*
*.log
.git
.gitignore
README.md
Dockerfile
docker-compose*.yml
coverage
__tests__

İmaj Oluşturma ve Yönetim

// BASH //
# İmaj oluştur (cache etkin)
docker build -t codeforge-api:1.0.0 .
 
# İmaj boyutu kontrolü
docker image ls codeforge-api
 
# Katman analizini gör
docker history codeforge-api:1.0.0
 
# İmajı registry'ye gönder
docker tag codeforge-api:1.0.0 registry.example.com/codeforge-api:1.0.0
docker push registry.example.com/codeforge-api:1.0.0
 
# Kullanılmayan imajları temizle
docker image prune -f

Volume: Kalıcı Veri

// BASH //
# Named volume — Docker yönetir
docker volume create pgdata
 
# PostgreSQL ile volume kullan
docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=gizli \
  -e POSTGRES_DB=codeforge \
  -v pgdata:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16-alpine
 
# Bind mount — host dizinini bağla (geliştirme)
docker run -d \
  --name app \
  -v $(pwd)/src:/app/src \   # kaynak kodu canlı güncelle
  -p 3000:3000 \
  codeforge-api:dev

Network: Konteynerler Arası İletişim

// BASH //
# Özel ağ oluştur
docker network create codeforge-net
 
# Aynı ağda çalıştır
docker run -d --name db    --network codeforge-net postgres:16-alpine
docker run -d --name redis --network codeforge-net redis:7-alpine
 
# App konteyneri DB ve Redis'e isim ile ulaşır
docker run -d \
  --name api \
  --network codeforge-net \
  -e DATABASE_URL=postgresql://postgres:gizli@db:5432/codeforge \
  -e REDIS_URL=redis://redis:6379 \
  codeforge-api:1.0.0
 
# İki konteyner arası bağlantı test et
docker exec api ping -c3 db

Docker Compose: Tek Dosya, Tüm Servisler

// YAML //
# docker-compose.yml
services:
  api:
    build:
      context: .
      target: runner
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://postgres:gizli@db:5432/codeforge
      REDIS_URL: redis://redis:6379
      NODE_ENV: production
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    restart: unless-stopped
 
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: gizli
      POSTGRES_DB: codeforge
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./prisma/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
 
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redisdata:/data
 
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/certs:/etc/nginx/certs:ro
    depends_on:
      - api
 
volumes:
  pgdata:
  redisdata:
// BASH //
# Tüm servisleri başlat (arka planda)
docker compose up -d
 
# Logları takip et
docker compose logs -f api
 
# Sadece api servisini yeniden başlat
docker compose restart api
 
# Prodüksiyona deploy: imajı güncelle
docker compose pull && docker compose up -d
 
# Her şeyi durdur ve temizle (volume hariç)
docker compose down
 
# Volume dahil komple temizle
docker compose down -v

Geliştirme Ortamı: Hot Reload

// YAML //
# docker-compose.dev.yml
services:
  api:
    build:
      context: .
      target: builder    # geliştirme aşaması
    command: npm run dev  # nodemon / ts-node-dev
    volumes:
      - .:/app
      - /app/node_modules  # node_modules'ü override etme
    ports:
      - "3000:3000"
      - "9229:9229"  # Node.js debugger
    environment:
      NODE_ENV: development
// BASH //
# Dev compose ile başlat
docker compose -f docker-compose.yml -f docker-compose.dev.yml up

Güvenlik İpuçları

// DOCKERFILE //
# 1. Minimal base image
FROM node:20-alpine  # debian değil alpine
 
# 2. Root olmayan kullanıcı
USER node
 
# 3. Read-only filesystem
# docker run --read-only --tmpfs /tmp ...
 
# 4. Secret yönetimi — ENV değil secrets
RUN --mount=type=secret,id=npm_token \
    npm config set //registry.npmjs.org/:_authToken=$(cat /run/secrets/npm_token)
 
# 5. İmaj tarama
# docker scout cves codeforge-api:1.0.0

Özet

Docker, konteyner ile VM arasındaki farkı anlayarak başlar. Dockerfile'da çok aşamalı build (AS deps → AS builder → AS runner) imaj boyutunu %70 küçültür. Docker Compose, çok servisli geliştirme ortamını tek docker compose up ile hazır hale getirir. Prodüksiyonda healthcheck, named volume ve non-root kullanıcı üçgeni vazgeçilmezdir.