Modern yazılım geliştirmede Docker, uygulamaları izole edilmiş container’larda çalıştırarak taşınabilirlik ve tutarlılık sağlayan en önemli araçlardan biri haline geldi. Bu kapsamlı rehberde Docker’ın temel kullanımını, en yaygın komutları ve pratik örnekleri ele alacağız.
Docker Nedir ve Neden Kullanmalıyız?
Docker, uygulamaları ve tüm bağımlılıklarını hafif, taşınabilir container’larda paketlememizi sağlayan bir containerization platformudur. Geleneksel virtualization’dan farklı olarak, Docker container’ları işletim sistemi çekirdeğini paylaşarak daha az kaynak tüketir ve daha hızlı başlatılır.
Docker’ın Ana Avantajları
- Taşınabilirlik: “Benim bilgisayarımda çalışıyor” problemini çözer
- İzolasyon: Her container kendi ortamında çalışır
- Kaynak Verimliliği: VM’lere göre daha az kaynak tüketir
- Hızlı Dağıtım: Saniyeler içinde container başlatma
- Tutarlılık: Geliştirme, test ve production ortamları arasında
Docker Kurulumu
Linux Üzerinde Kurulum
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
Docker Compose Kurulumu
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Temel Docker Komutları
Image İşlemleri
docker images # Mevcut tüm imajları listeler
docker pull nginx:latest # Docker Hub'dan nginx imajını indirir
docker rmi image_name # Belirtilen imajı siler (remove image)
docker build -t my-app . # Dockerfile'dan imaj oluşturur (-t: tag verir)
docker tag my-app:latest my-app:v1.0 # Mevcut imaja yeni tag ekler
Container İşlemleri
docker ps # Çalışan container'ları listeler (process status)
docker ps -a # Tüm container'ları listeler (-a: all)
docker run -d --name my-container nginx # Nginx container'ını arka planda çalıştırır (-d: detached)
docker start container_name # Durdurulmuş container'ı başlatır
docker stop container_name # Çalışan container'ı durdurur
docker restart container_name # Container'ı yeniden başlatır
docker rm container_name # Container'ı siler (remove)
Container İçine Erişim
docker exec -it container_name bash # Container içine terminal açar (-i: interactive, -t: tty)
docker logs container_name # Container loglarını gösterir
docker logs -f container_name # Logları canlı takip eder (-f: follow)
Dockerfile Oluşturma
Dockerfile, Docker imajlarını oluşturmak için kullanılan text dosyasıdır. İşte temel bir web uygulaması için örnek:
Node.js Uygulaması Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Bu Dockerfile, adım adım şu işlemleri gerçekleştirir:
İlk satırda node:18-alpine imajı kullanılır. Bu, Node.js’in 18. sürümünü içeren ve oldukça hafif olan Alpine tabanlı bir resmi Docker imajıdır. Küçük boyutu sayesinde daha hızlı indirilir ve dağıtımı kolaylaştırır.
Ardından WORKDIR /app satırıyla konteyner içerisinde çalışılacak dizin /app olarak tanımlanır. Bu, sonraki tüm komutların bu dizin içinde yürütüleceği anlamına gelir.
COPY package*.json ./ satırı, proje kök dizinindeki package.json ve varsa package-lock.json dosyalarını konteynere kopyalar. Bu dosyalar, proje bağımlılıklarının tanımlı olduğu yerlerdir.
Hemen ardından gelen RUN npm install komutu, bu bağımlılıkları indirir ve kurar. Bu adımda sadece gerekli olan dosyalar konteynere kopyalandığı için Docker cache mekanizmasından faydalanarak sonraki build işlemleri hızlandırılmış olur.
Sonrasında COPY . . komutuyla projenin tüm dosyaları konteyner içine kopyalanır. Artık tüm uygulama dosyaları konteynerde yer alır.
EXPOSE 3000 satırı, uygulamanın dinleyeceği portu belirtir. Bu sadece bilgilendirici bir ifadedir, gerçek port yönlendirmesi docker run -p komutu ile yapılır.
Son olarak CMD ["node", "server.js"] komutu, konteyner başlatıldığında çalıştırılacak olan komutu tanımlar. Burada uygulamanın giriş noktası olan server.js dosyası Node.js ile çalıştırılır.
Bu yapı sayesinde uygulamanızın her ortamda aynı şekilde çalışması garanti altına alınmış olur.
Docker Compose ile Multi-Container Uygulamalar
Docker Compose, birden fazla container’ı yönetmek için kullanılır. İşte LAMP stack örneği:
docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8000:80"
volumes:
- ./src:/var/www/html
depends_on:
- database
environment:
- DB_HOST=database
- DB_NAME=myapp
- DB_USER=root
- DB_PASS=secret
database:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
phpmyadmin:
image: phpmyadmin/phpmyadmin
ports:
- "8080:80"
environment:
PMA_HOST: database
depends_on:
- database
volumes:
db_data:
Docker Compose Komutları
docker-compose up -d # Tüm servisleri arka planda başlatır (-d: detached)
docker-compose down # Tüm servisleri durdurur ve kaldırır
docker-compose logs -f service_name # Belirtilen servisin loglarını canlı takip eder
docker-compose exec service_name bash # Belirtilen servis içine terminal açar
docker-compose build # Tüm servislerin imajlarını yeniden oluşturur
docker-compose restart service_name # Belirtilen servisi yeniden başlatır
Pratik Örnekler
1. Nginx Web Sunucusu
docker run -d \ # Arka planda çalıştır (detached)
--name my-nginx \ # Container'a isim ver
-p 8080:80 \ # Port yönlendirme (host:container)
-v $(pwd)/html:/usr/share/nginx/html \ # Volume mount (yerel:container)
nginx:alpine # Kullanılacak imaj
2. MySQL Veritabanı
docker run -d \ # Arka planda çalıştır
--name mysql-db \ # Container ismi
-e MYSQL_ROOT_PASSWORD=password \ # Environment variable (-e)
-e MYSQL_DATABASE=myapp \ # Oluşturulacak veritabanı
-p 3306:3306 \ # MySQL portu
-v mysql_data:/var/lib/mysql \ # Volume ile veri kalıcılığı
mysql:8.0 # MySQL 8.0 imajı
3. Redis Cache
docker run -d \ # Arka planda çalıştır
--name redis-cache \ # Container ismi
-p 6379:6379 \ # Redis portu
redis:alpine # Hafif Redis imajı
Volume ve Network Yönetimi
Volume İşlemleri
docker volume create my-volume # Yeni volume oluşturur
docker volume ls # Mevcut volume'ları listeler (list)
docker volume inspect my-volume # Volume detaylarını gösterir
docker volume rm my-volume # Volume'u siler (remove)
Network İşlemleri
docker network create my-network # Yeni network oluşturur
docker network ls # Mevcut network'leri listeler
docker network inspect my-network # Network detaylarını gösterir
docker run --network=my-network nginx # Container'ı belirtilen network'e bağlar
En İyi Pratikler
1. Multi-Stage Build Kullanımı
Modern uygulamalarda, özellikle frontend projelerinde, build işlemi zaman alabilir ve fazladan dosyalar üretebilir. Bu noktada Multi-Stage Build yöntemi devreye girer. Aşağıdaki Dockerfile örneğinde, bir Node.js uygulaması önce derleniyor, ardından sadece gerekli olan build çıktısı daha küçük bir imajda çalıştırılıyor.
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
Bu yapı iki aşamadan oluşur:
İlk aşama (builder):
İlk satırda node:18-alpine imajı kullanılır ve bu aşama "builder" olarak adlandırılır. Çalışma dizini /app olarak belirlenir. Ardından package.json ve varsa package-lock.json dosyaları kopyalanır ve npm install komutuyla bağımlılıklar kurulur. Sonrasında tüm proje dosyaları kopyalanır ve npm run build komutu çalıştırılarak projeyi derleyen bir dist klasörü üretilir.
İkinci aşama (final imaj):
İkinci aşamada, küçük ve hızlı bir web sunucusu olan nginx:alpine imajı temel alınır. İlk aşamadaki build çıktısı olan /app/dist dizini, Nginx’in servis verdiği /usr/share/nginx/html dizinine kopyalanır.
Sonuç olarak, yalnızca build sonucu olan statik dosyaları içeren, küçük boyutlu, güvenli ve production için ideal bir imaj elde edilir. Geliştirme araçları ve kaynak dosyalar son imajda yer almadığı için performans ve güvenlik açısından büyük avantaj sağlar.
2. .dockerignore Dosyası
Docker imajı oluşturulurken, proje klasöründeki tüm dosyalar konteynerin içine kopyalanır. Ancak bazı dosyaların veya klasörlerin imajın içine dahil edilmesi gereksizdir ve build süresini uzatabilir, imaj boyutunu şişirebilir. İşte bu noktada .dockerignore dosyası devreye girer.
.dockerignore, .gitignore dosyasına benzer şekilde çalışır ve hangi dosya veya klasörlerin Docker context’e dahil edilmeyeceğini belirtir.
Örnek bir .dockerignore dosyası şu şekilde olabilir:
node_modules
npm-debug.log
.git
.DS_Store
*.md
.env
Bu dosyada yer alan satırların anlamı:
node_modules: Lokal geliştirme sırasında oluşturulan bağımlılık klasörü, genellikle büyük boyutludur ve imaj içine dahil edilmesine gerek yoktur.npm-debug.log: Hata ayıklama günlük dosyalarıdır, gereksizdir..git: Versiyon kontrol klasörü, sadece geliştirme ortamında anlamlıdır..DS_Store: macOS sistemlerinin oluşturduğu gereksiz dosyalar.*.md: Belgeler (örneğin README.md) genellikle çalışma zamanında gerekli değildir..env: Ortam değişkenleri içeren dosya, güvenlik nedeniyle imaj içine alınmamalıdır.
Bu dosya sayesinde Docker imajı daha temiz, küçük ve hızlı hale gelir. Ayrıca hassas bilgilerin yanlışlıkla konteynerin içine dahil edilmesi de engellenmiş olur.
3. Güvenlik İpuçları
- Root kullanıcı yerine non-root kullanıcı kullanın
- Minimal base imajlar tercih edin (alpine, scratch)
- Secrets’ları environment variable olarak geçmeyin
- Regular security updates yapın
4. Performans Optimizasyonu
- Layer caching’den faydalanın
- Multi-stage build kullanın
- Gereksiz dosyaları .dockerignore ile hariç tutun
- Minimal imaj boyutu için alpine veya distroless imajlar kullanın
Container Monitoring ve Debugging
Resource Kullanımı İzleme
docker stats # Tüm container'ların kaynak kullanımını gösterir
docker stats container_name # Belirtilen container'ın istatistiklerini gösterir
docker system df # Docker'ın disk kullanımını gösterir (disk free)
docker system prune # Kullanılmayan imaj, container ve network'leri temizler
Log Yönetimi
docker logs --tail 100 container_name # Son 100 log satırını gösterir
docker logs --since 1h container_name # Son 1 saatteki logları gösterir
docker logs -f --timestamps container_name # Logları zaman damgasıyla canlı takip eder
Health Check Ekleme
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
Production Ortamı İçin İpuçları
1. Resource Limits
docker run -d \
--memory="512m" \ # Maksimum 512MB RAM kullanımı
--cpus="0.5" \ # Maksimum 0.5 CPU core kullanımı
--name limited-container \
nginx:alpine
2. Restart Policies
docker run -d \
--restart=unless-stopped \ # Manuel durdurulana kadar sürekli yeniden başlat
--name always-running \
nginx:alpine
3. Environment Variables
docker run -d \
--env-file .env \ # Environment variable'ları dosyadan oku
--name configured-app \
my-application
Sorun Giderme
Yaygın Problemler ve Çözümleri
- Port conflict:
docker psile kullanılan portları kontrol edin - Disk Alanı:
docker system prune -aile temizlik yapın - Permission Denied: Kullanıcıyı docker grubuna ekleyin
- Container Başlamıyor:
docker logs container_nameile logları kontrol edin
Debug Komutları
docker inspect container_name # Container'ın tüm detaylarını JSON formatında gösterir
docker exec -it container_name sh # Container içine shell erişimi (-it: interactive terminal)
docker run --rm -it alpine sh # Geçici alpine container'ında shell açar (--rm: çıkışta sil)
Uzun lafın kısası
Docker, modern yazılım geliştirmede vazgeçilmez bir araç haline gelmiştir. Container’lar sayesinde uygulamalarımızı tutarlı, taşınabilir ve ölçeklenebilir şekilde dağıtabiliyoruz. Bu rehberde ele aldığımız temel kavramlar ve komutlar, Docker yolculuğunuzda sağlam bir temel oluşturacaktır.
Docker’ı etkili kullanmak için sürekli pratik yapmak ve topluluktan öğrenmeye devam etmek önemlidir. Her proje farklı gereksinimler getirebilir, ancak burada öğrendiğiniz temel prensipleri uygulayarak başarılı containerization stratejileri geliştirebilirsiniz.
İlerleyen yazılarda Docker Swarm, Kubernetes entegrasyonu ve advanced networking konularını da ele alacağız. Docker journey’niz için bu temel rehberin faydalı olmasını umuyorum!