Skip to content

🐳 Docker Kapsamlı Rehber (Comprehensive Docker Guide)

Full-stack geliştiriciler için pratik Docker referans rehberi. A practical Docker reference for full-stack developers (PHP/Laravel, Node.js, React, Python).

Ne zaman Docker kullanmaliyim?

Kullan: Her proje için izole geliştirme ortami, CI/CD pipeline, mikroservis mimarisi, takim uyelerinin ayni ortamda calismasi gerektiginde

⚠️ Opsiyonel: Basit, tek servisli proje -- direkt calistirmak daha hızlı olabilir

Gereksiz: Sadece statik site sunmak (Netlify/Vercel yeterli)

Önerilen araclar: Docker + Docker Compose

Alternatifler: Podman (daemonless, rootless), LXC/LXD (sistem container), nerdctl (containerd CLI)

🧱 Docker Temelleri

Container vs VM (Sanal Makine)

ÖzellikContainerVirtual Machine
Başlatma süresiSaniyeler (seconds)Dakikalar (minutes)
Boyut (Size)MB seviyesindeGB seviyesinde
IzolasyonProcess-levelFull OS-level
KernelHost kernel paylasilir (shared)Kendi kernel'i var
PerformansNative'e yakinOverhead var
Tasinabilirlik (Portability)Cok yüksekOrta

💡 Container'lar uygulamayi ve bagimliklarini paketler ama OS kernel'ini host ile paylasir. Containers package the app and its dependencies but share the host OS kernel.

🔧 Kurulum (Installation)

Ubuntu / Debian

bash
# 1. Eski sürümleri kaldır (remove old versions)
sudo apt-get remove docker docker-engine docker.io containerd runc 2>/dev/null

# 2. Gerekli paketleri kur (install prerequisites)
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

# 3. Docker'ın resmi GPG anahtarını ekle (add Docker's official GPG key)
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 4. Docker repository'sini ekle (add Docker repository)
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 5. Docker Engine'i kur (install Docker Engine)
sudo apt-get update
sudo apt-get install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

# 6. Docker'ı sudo'suz kullan (run Docker without sudo)
sudo usermod -aG docker $USER

# Oturumu yeniden başlat (logout & login veya):
newgrp docker

# 7. Kurulumu doğrula (verify installation)
docker --version          # Docker version 27.x.x
docker compose version    # Docker Compose version v2.x.x
docker run hello-world    # Test container çalıştır

Kurulum sonrası kontrol listesi (Post-install checklist):

bash
# Docker servisi çalışıyor mu? (Is Docker service running?)
sudo systemctl status docker

# Otomatik başlatma (Start on boot)
sudo systemctl enable docker
sudo systemctl enable containerd

# Kullanıcı docker grubunda mı? (Is user in docker group?)
groups $USER   # "docker" görünmeli

# Eğer "permission denied" hatası alıyorsan:
# 1. Logout/Login yap
# 2. Veya: newgrp docker
# 3. Veya: sudo chmod 666 /var/run/docker.sock (geçici çözüm)

Sorun giderme (Troubleshooting):

Sorun (Problem)Çözüm (Solution)
permission deniedsudo usermod -aG docker $USER + logout/login
Cannot connect to Docker daemonsudo systemctl start docker
docker compose komutu yokdocker-compose-plugin paketini kur
GPG key hatası/etc/apt/keyrings/docker.asc dosyasını sil ve tekrar ekle
Disk doludocker system prune -a ile temizle

Windows

Docker Desktop (önerilen / recommended):

powershell
# 1. Önkoşul: WSL 2 kurulu olmalı (prerequisite: WSL 2)
wsl --install                    # WSL 2 + Ubuntu kur
wsl --set-default-version 2     # Varsayılan WSL sürümü

# 2. Docker Desktop indir ve kur
# https://www.docker.com/products/docker-desktop/
# veya winget ile:
winget install Docker.DockerDesktop

# 3. Kurulum sonrası bilgisayarı yeniden başlat (restart required)

# 4. Docker Desktop ayarları (Settings):
# ✅ General > Use WSL 2 based engine
# ✅ Resources > WSL Integration > Ubuntu aktif et

# 5. Doğrula (verify)
docker --version
docker compose version
docker run hello-world

Docker Desktop olmadan (WSL 2 içinde Docker Engine):

bash
# WSL 2 Ubuntu terminalinde (inside WSL 2 Ubuntu):
# Yukarıdaki Ubuntu kurulum adımlarını aynen uygula
# Docker Desktop gerektirmez, ücretsiz ve hafif

Windows Docker sorun giderme:

SorunÇözüm
WSL 2 yokwsl --install çalıştır, BIOS'ta Virtualization aktif et
Docker Desktop açılmıyorHyper-V ve WSL 2 aktif mi kontrol et
Port çakışmasınetstat -ano | findstr :3306 ile hangi process kullanıyor bul
Yavaş performansWSL 2 backend kullan, dosyaları WSL içinde tut (/home/ altında)

macOS

bash
# Yöntem 1: Docker Desktop (önerilen / recommended)
brew install --cask docker
# Docker Desktop uygulamasını aç ve "Start" butonuna bas

# Yöntem 2: Homebrew ile CLI only (Colima — hafif alternatif)
brew install docker docker-compose colima
colima start                    # Hafif VM başlat
docker run hello-world          # Test et
# colima stop                   # Durdur

# Doğrula (verify)
docker --version
docker compose version

macOS Docker sorun giderme:

SorunÇözüm
Docker Desktop çok RAM kullanıyorSettings > Resources > Memory limiti düşür veya Colima kullan
docker: command not foundDocker Desktop çalışıyor mu kontrol et veya PATH'e ekle
Dosya paylaşımı yavaşSettings > Resources > File sharing > VirtioFS kullan

Docker Compose Kurulumu

Docker Compose artık Docker Engine ile birlikte geliyor (docker compose — tire yok). Eski docker-compose (tireli) ayrı kurulum gerektiriyordu.

bash
# Yeni yol (v2 — plugin olarak gelir):
docker compose version    # v2.x.x

# Eğer gelmiyorsa:
sudo apt-get install docker-compose-plugin

# Eski yol (v1 — artık önerilmiyor):
# sudo apt install docker-compose    # ESKI, kullanma
Eski (v1)Yeni (v2)
docker-compose updocker compose up
docker-compose downdocker compose down
docker-compose builddocker compose build
Ayrı binaryDocker plugin'i

Kurulum Hızlı Referans (Quick Reference)

PlatformKomut / YöntemDocker Compose
Ubuntuapt (resmi repo)Plugin olarak gelir
WindowsDocker Desktop veya WSL 2Desktop ile gelir
macOSDocker Desktop veya ColimaDesktop/brew ile gelir
Arch Linuxsudo pacman -S docker docker-composeAyrı paket
Fedorasudo dnf install docker-cePlugin olarak gelir

