Docker: Geliştirmeden Üretime

Uygulamaları konteynerleştirmek için eksiksiz Docker rehberi. Dockerfile, Docker Compose, multi-stage build ve üretim ortamına dağıtım pratik örneklerle açıklanıyor.

Docker rehberi geliştirmeden üretime

Docker, uygulamaların geliştirilme, test edilme ve dağıtılma şeklini kökten değiştirmektedir. Bir uygulamayı ve bağımlılıklarını taşınabilir bir konteyner içinde kapsülleyerek Docker, meşhur "benim makinemde çalışıyor" sorununu ortadan kaldırır ve tüm ortamlarda tutarlılık sağlar. Bu rehber, ilk Dockerfile'dan üretim ortamına dağıtıma kadar tam yolculuğu kapsamaktadır.

2026'da Docker

Docker Desktop 5.x, yerel containerd desteği, optimize edilmiş kaynak yönetimi ve sorunsuz Kubernetes entegrasyonu dahil önemli performans iyileştirmeleri getirmektedir. Çoklu mimari imajlar (ARM/x86) artık standart uygulama haline gelmiştir.

Konteynerleştirme Temelleri

Bir konteyner, kod, çalışma zamanı, sistem kütüphaneleri ve ayarları paketleyen hafif bir yazılım birimidir. Donanımı sanallaştıran sanal makinelerin aksine, konteynerler ana bilgisayar çekirdeğini paylaşır ve bu da onları daha hızlı başlatılabilir ve daha az kaynak tüketir hale getirir.

bash
# terminal
# Docker installation on Ubuntu
sudo apt update
sudo apt install -y docker.io

# Add user to docker group (avoids sudo)
sudo usermod -aG docker $USER

# Verify installation
docker --version
# Docker version 26.1.0, build 1234567

# First container: downloads image and runs
docker run hello-world

Bu komut Docker Hub'dan hello-world imajını indirir ve bir onay mesajı görüntüleyen bir konteyner başlatır.

bash
# terminal
# List running containers
docker ps

# List all containers (including stopped)
docker ps -a

# List downloaded images
docker images

# Remove a container
docker rm <container_id>

# Remove an image
docker rmi <image_name>

Bu temel komutlar konteynerlerin ve imajların yaşam döngüsünü yönetir.

İlk Dockerfile'ın Oluşturulması

Bir Dockerfile, Docker imajı oluşturmak için talimatlar içerir. Her talimat son imajda bir katman oluşturur ve böylece önbelleğe alma ve yeniden kullanım mümkün olur.

dockerfile
# Dockerfile
# Base image: Node.js 22 on Alpine Linux (lightweight)
FROM node:22-alpine

# Set working directory in the container
WORKDIR /app

# Copy dependency files first (cache optimization)
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy source code
COPY . .

# Expose port (documentation)
EXPOSE 3000

# Startup command
CMD ["node", "server.js"]

Talimatların sırası önbellek optimizasyonu için kritik öneme sahiptir. Nadiren değişen dosyalar (package.json) kaynak koddan önce kopyalanmalıdır.

bash
# terminal
# Build image with a tag
docker build -t my-app:1.0 .

# Run the container
docker run -d -p 3000:3000 --name my-app-container my-app:1.0

# Check logs
docker logs my-app-container

# Access container shell
docker exec -it my-app-container sh

-d bayrağı konteyneri arka planda çalıştırır, -p konteynerin 3000 portunu ana bilgisayarın 3000 portuna eşler.

Alpine vs Debian