📦 Temel Kavramlar (Core Concepts)

  • Image: Uygulamanin read-only sablonu (blueprint). Dockerfile'dan olusturulur.
  • Container: Image'den calistirilan instance. Yazilabilir katman (writable layer) eklenir.
  • Dockerfile: Image olusturmak için talimat dosyasi (instruction file).
  • Docker Compose: Birden fazla container'i tanimlayip yonetme araci (multi-container orchestration).
  • Volume: Kalici veri saklama (persistent data storage).
  • Network: Container'lar arasi iletisim (inter-container communication).
  • Registry: Image'lerin depolandigi yer (Docker Hub, private registry).

⚡ Temel Komutlar

Container Yönetimi (Container Management)

KomutAçıklama (Description)Örnek (Example)
docker runYeni container oluştur ve çalıştırdocker run -d -p 8080:80 nginx
docker psCalisan container'lari listeledocker ps -a (tumunu göster)
docker stopContainer'i durdurdocker stop my_container
docker startDurmus container'i baslatdocker start my_container
docker restartContainer'i yeniden baslatdocker restart my_container
docker rmContainer'i sildocker rm -f my_container
docker execCalisan container'da komut çalıştırdocker exec -it app bash
docker logsContainer loglarini gösterdocker logs -f --tail 100 app
docker inspectDetayli bilgi al (JSON)docker inspect my_container
docker statsCanli kaynak kullanimidocker stats
docker topContainer icindeki process'lerdocker top my_container
docker cpDosya kopyala (host↔container)docker cp app:/var/log/app.log .

Image Yönetimi (Image Management)

KomutAçıklamaÖrnek
docker buildDockerfile'dan image oluşturdocker build -t myapp:1.0 .
docker imagesYerel image'leri listeledocker images
docker pullRegistry'den image indirdocker pull node:20-alpine
docker pushRegistry'ye image yükledocker push myuser/myapp:1.0
docker rmiImage sildocker rmi myapp:1.0
docker tagImage'e tag ekledocker tag myapp myuser/myapp:latest
docker historyImage katmanlarini gösterdocker history nginx

Temizlik Komutları (Cleanup)

bash
# Durmus container'lari sil (remove stopped containers)
docker container prune

# Kullanilmayan image'leri sil (remove dangling images)
docker image prune

# Kullanilmayan volume'lari sil (remove unused volumes)
docker volume prune

# Hepsini temizle (remove all unused data)
docker system prune -a --volumes

# Disk kullanimini goster (show disk usage)
docker system df

docker run Önemli Flag'leri

bash
# Arka planda calistir (detached mode)
docker run -d nginx

# Port yonlendirme (port mapping) — host:container
docker run -d -p 3000:3000 myapp

# Isim ver (name the container)
docker run -d --name my_nginx nginx

# Ortam degiskeni (environment variable)
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql:8

# Volume bagla (mount volume)
docker run -d -v mydata:/var/lib/mysql mysql:8

# Bind mount (host dizinini bagla)
docker run -d -v $(pwd)/src:/app/src myapp

# Otomatik yeniden baslat (restart policy)
docker run -d --restart unless-stopped nginx

# Bellek limiti (memory limit)
docker run -d --memory=512m myapp

# CPU limiti
docker run -d --cpus=1.5 myapp

# Ag belirt (specify network)
docker run -d --network my_network myapp

# Interaktif terminal (interactive shell)
docker run -it ubuntu bash

# Container kapandiginda sil (remove on exit)
docker run --rm -it alpine sh

📄 Dockerfile

Temel Komutlar (Instructions)

dockerfile
# Base image sec (select base image)
FROM node:20-alpine

# Metadata ekle
LABEL maintainer="fahri@example.com"
LABEL description="My Node.js Application"

# Build-time arguman (build argument)
ARG NODE_ENV=production
ARG APP_VERSION=1.0.0

# Ortam degiskeni (environment variable — runtime'da da gecerli)
ENV NODE_ENV=${NODE_ENV}
ENV PORT=3000

# Calisma dizini (working directory)
WORKDIR /app

# Dosya kopyala (copy files)
COPY package*.json ./

# Komut calistir (run command — build sirasinda)
RUN npm ci --only=production

# Uygulama kodunu kopyala
COPY . .

# Port bildir (declare port — documentation amacli)
EXPOSE 3000

# Saglik kontrolu (health check)
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# Calistirma komutu (default command)
CMD ["node", "server.js"]

FROM vs CMD vs ENTRYPOINT

dockerfile
# CMD — Varsayilan komut, docker run ile override edilebilir
CMD ["node", "server.js"]
# docker run myapp node other.js  → other.js calisir

# ENTRYPOINT — Sabit komut, override edilmez (arguman eklenir)
ENTRYPOINT ["node"]
CMD ["server.js"]
# docker run myapp other.js  → node other.js calisir

# Exec form (onerilen — recommended)
CMD ["node", "server.js"]

# Shell form (shell uzerinden calisir, signal handling sorunlu olabilir)
CMD node server.js

COPY vs ADD

dockerfile
# COPY — Basit dosya kopyalama (tercih edin — preferred)
COPY . .
COPY --chown=node:node package.json ./

# ADD — Ekstra ozellikler: URL'den indirme, tar otomatik acma
ADD https://example.com/file.tar.gz /tmp/
ADD archive.tar.gz /app/
# ⚠️ Genelde COPY kullanin, ADD sadece tar acma gerektiginde

RUN — Layer Optimizasyonu

dockerfile
# ❌ Kotu — Her RUN yeni layer olusturur (each RUN creates a new layer)
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN rm -rf /var/lib/apt/lists/*

# ✅ Iyi — Tek layer, daha kucuk image
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
      curl \
      git \
    && rm -rf /var/lib/apt/lists/*

.dockerignore

# Git
.git
.gitignore

# Dependencies
node_modules
vendor

# Environment
.env
.env.local
.env.*.local

# IDE
.vscode
.idea
*.swp

# OS
.DS_Store
Thumbs.db

# Build / Test
dist
build
coverage
*.log

# Docker
Dockerfile
docker-compose*.yml
.dockerignore

🐙 Docker Compose

Temel Yapi (Basic Structure)

yaml
# docker-compose.yml
version: "3.8"  # Compose file version (3.8+ onerilir)

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        NODE_ENV: production
    image: myapp:latest
    container_name: myapp
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=db
    env_file:
      - .env
    volumes:
      - ./src:/app/src
      - node_modules:/app/node_modules
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    image: mysql:8
    container_name: mydb
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "3306:3306"
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  db_data:
    driver: local
  node_modules:

networks:
  app-network:
    driver: bridge

Docker Compose Komutları

bash
# Tum servisleri baslat (start all services)
docker compose up -d

# Build edip baslat (build and start)
docker compose up -d --build

# Loglari takip et (follow logs)
docker compose logs -f app

# Belirli servisi yeniden baslat
docker compose restart app

# Servisleri durdur ve kaldir (stop and remove)
docker compose down

# Volume'larla birlikte kaldir (remove with volumes)
docker compose down -v

# Servis durumlarini goster
docker compose ps

# Belirli bir serviste komut calistir
docker compose exec app bash

# Tek seferlik komut calistir (one-off command)
docker compose run --rm app npm test

# Sadece belirli servisi baslat (start specific service)
docker compose up -d db

# Konfigurasyonu dogrula (validate config)
docker compose config

depends_on ve Servis Sirasi

yaml
services:
  app:
    depends_on:
      db:
        condition: service_healthy    # DB saglikli olana kadar bekle
      redis:
        condition: service_started    # Redis baslayana kadar bekle
      migration:
        condition: service_completed_successfully  # Migration bitene kadar bekle

  migration:
    build: .
    command: npm run migrate
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine

Docker Compose İleri Seviye

Profiles -- Ortama Gore Servis Secimi

Profiles ile bazi servisleri sadece belirli profillerde calistirabilirsiniz. Ornegin debug araçları sadece development ortaminda aktif olsun:

yaml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    # profil belirtilmezse her zaman calisir

  db:
    image: postgres:16
    # profil belirtilmezse her zaman calisir

  adminer:
    image: adminer
    ports:
      - "8080:8080"
    profiles:
      - debug       # sadece debug profili ile baslar

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

  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    profiles:
      - monitoring  # sadece monitoring profili ile baslar
bash
# Sadece profil-siz servisleri baslat
docker compose up -d

# debug profilindeki servisleri de baslat
docker compose --profile debug up -d

# birden fazla profil
docker compose --profile debug --profile monitoring up -d

Override Dosyalari

Docker Compose override dosyaları ile ortama ozel yapılandırma yapabilirsiniz. docker-compose.override.yml dosyasi otomatik olarak yuklenir:

yaml
# docker-compose.yml (base -- production)
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    restart: always
yaml
# docker-compose.override.yml (otomatik yuklenir -- development)
services:
  app:
    build:
      target: development
    volumes:
      - ./src:/app/src
    environment:
      - NODE_ENV=development
      - DEBUG=true
    command: npm run dev
bash
# development: base + override otomatik birlesir
docker compose up -d

# production: sadece base + prod dosyasini kullan
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# staging ortami
docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d

env_file ile Ortam Degiskeni Yönetimi

yaml
services:
  app:
    env_file:
      - .env                  # varsayilan
      - .env.local            # yerel override (gitignore'da)
      - .env.${ENV:-dev}      # ortama gore: .env.dev, .env.prod
    environment:
      - APP_VERSION=1.0.0     # env_file'i override eder
bash
# .env dosyasi ornegi
DB_HOST=db
DB_PORT=5432
DB_NAME=myapp
DB_USER=postgres
DB_PASSWORD=secret

YAML Anchor ve Alias (Tekrar Onleme)

Compose dosyalarinda tekrarlanan yapilandirmalari anchor/alias ile ortadan kaldirabilirsiniz:

yaml
# x- prefiksi ile extension field tanimla (Compose tarafindan ignore edilir)
x-common-env: &common-env
  TZ: Europe/Istanbul
  LANG: tr_TR.UTF-8

x-logging: &default-logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

x-healthcheck-defaults: &healthcheck-defaults
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 15s

services:
  app:
    build: .
    environment:
      <<: *common-env          # anchor'u kullan
      NODE_ENV: production
    logging: *default-logging  # logging yapilandirmasi
    healthcheck:
      <<: *healthcheck-defaults
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]

  worker:
    build: .
    command: npm run worker
    environment:
      <<: *common-env          # ayni env tekrar kullanilir
      WORKER_CONCURRENCY: "4"
    logging: *default-logging

  scheduler:
    build: .
    command: npm run scheduler
    environment:
      <<: *common-env
    logging: *default-logging

💾 Volumes & Networking

Volume Turleri (Volume Types)

1. Named Volumes (Isimli Volume'lar)

bash
# Volume olustur
docker volume create mydata

# Volume listesi
docker volume ls

# Volume detayi
docker volume inspect mydata

# Kullan
docker run -d -v mydata:/var/lib/mysql mysql:8
yaml
# docker-compose.yml icinde
services:
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
    driver: local

💡 Named volume'lar Docker tarafindan yonetilir, container silinse bile veri kalir (data persists).

2. Bind Mounts (Host Dizin Baglama)

bash
# Host dizinini container'a bagla
docker run -d -v /home/fahri/project/src:/app/src myapp

# Sadece okunabilir (read-only)
docker run -d -v $(pwd)/config:/app/config:ro myapp
yaml
# docker-compose.yml — development icin ideal
services:
  app:
    volumes:
      - ./src:/app/src           # Kaynak kodu (source code)
      - ./config:/app/config:ro  # Sadece okunur (read-only)

💡 Bind mount'lar development'ta hot-reload için cok kullanisli. Production'da named volume tercih edin.

3. tmpfs Mounts (Gecici Bellek)

bash
# RAM'de gecici storage (temporary in-memory storage)
docker run -d --tmpfs /tmp:rw,size=100m myapp

Volume Karşılaştırma (Comparison)

ÖzellikNamed VolumeBind Mounttmpfs
Konum (Location)Docker yonetirHost path belirtilirRAM
Veri kaliciligi (Persistence)EvetEvetHayir
Backup kolayligiKolayKolayYok
PerformansIyiHost FS'ye bagliEn hızlı
Kullanım alaniProduction dataDev source codeSecrets, cache

🌐 Networking

Network Turleri (Network Types)

TurAçıklamaKullanım
bridgeVarsayilan, izole agTek host uzerinde container iletisimi
hostHost agini dogrudan kullanPerformans gerektiginde
overlayBirden fazla host arasi agDocker Swarm / cluster
noneAg baglantisi yokIzole islemler
macvlanContainer'a fiziksel MAC adresiLegacy uygulamalar

Network Komutları

bash
# Ag olustur (create network)
docker network create my_network

# Belirli subnet ile olustur
docker network create --subnet=172.20.0.0/16 my_network

# Aglari listele
docker network ls

# Ag detayi (hangi container'lar bagli)
docker network inspect my_network

# Container'i aga bagla (connect)
docker network connect my_network my_container

# Container'i agdan cikar (disconnect)
docker network disconnect my_network my_container

# Agi sil
docker network rm my_network

Port Mapping (Port Yonlendirme)

bash
# Tek port — host:container
docker run -d -p 8080:80 nginx

# Birden fazla port
docker run -d -p 8080:80 -p 8443:443 nginx

# Belirli IP'ye bagla (bind to specific IP)
docker run -d -p 127.0.0.1:8080:80 nginx

# Rastgele host port (random host port)
docker run -d -p 80 nginx
# docker ps ile hangi port atandigini gorebilirsin

# UDP port
docker run -d -p 53:53/udp dns-server

Container'lar Arasi İletişim

yaml
# Ayni network'teki container'lar birbirini isimle cozumler (DNS resolution)
services:
  app:
    networks:
      - backend
    environment:
      - DB_HOST=db         # "db" servis adi hostname olarak kullanilir
      - REDIS_HOST=redis

  db:
    image: mysql:8
    networks:
      - backend

  redis:
    image: redis:7-alpine
    networks:
      - backend

networks:
  backend:
    driver: bridge

Custom Network ve DNS Resolution

Ayni bridge network'teki container'lar Docker'in dahili DNS servisi sayesinde birbirini servis adiyla bulur. Farkli network'lerdeki container'lar birbirine erisemez (izolasyon):

yaml
services:
  frontend:
    build: ./frontend
    networks:
      - frontend-net
      - backend-net    # hem frontend hem backend aginda

  api:
    build: ./api
    networks:
      - backend-net    # sadece backend aginda
      - db-net

  db:
    image: postgres:16
    networks:
      - db-net         # sadece db aginda -- frontend erisemez

networks:
  frontend-net:
    driver: bridge
  backend-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16
  db-net:
    driver: bridge
    internal: true     # dis dunyaya erisim yok
bash
# Container icinden DNS cozumlemesini test et
docker exec -it api ping db
docker exec -it api nslookup db

# Ayni network'teki container'lari gor
docker network inspect backend-net --format '{{range .Containers}}{{.Name}} {{end}}'

🛠️ Pratik Ornekler

1. Laravel + MySQL + Redis + Nginx

Proje Yapisi

laravel-docker/
├── docker/
│   ├── nginx/
│   │   └── default.conf
│   └── php/
│       └── Dockerfile
├── src/                    # Laravel kaynak kodu
├── docker-compose.yml
└── .env

docker-compose.yml

yaml
version: "3.8"

services:
  # PHP-FPM (Laravel)
  app:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    container_name: laravel_app
    working_dir: /var/www/html
    volumes:
      - ./src:/var/www/html
      - ./docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=db
      - DB_PORT=3306
      - DB_DATABASE=${DB_DATABASE:-laravel}
      - DB_USERNAME=${DB_USERNAME:-laravel}
      - DB_PASSWORD=${DB_PASSWORD:-secret}
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - CACHE_DRIVER=redis
      - SESSION_DRIVER=redis
      - QUEUE_CONNECTION=redis
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - laravel-network

  # Nginx
  nginx:
    image: nginx:1.25-alpine
    container_name: laravel_nginx
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - laravel-network

  # MySQL
  db:
    image: mysql:8
    container_name: laravel_db
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootsecret}
      MYSQL_DATABASE: ${DB_DATABASE:-laravel}
      MYSQL_USER: ${DB_USERNAME:-laravel}
      MYSQL_PASSWORD: ${DB_PASSWORD:-secret}
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - laravel-network

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

  # Queue Worker
  queue:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    container_name: laravel_queue
    working_dir: /var/www/html
    command: php artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
    volumes:
      - ./src:/var/www/html
    depends_on:
      - app
      - redis
    networks:
      - laravel-network
    restart: unless-stopped

volumes:
  mysql_data:
  redis_data:

networks:
  laravel-network:
    driver: bridge

docker/php/Dockerfile

dockerfile
FROM php:8.3-fpm-alpine

# Sistem bagimliliklari (system dependencies)
RUN apk add --no-cache \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev \
    libzip-dev \
    zip \
    unzip \
    git \
    curl

# PHP eklentileri (extensions)
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) \
      pdo_mysql \
      gd \
      zip \
      bcmath \
      opcache

# Redis eklentisi
RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
    && pecl install redis \
    && docker-php-ext-enable redis \
    && apk del .build-deps

# Composer kur
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Calisma dizini
WORKDIR /var/www/html

# Kullanici olustur (non-root user)
RUN addgroup -g 1000 -S www && \
    adduser -u 1000 -S www -G www

USER www

EXPOSE 9000
CMD ["php-fpm"]

docker/nginx/default.conf

nginx
server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

2. Node.js/Express + MongoDB

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

services:
  api:
    build: .
    container_name: express_api
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - MONGO_URI=mongodb://mongo:27017/myapp
      - JWT_SECRET=${JWT_SECRET:-supersecretkey}
    volumes:
      - ./src:/app/src
      - ./package.json:/app/package.json
    depends_on:
      mongo:
        condition: service_healthy
    networks:
      - app-net
    command: npm run dev

  mongo:
    image: mongo:7
    container_name: mongodb
    ports:
      - "27017:27017"
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_USER:-admin}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASS:-secret}
      MONGO_INITDB_DATABASE: myapp
    volumes:
      - mongo_data:/data/db
      - ./docker/mongo/init.js:/docker-entrypoint-initdb.d/init.js:ro
    healthcheck:
      test: echo 'db.runCommand("ping").ok' | mongosh --quiet
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-net

  mongo-express:
    image: mongo-express
    container_name: mongo_ui
    ports:
      - "8081:8081"
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: ${MONGO_USER:-admin}
      ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGO_PASS:-secret}
      ME_CONFIG_MONGODB_URL: mongodb://${MONGO_USER:-admin}:${MONGO_PASS:-secret}@mongo:27017/
    depends_on:
      - mongo
    networks:
      - app-net

volumes:
  mongo_data:

networks:
  app-net:
    driver: bridge

Node.js Dockerfile

dockerfile
FROM node:20-alpine

WORKDIR /app

# Bagimliliklari once kopyala (dependency caching)
COPY package*.json ./
RUN npm ci

# Uygulama kodunu kopyala
COPY . .

EXPOSE 3000

# Development modunda nodemon ile calistir
CMD ["npm", "run", "dev"]

3. React Development Container

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

services:
  react-app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    container_name: react_dev
    ports:
      - "5173:5173"   # Vite default port
    volumes:
      - ./src:/app/src
      - ./public:/app/public
      - ./index.html:/app/index.html
      - ./vite.config.ts:/app/vite.config.ts
    environment:
      - VITE_API_URL=http://localhost:3000/api
      - CHOKIDAR_USEPOLLING=true  # Docker'da file watching icin
    stdin_open: true
    tty: true

Dockerfile.dev

dockerfile
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

EXPOSE 5173

# Vite dev server — host 0.0.0.0 Docker'da gerekli
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]

4. Python Flask + PostgreSQL

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

services:
  web:
    build: .
    container_name: flask_app
    ports:
      - "5000:5000"
    environment:
      - FLASK_APP=app.py
      - FLASK_ENV=development
      - DATABASE_URL=postgresql://postgres:secret@db:5432/flaskapp
      - SECRET_KEY=${SECRET_KEY:-dev-secret-key}
    volumes:
      - ./app:/app/app
      - ./migrations:/app/migrations
    depends_on:
      db:
        condition: service_healthy
    networks:
      - flask-net
    command: flask run --host=0.0.0.0 --debug

  db:
    image: postgres:16-alpine
    container_name: flask_db
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: flaskapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - flask-net

  pgadmin:
    image: dpage/pgadmin4
    container_name: flask_pgadmin
    ports:
      - "5050:80"
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@admin.com
      PGADMIN_DEFAULT_PASSWORD: admin
    depends_on:
      - db
    networks:
      - flask-net

volumes:
  pgdata:

networks:
  flask-net:
    driver: bridge

Flask Dockerfile

dockerfile
FROM python:3.12-slim

WORKDIR /app

# Sistem bagimliliklari
RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc libpq-dev && \
    rm -rf /var/lib/apt/lists/*

# Python bagimliliklari (cache layer)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["flask", "run", "--host=0.0.0.0"]

🏗️ Multi-Stage Builds

Multi-stage build ile development araclarini (compiler, dev dependencies) final image'dan cikararak cok daha küçük production image'lar olusturabilirsiniz. Use multi-stage builds to exclude dev tools from the final image, resulting in much smaller production images.

Node.js Production Dockerfile

dockerfile
# ============================================
# Stage 1: Dependencies (Bagimliliklar)
# ============================================
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# ============================================
# Stage 2: Build (Derleme)
# ============================================
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ============================================
# Stage 3: Production (Final Image)
# ============================================
FROM node:20-alpine AS runner
WORKDIR /app

# Guvenlik: non-root kullanici
RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 appuser

# Sadece gerekli dosyalari kopyala
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./package.json

USER appuser

EXPOSE 3000

ENV NODE_ENV=production

CMD ["node", "dist/server.js"]

# Final image boyutu: ~80MB (vs ~400MB tek stage ile)

React Production Build (Nginx ile)

dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Serve with Nginx
FROM nginx:1.25-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

# Final image boyutu: ~25MB

Laravel Production Dockerfile

dockerfile
# ============================================
# Stage 1: Composer Dependencies
# ============================================
FROM composer:latest AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install \
    --no-dev \
    --no-scripts \
    --no-autoloader \
    --prefer-dist

COPY . .
RUN composer dump-autoload --optimize --no-dev

# ============================================
# Stage 2: Frontend Assets
# ============================================
FROM node:20-alpine AS frontend
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ============================================
# Stage 3: Production Image
# ============================================
FROM php:8.3-fpm-alpine

RUN apk add --no-cache \
    libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install pdo_mysql gd zip bcmath opcache

# OPcache ayarlari
RUN echo "opcache.enable=1" >> /usr/local/etc/php/conf.d/opcache.ini && \
    echo "opcache.memory_consumption=128" >> /usr/local/etc/php/conf.d/opcache.ini && \
    echo "opcache.max_accelerated_files=10000" >> /usr/local/etc/php/conf.d/opcache.ini && \
    echo "opcache.validate_timestamps=0" >> /usr/local/etc/php/conf.d/opcache.ini

WORKDIR /var/www/html

# Vendor ve frontend asset'lerini kopyala
COPY --from=vendor /app/vendor ./vendor
COPY --from=frontend /app/public/build ./public/build

# Uygulama kodunu kopyala
COPY . .

# Storage ve cache izinleri
RUN chown -R www-data:www-data storage bootstrap/cache && \
    chmod -R 775 storage bootstrap/cache

# Cache olustur
RUN php artisan config:cache && \
    php artisan route:cache && \
    php artisan view:cache

USER www-data

EXPOSE 9000
CMD ["php-fpm"]

Python Production Dockerfile

dockerfile
# Stage 1: Build
FROM python:3.12-slim AS builder
WORKDIR /app

RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc libpq-dev && \
    rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# Stage 2: Production
FROM python:3.12-slim
WORKDIR /app

RUN apt-get update && \
    apt-get install -y --no-install-recommends libpq5 && \
    rm -rf /var/lib/apt/lists/*

COPY --from=builder /install /usr/local

RUN useradd --create-home appuser
USER appuser

COPY . .

EXPOSE 5000

CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:create_app()"]

📦 Docker Registry

Docker Hub

bash
# Giris yap (login)
docker login
# Kullanici adi ve sifre / access token sor

# Image'i tag'le (tag for push)
docker tag myapp:latest fahriaydin/myapp:1.0.0
docker tag myapp:latest fahriaydin/myapp:latest

# Push et (upload)
docker push fahriaydin/myapp:1.0.0
docker push fahriaydin/myapp:latest

# Pull et (download)
docker pull fahriaydin/myapp:1.0.0

# Docker Hub'da arama
docker search nginx

Private Registry (Self-Hosted)

bash
# Basit registry calistir
docker run -d -p 5000:5000 --name registry \
  -v registry_data:/var/lib/registry \
  registry:2

# Image'i private registry'ye push et
docker tag myapp:latest localhost:5000/myapp:1.0.0
docker push localhost:5000/myapp:1.0.0

# Baska bir makineden pull et
docker pull my-server.com:5000/myapp:1.0.0

GitHub Container Registry (ghcr.io)

bash
# GitHub token ile giris
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin

# Push
docker tag myapp:latest ghcr.io/fahriaydin/myapp:1.0.0
docker push ghcr.io/fahriaydin/myapp:1.0.0

Tag Stratejileri (Tagging Strategies)

bash
# Semantic versioning (onerilen — recommended)
docker tag myapp fahriaydin/myapp:1.0.0
docker tag myapp fahriaydin/myapp:1.0
docker tag myapp fahriaydin/myapp:1
docker tag myapp fahriaydin/myapp:latest

# Git commit hash
docker tag myapp fahriaydin/myapp:$(git rev-parse --short HEAD)

# Tarih bazli (date-based)
docker tag myapp fahriaydin/myapp:$(date +%Y%m%d-%H%M%S)

🏭 Production Best Practices

Base Image Secimi -- Karşılaştırma Tablosu

ÖzellikAlpineSlim (Debian)Distroless
BoyutEn küçük (~5MB base)Orta (~80MB base)Küçük (~20MB base)
Paket yoneticisiapkaptYok
Shellash (varsayılan)bashYok
Güvenlik yuzey alaniDüşükOrtaEn düşük
Debug kolayligiOrtaIyiZor (shell yok)
glibc/muslmuslglibcglibc
UyumlulukBazi native modullerde sorunGenis uyumlulukSınırlı
Kullanım alaniGenel üretimNative bağımlılık gerektigindeMaksimum güvenlik
dockerfile
# Alpine -- en yaygin tercih
FROM node:20-alpine          # ~135MB
FROM python:3.12-alpine      # ~50MB

# Slim -- glibc gerektiginde
FROM node:20-slim            # ~200MB
FROM python:3.12-slim        # ~125MB

# Distroless -- maksimum guvenlik
FROM gcr.io/distroless/nodejs20-debian12   # ~130MB
FROM gcr.io/distroless/python3-debian12    # ~50MB

Image Boyut Kucultme Kontrol Listesi

  1. Multi-stage build kullan (dev araçları final image'da olmaz)
  2. Alpine veya slim base image seç
  3. .dockerignore ile gereksiz dosyaları disla
  4. --no-install-recommends (apt) veya --no-cache (apk) kullan
  5. Tek RUN komutunda birlestir ve gecici dosyaları temizle
  6. npm ci --only=production veya pip install --no-cache-dir kullan
  7. COPY ile sadece gerekli dosyaları kopyala (COPY . . yerine spesifik)
bash
# Image boyutunu kontrol et
docker images myapp
docker history myapp:latest

# Dive ile katman analizi (opsiyonel arac)
# https://github.com/wagoodman/dive
dive myapp:latest

Layer Caching Stratejisi

Dockerfile'da az degisen katmanlari uste, sik degisenleri alta yerlestirin:

dockerfile
FROM node:20-alpine
WORKDIR /app

## 1. Sistem bagimliliklari (nadiren degisir)
RUN apk add --no-cache curl

## 2. Paket dosyalari (ara sira degisir)
COPY package*.json ./
RUN npm ci --only=production

## 3. Uygulama kodu (sik degisir -- en alta)
COPY . .

CMD ["node", "server.js"]

🩺 Health Check ve Monitoring

HEALTHCHECK Instruction

Dockerfile icinde HEALTHCHECK tanimlanarak Docker'in container sagligini otomatik kontrol etmesi saglanir:

dockerfile
# HTTP endpoint kontrolu
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# TCP port kontrolu (curl yoksa)
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD nc -z localhost 3000 || exit 1

# Veritabani kontrolu
HEALTHCHECK --interval=10s --timeout=5s --retries=5 \
  CMD pg_isready -U postgres || exit 1

# Dosya bazli kontrol
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD test -f /tmp/healthy || exit 1

HEALTHCHECK parametreleri:

ParametreVarsayilanAçıklama
--interval30sKontroller arasi bekleme süresi
--timeout30sTek bir kontrol için maksimum sure
--start-period0sBaslangic bekleme süresi (bu surede basarisizlik sayilmaz)
--retries3Kac basarisiz denemeden sonra unhealthy sayilacagi
bash
# Container saglik durumunu kontrol et
docker inspect --format='{{.State.Health.Status}}' my_container

# Saglik kontrolu gecmisini gor
docker inspect --format='{{json .State.Health}}' my_container | jq

Restart Policies

PolicyAçıklamaKullanım
noYeniden başlatma (varsayılan)Test / gecici container'lar
on-failureSadece hata ile ciktiginda yeniden baslatBatch isler
on-failure:5Maksimum 5 deneme ile yeniden baslatSınırlı yeniden deneme
alwaysHer zaman yeniden baslat (manuel stop haric)Kritik servisler
unless-stoppedalways gibi ama Docker daemon yeniden basladiginda durmus kalirGenel production
yaml
# docker-compose.yml
services:
  app:
    restart: unless-stopped    # onerilen production ayari

  worker:
    restart: on-failure
    deploy:
      restart_policy:
        condition: on-failure
        max_attempts: 5
        delay: 10s
        window: 60s

Resource Limits (Kaynak Sinirlandirma)

yaml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: "2.0"          # maksimum 2 CPU
          memory: 512M         # maksimum 512MB RAM
        reservations:
          cpus: "0.5"          # garanti 0.5 CPU
          memory: 256M         # garanti 256MB RAM
bash
# Komut satirindan kaynak sinirlandirma
docker run -d \
  --memory=512m \
  --memory-swap=1g \
  --cpus=1.5 \
  --pids-limit=100 \
  myapp

# Canli kaynak kullanimini izle
docker stats
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"

Docker Logs ve Log Drivers

bash
# Temel log komutlari
docker logs my_container              # Tum loglar
docker logs -f my_container           # Canli takip
docker logs --tail 50 my_container    # Son 50 satir
docker logs --since 1h my_container   # Son 1 saat
docker logs --since 2024-01-01T00:00:00 my_container  # Belirli tarihten itibaren
docker logs -f --until 10m my_container  # Son 10 dakikaya kadar

Desteklenen log driver'lar:

DriverAçıklamaKullanım
json-fileVarsayilan, JSON formatinda dosyaya yazarGenel kullanım
localOptimize edilmis yerel depolamajson-file alternatifi
syslogSyslog daemon'a gonderirLinux sunucular
journaldsystemd journal'a gonderirsystemd tabanli sunucular
fluentdFluentd collector'a gonderirMerkezi loglama
awslogsAmazon CloudWatch'a gonderirAWS ortami
gcplogsGoogle Cloud Logging'e gonderirGCP ortami
noneLog tutmazHassas veri işleme
yaml
# docker-compose.yml -- log yapilandirmasi
services:
  app:
    logging:
      driver: json-file
      options:
        max-size: "10m"      # dosya basina max boyut
        max-file: "5"        # max dosya sayisi
        compress: "true"     # eski dosyalari sikistir
        tag: "{{.Name}}/{{.ID}}"

🔐 Güvenlik

Non-Root Kullanici

Container'lari root olarak calistirmak güvenlik riski olusturur. Her zaman non-root kullanici kullanin:

dockerfile
# Alpine
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser

# Debian/Ubuntu
RUN groupadd --system --gid 1001 appgroup && \
    useradd --system --uid 1001 --gid appgroup --create-home appuser

# Dosya sahipligini ayarla
COPY --chown=appuser:appgroup . .
WORKDIR /app
RUN chown -R appuser:appgroup /app

USER appuser

Image Tarama (Vulnerability Scanning)

bash
# Docker Scout (Docker Desktop ile gelir)
docker scout cves myapp:latest
docker scout quickview myapp:latest

# Trivy (acik kaynak, kapsamli)
trivy image myapp:latest
trivy image --severity HIGH,CRITICAL myapp:latest
trivy image --exit-code 1 myapp:latest   # CI/CD'de basarisiz yap

# Snyk
snyk container test myapp:latest
snyk container monitor myapp:latest       # surekli izleme
yaml
# CI/CD pipeline icinde tarama ornegi (GitHub Actions)
# .github/workflows/scan.yml
# - name: Trivy scan
#   uses: aquasecurity/trivy-action@master
#   with:
#     image-ref: myapp:latest
#     severity: HIGH,CRITICAL
#     exit-code: 1

Docker Secrets

bash
# Swarm mode'da secret olustur
echo "my-secret-password" | docker secret create db_password -
docker secret create ssl_cert ./cert.pem

# Serviste kullan
docker service create \
  --secret db_password \
  --secret ssl_cert \
  myapp
yaml
# docker-compose.yml ile secrets (Swarm veya Compose v2)
services:
  app:
    secrets:
      - db_password
      - api_key
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt    # development
  api_key:
    external: true                      # production (onceden olusturulmus)

Read-Only Filesystem

yaml
services:
  app:
    read_only: true           # root filesystem read-only
    tmpfs:
      - /tmp                  # gecici dosyalar icin yazilabilir alan
      - /var/run              # PID dosyalari icin
    volumes:
      - app_data:/app/data    # sadece gerekli dizinler yazilabilir

Güvenlik Sertlestirme

yaml
services:
  app:
    security_opt:
      - no-new-privileges:true    # privilege escalation onle
    cap_drop:
      - ALL                        # tum Linux capability'leri kaldir
    cap_add:
      - NET_BIND_SERVICE           # sadece gerekli olanlari ekle
    read_only: true
    tmpfs:
      - /tmp
bash
# Docker Content Trust -- image imzalama
export DOCKER_CONTENT_TRUST=1
docker push myapp:latest       # otomatik imzalar
docker pull myapp:latest       # imzali degilse reddeder

# Container'i guvenlik opsiyonlariyla calistir
docker run -d \
  --read-only \
  --security-opt no-new-privileges:true \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --tmpfs /tmp:rw,noexec,nosuid \
  --user 1001:1001 \
  myapp

Linux Capabilities Referansi

CapabilityAçıklamaGerekli mi?
NET_BIND_SERVICE1024 altindaki portlara bindWeb sunuculari
CHOWNDosya sahipligi değiştirmeNadiren
SETUID/SETGIDKullanici/grup değiştirmeNadiren
SYS_PTRACEProcess trace (debug)Sadece debug
NET_RAWRaw socket (ping vb.)Nadiren
MKNODOzel dosya oluşturmaHayir

Genel kural: cap_drop: ALL ile başla, sadece gereklileri cap_add ile ekle.


🔍 Debugging & Best Practices

Debugging Teknikleri

bash
# Container'a baglan (attach to running container)
docker exec -it my_container bash
docker exec -it my_container sh  # Alpine image'larda sh kullan

# Loglari incele (inspect logs)
docker logs my_container              # Tum loglar
docker logs -f my_container           # Canli takip (follow)
docker logs --tail 50 my_container    # Son 50 satir
docker logs --since 1h my_container   # Son 1 saat

# Container event'lerini izle
docker events

# Container process'lerini goster
docker top my_container

# Kaynak kullanimini izle (resource monitoring)
docker stats
docker stats my_container --no-stream  # Tek seferlik snapshot

# Container dosya sistemini incele
docker diff my_container  # Degisen dosyalari goster

# Cikis kodunu kontrol et (check exit code)
docker inspect my_container --format='{{.State.ExitCode}}'

# Network sorunlarini debug et
docker exec -it my_container ping db
docker exec -it my_container nslookup db
docker exec -it my_container curl -v http://api:3000/health

# Image katmanlarini incele
docker history myapp:latest
docker inspect myapp:latest

# Build sirasinda debug (build debug)
docker build --no-cache -t myapp . 2>&1 | tee build.log
docker build --progress=plain -t myapp .

Sik Karsilasilan Sorunlar (Common Issues)

bash
# "port is already allocated"
# Cozum: Portu kullanan process'i bul ve durdur
sudo lsof -i :8080
docker ps -a | grep 8080
docker stop <container_id>

# "no space left on device"
# Cozum: Docker temizligi
docker system prune -a --volumes
docker builder prune

# Container hemen kapaniyor (exits immediately)
# Cozum: Loglari kontrol et
docker logs my_container
# veya interaktif calistir
docker run -it myapp bash

# "permission denied" — Volume sorunlari
# Cozum: Dosya sahipligini kontrol et
docker exec -it my_container ls -la /app
# Dockerfile'da: RUN chown -R appuser:appuser /app

# Container'lar birbirini bulamiyor (DNS resolution)
# Cozum: Ayni network'te olduklarini kontrol et
docker network inspect my_network

Best Practices

1. Küçük Base Image Kullan (Use Small Base Images)

dockerfile
# Buyuk — ~900MB
FROM node:20

# Kucuk — ~130MB
FROM node:20-alpine

# Daha da kucuk (gerektiginde) — ~80MB
FROM node:20-slim

2. Layer Cache'i Optimize Et

dockerfile
# Kotu — Her kod degisikliginde npm install tekrar calisir
COPY . .
RUN npm ci

# Iyi — package.json degismezse cache kullanilir
COPY package*.json ./
RUN npm ci
COPY . .

3. Non-Root Kullanici (Security)

dockerfile
# Kullanici olustur ve gec
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser

# Dosya sahipligini ayarla
COPY --chown=appuser:appgroup . .

USER appuser

4. Saglik Kontrolu Ekle (Health Check)

dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

5. .dockerignore Kullan

Her zaman .dockerignore dosyasi oluştur (always create one). Build context boyutunu kucultur, build suresini azaltir.

6. Secrets Yönetimi (Secret Management)

dockerfile
# Kotu — Secret image layer'ina yazilir
ENV API_KEY=my-secret-key
COPY .env /app/.env

# Iyi — Runtime'da environment variable olarak ver
# docker run -e API_KEY=my-secret-key myapp

# Docker secrets (Swarm mode)
# docker secret create my_secret ./secret.txt
yaml
# docker-compose.yml ile environment
services:
  app:
    env_file:
      - .env    # .env dosyasi .gitignore'da olmali
    environment:
      - API_KEY  # Host'taki env variable'i gecir

7. Log Yönetimi (Log Management)

bash
# Log driver ayarla (set log driver)
docker run -d --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  myapp

# Container log boyutunu kontrol et
docker inspect --format='{{.LogPath}}' my_container
du -sh $(docker inspect --format='{{.LogPath}}' my_container)
yaml
# docker-compose.yml — tum servisler icin log limiti
services:
  app:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

8. Image Boyut Optimizasyonu (Image Size Optimization)

dockerfile
## 1. Multi-stage build kullan (yukaridaki orneklere bak)

## 2. Gereksiz dosyalari temizle
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*

## 3. Tek RUN komutu ile birlestir (combine into single RUN)
RUN apk add --no-cache curl && \
    curl -o /tmp/file.tar.gz https://example.com/file.tar.gz && \
    tar xzf /tmp/file.tar.gz -C /app && \
    rm /tmp/file.tar.gz

## 4. COPY ile sadece gerekli dosyalari kopyala
COPY package*.json ./
COPY src/ ./src/
COPY public/ ./public/
# COPY . .  yerine spesifik kopyalama

## 5. --no-cache-dir flag'ini kullan (Python)
RUN pip install --no-cache-dir -r requirements.txt

## 6. npm ci --only=production (Node.js)
RUN npm ci --only=production

📋 Sik Kullanilan Komutlar Tablosu (Quick Reference)

Container Islemleri

KomutAçıklama
docker run -d -p 80:80 --name web nginxNginx container baslat
docker psCalisan container'lari göster
docker ps -aTüm container'lari göster
docker stop webContainer'i durdur
docker start webContainer'i baslat
docker restart webYeniden baslat
docker rm -f webContainer'i zorla sil
docker exec -it web bashContainer'a baglan
docker logs -f webLoglari takip et
docker cp web:/etc/nginx/nginx.conf .Dosya kopyala
docker statsKaynak kullanimini göster

Image Islemleri

KomutAçıklama
docker build -t myapp:1.0 .Image oluştur
docker imagesImage listesi
docker pull node:20-alpineImage indir
docker push user/myapp:1.0Image yükle
docker rmi myapp:1.0Image sil
docker tag myapp user/myapp:latestImage tag'le
docker save -o backup.tar myappImage'i dosyaya kaydet
docker load -i backup.tarDosyadan image yükle

Docker Compose

KomutAçıklama
docker compose up -dServisleri baslat
docker compose up -d --buildBuild edip baslat
docker compose downServisleri durdur ve kaldir
docker compose down -vVolume'larla birlikte kaldir
docker compose psServis durumlari
docker compose logs -fTüm loglar
docker compose logs -f appBelirli servis loglari
docker compose exec app bashServise baglan
docker compose run --rm app npm testTek seferlik komut
docker compose pullImage'leri güncelle
docker compose configConfig doğrula

Volume & Network

KomutAçıklama
docker volume lsVolume listesi
docker volume create mydataVolume oluştur
docker volume inspect mydataVolume detayi
docker volume rm mydataVolume sil
docker volume pruneKullanilmayan volume'lari sil
docker network lsNetwork listesi
docker network create mynetNetwork oluştur
docker network inspect mynetNetwork detayi
docker network connect mynet webContainer'i aga bagla
docker network rm mynetNetwork sil

Temizlik & Bakim

KomutAçıklama
docker system dfDisk kullanimini göster
docker system pruneKullanilmayan her seyi sil
docker system prune -a --volumesAgresif temizlik
docker container pruneDurmus container'lari sil
docker image prune -aKullanilmayan image'leri sil
docker builder pruneBuild cache temizle

💡 Tips ve İpuçları

docker system prune -- Kapsamli Temizlik

bash
# Kullanilmayan container, network, image (dangling) temizle
docker system prune

# Tum kullanilmayan image'ler + volume'lar dahil
docker system prune -a --volumes

# Sadece 24 saatten eski olanlari temizle
docker system prune -a --filter "until=24h"

# Ne kadar alan kullanildigini gor
docker system df
docker system df -v   # detayli

Buildx ile Multi-Platform Build

Tek Dockerfile'dan farkli mimariler için image oluşturma:

bash
# Buildx builder olustur
docker buildx create --name multiarch --use

# AMD64 + ARM64 icin build ve push
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t myuser/myapp:latest \
  --push .

# Desteklenen platformlari listele
docker buildx ls

# Belirli platform icin yerel build
docker buildx build --platform linux/arm64 -t myapp:arm64 --load .

.env Dosyasi Yönetimi

bash
# .env.example olustur (git'e ekle -- sablonu paylas)
# DB_HOST=localhost
# DB_PORT=5432
# DB_PASSWORD=          # bos birak, herkes kendi degerini girer

# .env dosyasini .env.example'dan olustur
cp .env.example .env

# .env dosyasini .gitignore'a ekle
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env.*.local" >> .gitignore
yaml
# docker-compose.yml -- varsayilan deger belirle
services:
  app:
    environment:
      - DB_HOST=${DB_HOST:-localhost}
      - DB_PORT=${DB_PORT:-5432}
      - NODE_ENV=${NODE_ENV:-development}

Container Debug -- exec Kullanimi

bash
# Container icine shell ile gir
docker exec -it my_container bash       # Debian/Ubuntu
docker exec -it my_container sh         # Alpine
docker exec -it my_container /bin/ash   # Bazi Alpine image'lar

# Belirli kullanici ile gir
docker exec -it --user root my_container bash

# Ortam degiskeni ile komut calistir
docker exec -it -e DEBUG=true my_container node debug.js

# Calisan process'leri gor
docker exec my_container ps aux

# Disk kullanimini kontrol et
docker exec my_container df -h

# Network durumunu kontrol et
docker exec my_container cat /etc/hosts
docker exec my_container netstat -tlnp

# Dosya icerigini kontrol et (container icinde)
docker exec my_container cat /app/config.json

Layer Caching Sirasi

Dockerfile'da satirlarin sirasi cache performansini dogrudan etkiler. Genel kural: az degisenden cok degisene doğru siralama yapin:

dockerfile
FROM node:20-alpine
WORKDIR /app

## 1. Sistem bagimliliklari (neredeyse hic degismez)
RUN apk add --no-cache curl tini

## 2. Paket tanimlari (haftada bir degisir)
COPY package.json package-lock.json ./

## 3. Bagimlilik kurulumu (paket dosyasi degistiginde)
RUN npm ci --only=production

## 4. Yapilandirma dosyalari (ara sira degisir)
COPY tsconfig.json ./
COPY .env.example ./

## 5. Uygulama kodu (her commit'te degisir)
COPY src/ ./src/

## 6. Build (kod degistiginde)
RUN npm run build

ENTRYPOINT ["tini", "--"]
CMD ["node", "dist/server.js"]

Bu rehber duzenli olarak guncellenecektir. Onerileriniz için issue acabilirsiniz.

This guide is updated regularly. Feel free to open issues for suggestions.


Ilgili Rehberler

DevOps & Tools

Diger Kategoriler

Developer Guides & Technical References