Alpine imajları önemli ölçüde daha küçüktür (Debian için yaklaşık 120 MB'ye karşı 5 MB). Ancak glibc yerine musl libc kullanırlar ve bu bazı yerel bağımlılıklarla uyumsuzluklara neden olabilir. Sorun yaşandığında Debian tabanlı imajların (node:22-slim) tercih edilmesi önerilir.

Üretim İçin Multi-stage Build

Multi-stage build'ler, derleme ortamını çalışma zamanı ortamından ayırarak optimize edilmiş üretim imajları oluşturur. Son imaja yalnızca gerekli bileşenler dahil edilir.

dockerfile
# Dockerfile.production
# ============================================
# Stage 1: Build
# ============================================
FROM node:22-alpine AS builder

WORKDIR /app

# Copy and install dependencies (including devDependencies)
COPY package*.json ./
RUN npm ci

# Copy source code
COPY . .

# Build the application (TypeScript, bundling, etc.)
RUN npm run build

# ============================================
# Stage 2: Production
# ============================================
FROM node:22-alpine AS production

# Non-root user for security
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

WORKDIR /app

# Copy only necessary files from builder stage
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

# Switch to non-root user
USER nodejs

# Environment variables
ENV NODE_ENV=production
ENV PORT=3000

EXPOSE 3000

# Startup command
CMD ["node", "dist/server.js"]

Bu yaklaşım, derleme araçlarını, devDependencies ve kaynak dosyalarını hariç tutarak son imaj boyutunu önemli ölçüde azaltır.

bash
# terminal
# Build with specific file
docker build -f Dockerfile.production -t my-app:production .

# Compare image sizes
docker images | grep my-app
# my-app    production    abc123    150MB
# my-app    1.0           def456    450MB

Boyut azaltma projeye bağlı olarak %60-70'e ulaşabilir ve bu da dağıtım sürelerini iyileştirirken saldırı yüzeyini azaltır.

Yerel Orkestrasyon İçin Docker Compose

Docker Compose, çok konteynerli uygulama yönetimini basitleştirir. Bir YAML dosyası tüm servisleri, yapılandırmalarını ve bağımlılıklarını bildirir.

yaml
# docker-compose.yml
version: "3.9"

services:
  # Main application
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
      - REDIS_URL=redis://cache:6379
    volumes:
      # Mount source code for hot-reload
      - ./src:/app/src
      - ./package.json:/app/package.json
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    networks:
      - app-network

  # PostgreSQL database
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      # Data persistence
      - postgres_data:/var/lib/postgresql/data
      # Initialization script
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - app-network

  # Redis cache
  cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    networks:
      - app-network

# Named volumes for persistence
volumes:
  postgres_data:
  redis_data:

# Dedicated network for isolation
networks:
  app-network:
    driver: bridge

Servisler, dahili Docker ağı üzerinden adlarıyla (db, cache) iletişim kurar. Healthcheck'ler, uygulama başlamadan önce bağımlılıkların hazır olmasını sağlar.

bash
# terminal
# Start all services
docker compose up -d

# View logs from all services
docker compose logs -f

# Logs from a specific service
docker compose logs -f app

# Stop and remove containers
docker compose down

# Removal including volumes (caution: data loss)
docker compose down -v

# Rebuild after Dockerfile changes
docker compose up -d --build

DevOps mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Gizli Bilgi ve Ortam Değişkeni Yönetimi

Gizli bilgilerin güvenli yönetimi üretim ortamında kritik öneme sahiptir. Docker, bağlama göre farklı yaklaşımlar sunar.

yaml
# docker-compose.override.yml (development only)
version: "3.9"

services:
  app:
    env_file:
      - .env.development
    environment:
      - DEBUG=true

Üretim ortamı için Docker secrets daha yüksek güvenlik sağlar.

yaml
# docker-compose.production.yml
version: "3.9"

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.production
    secrets:
      - db_password
      - api_key
    environment:
      - NODE_ENV=production
      - DATABASE_PASSWORD_FILE=/run/secrets/db_password
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    file: ./secrets/api_key.txt

Uygulama kodu gizli bilgileri bağlanmış dosyalardan okur.

config/secrets.jsjavascript
const fs = require('fs');
const path = require('path');

// Utility function to read Docker secrets
function readSecret(secretName) {
  const secretPath = `/run/secrets/${secretName}`;

  // Check if secret file exists
  if (fs.existsSync(secretPath)) {
    return fs.readFileSync(secretPath, 'utf8').trim();
  }

  // Fallback to classic environment variables
  const envVar = secretName.toUpperCase();
  return process.env[envVar];
}

module.exports = {
  databasePassword: readSecret('db_password'),
  apiKey: readSecret('api_key'),
};

Bu yaklaşım, gizli bilgilerin ortam değişkenlerinde veya Docker imajlarında açığa çıkmasını önler.

Docker İmajlarının Optimizasyonu

Çeşitli teknikler imaj boyutunu azaltır ve performansı artırır.

dockerfile
# Dockerfile.optimized
FROM node:22-alpine AS base

# Install necessary tools in a single layer
RUN apk add --no-cache \
    dumb-init \
    && rm -rf /var/cache/apk/*

# ============================================
# Stage: Dependencies
# ============================================
FROM base AS deps

WORKDIR /app

# Copy only lock files for caching
COPY package.json package-lock.json ./

# Install with mounted npm cache (BuildKit)
RUN --mount=type=cache,target=/root/.npm \
    npm ci --only=production

# ============================================
# Stage: Builder
# ============================================
FROM base AS builder

WORKDIR /app

COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci

COPY . .
RUN npm run build

# ============================================
# Stage: Production
# ============================================
FROM base AS production

# Image metadata
LABEL maintainer="team@example.com"
LABEL version="1.0"
LABEL description="Production-ready Node.js application"

# Non-root user
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

WORKDIR /app

# Copy production dependencies
COPY --from=deps --chown=nodejs:nodejs /app/node_modules ./node_modules

# Copy build output
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/package.json ./

USER nodejs

ENV NODE_ENV=production

# dumb-init as PID 1 for signal handling
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]

dumb-init kullanımı Unix sinyallerinin doğru işlenmesini sağlar ve konteynerin düzgün bir şekilde kapatılmasını mümkün kılar.

bash
# terminal
# Enable BuildKit for advanced features
export DOCKER_BUILDKIT=1

# Build with cache and detailed output
docker build --progress=plain -t my-app:optimized .

# Analyze image layers
docker history my-app:optimized

# Detailed image inspection
docker inspect my-app:optimized
İmaj Güvenliği

İmajlar Trivy veya Snyk gibi araçlarla düzenli olarak güvenlik açıkları için taranmalıdır. Temel imajlar güvenlik yamalarını içerecek şekilde düzenli olarak güncellenmelidir.

Gelişmiş Docker Ağları

Docker, farklı kullanım senaryoları için çeşitli ağ sürücüleri sunar.

yaml
# docker-compose.networking.yml
version: "3.9"

services:
  # Publicly accessible frontend
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    networks:
      - frontend-network
      - backend-network

  # API accessible only from frontend
  api:
    build: ./api
    networks:
      - backend-network
      - database-network
    # No external ports exposed

  # Isolated database
  database:
    image: postgres:16-alpine
    networks:
      - database-network
    # Accessible only by API

networks:
  frontend-network:
    driver: bridge
  backend-network:
    driver: bridge
    internal: true  # No internet access
  database-network:
    driver: bridge
    internal: true

Bu yapılandırma en az yetki ilkesini izleyerek servisleri izole eder. Veritabanı yalnızca API tarafından erişilebilir durumdadır.

bash
# terminal
# Inspect Docker networks
docker network ls

# Details of a specific network
docker network inspect app-network

# Create a custom network
docker network create --driver bridge --subnet 172.28.0.0/16 custom-network

# Connect a container to an existing network
docker network connect custom-network my-container

Volume'lar ve Veri Kalıcılığı

Docker volume'ları verileri konteyner yaşam döngüsünün ötesinde korur.

yaml
# docker-compose.volumes.yml
version: "3.9"

services:
  app:
    image: my-app:latest
    volumes:
      # Named volume for persistent data
      - app_data:/app/data
      # Bind mount for development
      - ./uploads:/app/uploads:rw
      # Read-only mount for configuration
      - ./config:/app/config:ro

  backup:
    image: alpine
    volumes:
      # Access same volume for backups
      - app_data:/data:ro
      - ./backups:/backups
    command: |
      sh -c "tar czf /backups/backup-$$(date +%Y%m%d).tar.gz /data"

volumes:
  app_data:
    driver: local
    driver_opts:
      type: none
      device: /path/to/host/data
      o: bind

Adlandırılmış volume'lar ve bind mount'lar arasındaki fark önemlidir: volume'lar Docker tarafından yönetilirken, bind mount'lar doğrudan ana bilgisayar dosya sistemini kullanır.

bash
# terminal
# List volumes
docker volume ls

# Inspect a volume
docker volume inspect app_data

# Remove orphaned volumes
docker volume prune

# Backup a volume
docker run --rm -v app_data:/data -v $(pwd):/backup alpine \
  tar czf /backup/volume-backup.tar.gz /data

Üretim Ortamına Dağıtım

Sağlam bir dağıtım iş akışı derleme, test ve registry'ye gönderme işlemlerini içerir.

bash
# deploy.sh
#!/bin/bash
set -e

# Variables
REGISTRY="registry.example.com"
IMAGE_NAME="my-app"
VERSION=$(git describe --tags --always)

echo "Building version: $VERSION"

# Build production image
docker build \
  -f Dockerfile.production \
  -t $REGISTRY/$IMAGE_NAME:$VERSION \
  -t $REGISTRY/$IMAGE_NAME:latest \
  --build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
  --build-arg VERSION=$VERSION \
  .

# Security scan
echo "Running security scan..."
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy image $REGISTRY/$IMAGE_NAME:$VERSION

# Push to registry
echo "Pushing to registry..."
docker push $REGISTRY/$IMAGE_NAME:$VERSION
docker push $REGISTRY/$IMAGE_NAME:latest

echo "Deployment complete: $REGISTRY/$IMAGE_NAME:$VERSION"

Sunucu dağıtımları için ayrı bir üretim compose dosyası yapılandırmayı uyarlar.

yaml
# docker-compose.prod.yml
version: "3.9"

services:
  app:
    image: registry.example.com/my-app:latest
    restart: always
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Bu yapılandırma güvenilir bir dağıtım için kaynak tahsisi, güncelleme stratejisi ve healthcheck'leri tanımlar.

bash
# terminal
# Production deployment with Docker Compose
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# Zero-downtime update (rolling update)
docker compose -f docker-compose.yml -f docker-compose.prod.yml pull
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps app

# Rollback if issues occur
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps \
  --scale app=0 && \
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps app

Konteyner İzleme ve Hata Ayıklama

Konteyner izleme üretim ortamında vazgeçilmezdir.

bash
# terminal
# Real-time statistics for all containers
docker stats

# Statistics for a specific container with custom format
docker stats my-app --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# Inspect processes in a container
docker top my-app

# Real-time Docker events
docker events --filter container=my-app

# Copy files from/to a container
docker cp my-app:/app/logs/error.log ./error.log

Derinlemesine hata ayıklama için çeşitli teknikler mevcuttur.

bash
# terminal
# Interactive shell in a running container
docker exec -it my-app sh

# Execute a single command
docker exec my-app cat /app/config/settings.json

# Start a container in debug mode
docker run -it --rm --entrypoint sh my-app:latest

# Inspect environment variables
docker exec my-app printenv

# Analyze logs with filters
docker logs my-app --since 1h --tail 100 | grep ERROR
yaml
# docker-compose.monitoring.yml
version: "3.9"

services:
  app:
    # ... existing configuration
    labels:
      - "prometheus.scrape=true"
      - "prometheus.port=3000"
      - "prometheus.path=/metrics"

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=15d'

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3001:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=secret

volumes:
  prometheus_data:
  grafana_data:

Bu izleme yığını konteyner metriklerinin toplanmasını ve görselleştirilmesini sağlar.

Sonuç

Docker, tüm ortamlarda tutarlılık sağlayarak geliştirme döngüsünü dönüştürmektedir. Konteynerleştirme taşınabilirlik, izolasyon ve tekrarlanabilirlik getirir — modern uygulamalar için temel nitelikler.

Üretim İçin Docker Kontrol Listesi

  • ✅ Optimize edilmiş imajlar için multi-stage build'ler
  • ✅ Konteynerlerde root olmayan kullanıcı
  • ✅ Tüm servisler için healthcheck'ler yapılandırılmış
  • ✅ Docker secrets veya güvenli ortam değişkenleri ile yönetilen gizli bilgiler
  • ✅ Kaynak limitleri (CPU, bellek) tanımlanmış
  • ✅ Kritik veri kalıcılığı için volume'lar
  • ✅ Dosya rotasyonlu merkezi loglama
  • ✅ Dağıtım öncesi imaj güvenlik taraması
  • ✅ Kesintisiz güncelleme stratejisi
  • ✅ Servisler arası izole ağ

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Docker'a hakim olmak her modern geliştiricinin temel becerisidir. Yerel ortamdan üretim dağıtımına kadar Docker iş akışlarını standartlaştırır ve operasyonları basitleştirir. Burada sunulan kavramlar, Kubernetes ve büyük ölçekli konteyner orkestrasyonunu keşfetmek için sağlam bir temel oluşturmaktadır.

Etiketler

#docker
#containerization
#devops
#docker compose
#deployment

Paylaş

İlgili makaleler