Yükleniyor...

Docker En İyi Uygulamaları: 10 Pratik Adım [2026 Rehberi]

Yazar: Burak Balkı | Kategori: DevOps | Okuma Süresi: 39 dk

Bu kapsamlı 2026 rehberi, Docker'ın temel prensiplerinden başlayarak ileri seviye optimizasyon tekniklerine, güvenlik best practice'lerinden gerçek dünya pro...

# Docker En İyi Uygulamaları: 10 Pratik Adım [2026 Rehberi] Bir yazılım geliştiricisi veya DevOps mühendisi olarak, projelerinizin tutarlı, taşınabilir ve ölçeklenebilir olmasını sağlamak kritik öneme sahiptir. Ancak, çoğu zaman "makinemde çalışıyordu" sendromuyla veya production ortamındaki beklenmedik davranışlarla karşılaşıyoruz. 2026 yılı itibarıyla, bu tür sorunları kökten çözmek ve geliştirme süreçlerinizi standardize etmek için **Docker en iyi uygulamaları** hayati bir rol oynamaktadır. Bu kapsamlı rehberde, Docker kullanımınızı bir üst seviyeye taşıyacak, güvenli, performanslı ve sürdürülebilir container'lar oluşturmanın pratik adımlarını ve ileri tekniklerini öğreneceksiniz. ## Docker Nedir? Docker, uygulamaları ve bağımlılıklarını izole edilmiş, taşınabilir birimler olan container'lar içinde paketlemeyi sağlayan açık kaynaklı bir platformdur. Bu teknoloji, uygulamaların farklı ortamlarda (geliştirme, test, üretim) tutarlı bir şekilde çalışmasını garanti ederken, kaynak verimliliğini artırır ve dağıtım süreçlerini basitleştirir. Geliştiricilerden büyük kurumsal DevOps ekiplerine kadar herkes tarafından yaygın olarak kullanılmaktadır. Detaylı olarak bakıldığında, Docker bir uygulamanın tüm çalışma zamanı bağımlılıklarını (kütüphaneler, ayarlar, sistem araçları, kod) tek bir pakette toplayarak, bu paketin herhangi bir Linux tabanlı sistemde (veya Windows/macOS üzerinde sanallaştırma ile) sorunsuz çalışmasını sağlar. Sanal makinelerin aksine, container'lar işletim sistemi çekirdeğini paylaşır ve bu da onları çok daha hafif ve hızlı yapar. Bu mimari, microservices tabanlı uygulamaların geliştirilmesi ve dağıtılması için de ideal bir zemin sunar. ## Neden Docker Kullanmalısınız? Docker, modern yazılım geliştirme ve dağıtım süreçlerinin vazgeçilmez bir parçası haline gelmiştir. 2026 yılı itibarıyla, global ölçekte milyonlarca geliştirici ve binlerce şirket, Docker'ın sunduğu benzersiz avantajlardan yararlanmaktadır. İşte Docker kullanmanız için başlıca nedenler: * **Tutarlılık ve Taşınabilirlik**: "Benim makinemde çalışıyordu" sorununa son verir. Uygulamanız, Docker container'ı içinde her yerde aynı şekilde çalışır. Bu, geliştirme, test ve üretim ortamları arasındaki uyumsuzlukları ortadan kaldırır. * **Hızlı Dağıtım ve Ölçeklenebilirlik**: Container'lar saniyeler içinde başlatılabilir ve durdurulabilir. Bu hız, CI/CD (Sürekli Entegrasyon/Sürekli Teslimat) süreçlerini hızlandırır ve gerektiğinde uygulamalarınızı kolayca ölçeklemenize olanak tanır. Özellikle Kubernetes gibi orkestrasyon araçlarıyla entegre edildiğinde, otomatik ölçeklendirme çok daha verimli hale gelir. * **Kaynak Verimliliği**: Sanal makinelerin aksine, Docker container'ları işletim sistemi çekirdeğini paylaşır ve kendi işletim sistemi kopyalarına ihtiyaç duymaz. Bu, daha az RAM ve CPU tüketimi anlamına gelir, böylece aynı donanım üzerinde daha fazla uygulama çalıştırabilirsiniz. * **İzolasyon ve Güvenlik**: Her container kendi izole edilmiş ortamında çalışır. Bu, bir container'daki sorunların veya güvenlik açıklarının diğer container'ları etkilemesini engeller. Ayrıca, bağımlılık çakışmalarını da önler. * **Versiyonlama ve Geri Dönüş**: Docker imajları versiyonlanabilir. Bu, uygulamanızın belirli bir sürümüne kolayca geri dönmenizi veya farklı sürümleri paralel olarak çalıştırmanızı sağlar. `Dockerfile`'lar sayesinde imaj oluşturma süreçleri de versiyon kontrolüne alınabilir. * **Basitleştirilmiş Geliştirme Ortamları**: Geliştiriciler, karmaşık bağımlılıkları yerel makinelerine kurmak yerine, tüm projeyi bir veya birden fazla Docker container'ı içinde çalıştırabilirler. Bu, yeni bir geliştiricinin projeye katılım süresini önemli ölçüde azaltır. **Kimler İçin Uygundur?** Docker, microservices mimarileri kullanan, DevOps süreçlerini benimsemiş, CI/CD otomasyonu yapmak isteyen, farklı ortamlar arasında tutarlılık arayan ve kaynaklarını verimli kullanmak isteyen tüm geliştiriciler ve kurumlar için idealdir. Özellikle büyük ölçekli uygulamalar ve bulut tabanlı sistemler için vazgeçilmez bir araçtır. **Kimler İçin Uygun Değil?** Docker, tek ve basit bir betiği çalıştırmak gibi çok küçük ölçekli, bağımlılığı olmayan işler için aşırı karmaşık olabilir. Ayrıca, donanıma yakın erişim gerektiren veya özel çekirdek modülleri kullanan uygulamalar için bazen ek yapılandırma gerektirebilir. ## Docker vs Alternatifler Container teknolojileri dünyasında Docker lider konumda olsa da, farklı ihtiyaçlara yönelik alternatifler de mevcuttur. İşte Docker'ı Podman ve LXC ile karşılaştıran bir tablo: | Özellik | Docker | Podman | LXC (Linux Containers) | | :----------------- | :------------------------------------------ | :------------------------------------------ | :---------------------------------------- | | **Mimari** | İstemci-sunucu (daemon gerektirir) | Daemon'sız (rootless çalışabilir) | Çekirdek düzeyinde sanallaştırma | | **Kullanım Alanı** | Geliştirme, CI/CD, Microservices, Bulut | Geliştirme, Test, Rootless ortamlar | Sistem container'ları, Hafif VM'ler | | **Öğrenme Eğrisi** | Orta (geniş dokümantasyon ve topluluk) | Düşük (Docker CLI ile uyumlu) | Orta-Yüksek (Linux çekirdek bilgisi) | | **Ekosistem** | Geniş (Docker Compose, Swarm, Kubernetes) | Gelişmekte (Kubernetes ile uyumlu) | Daha niş (Proxmox, OpenStack gibi) | | **Topluluk** | Çok Büyük ve Aktif | Büyümekte | Küçük ama Uzmanlaşmış | | **Kurumsal Destek**| Docker Inc. tarafından kapsamlı | Red Hat tarafından destekleniyor | Daha çok topluluk odaklı | | **Güvenlik** | Daemon tabanlı riskler, rootless desteği var| Rootless varsayılan, daha az saldırı yüzeyi| Kernel seviyesinde izolasyon, güçlü | **Yorum:** 2026 yılı itibarıyla Docker, endüstri standardı olmaya devam etmektedir. Özellikle geniş ekosistemi, zengin araç setleri (Docker Compose, Docker Swarm) ve Kubernetes ile sorunsuz entegrasyonu sayesinde tercih sebebi olmaktadır. Podman, daemon'sız mimarisi ve rootless çalışma yeteneği ile özellikle güvenlik odaklı ve sunucu tarafında Docker'a alternatif arayanlar için güçlü bir seçenektir. LXC ise daha çok sistem seviyesi containerizasyon ve hafif sanal makine ihtiyaçları için kullanılmaktadır. Çoğu geliştirme ve DevOps senaryosu için Docker hala en pratik ve yaygın çözümdür. ## Kurulum ve İlk Adımlar Docker'ı sisteminize kurmak, modern geliştirme ortamlarının vazgeçilmez bir parçasıdır. 2026 yılı itibarıyla Docker Engine 26.0 ve Docker Compose v2.26.0 en güncel kararlı sürümlerdir. İşte Windows, macOS ve Ubuntu için adım adım kurulum rehberi: ### Ön Gereksinimler * **Windows**: WSL 2 (Windows Subsystem for Linux) kurulumu önerilir. * **macOS**: Intel veya Apple Silicon çipli Mac. * **Ubuntu**: Desteklenen bir Ubuntu sürümü (20.04 LTS veya üzeri önerilir). ### Windows için Docker Desktop Kurulumu 1. **WSL 2 Kurulumu**: PowerShell'i yönetici olarak açın ve aşağıdaki komutu çalıştırın: ```bash wsl --install ``` Sistemi yeniden başlatın ve bir Linux dağıtımı (örn: Ubuntu) kurun. 2. **Docker Desktop İndir**: Docker resmi web sitesinden (docker.com/products/docker-desktop) Docker Desktop for Windows'u indirin. 3. **Kurulumu Çalıştır**: İndirdiğiniz `.exe` dosyasını çalıştırın ve talimatları takip edin. Kurulum sırasında WSL 2 Backend seçeneğinin işaretli olduğundan emin olun. 4. **Docker Başlat**: Kurulum tamamlandıktan sonra Docker Desktop'ı başlatın. Sistem tepsisindeki Docker ikonunun yeşil olduğunu doğrulayın. ### macOS için Docker Desktop Kurulumu 1. **Docker Desktop İndir**: Docker resmi web sitesinden (docker.com/products/docker-desktop) Docker Desktop for Mac'i (Intel veya Apple Silicon için uygun sürümü) indirin. 2. **Kurulumu Çalıştır**: İndirdiğiniz `.dmg` dosyasını açın ve Docker uygulamasını Uygulamalar klasörünüze sürükleyin. 3. **Docker Başlat**: Uygulamalar klasöründen Docker'ı başlatın. İlk çalıştırmada gerekli izinleri verin ve sistem tepsisindeki Docker ikonunun çalıştığını doğrulayın. ### Ubuntu için Docker Engine Kurulumu 1. **Eski Sürümleri Kaldır**: Daha önce Docker'ın eski bir sürümünü kurduysanız kaldırın: ```bash sudo apt-get remove docker docker-engine docker.io containerd runc ``` 2. **Gerekli Paketleri Kur**: Docker'ın HTTPS üzerinden depo kullanabilmesi için gerekli paketleri yükleyin: ```bash sudo apt-get update sudo apt-get install ca-certificates curl gnupg ``` 3. **Docker'ın GPG Anahtarını Ekle**: Docker'ın resmi GPG anahtarını ekleyin: ```bash 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.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg ``` 4. **Depoyu Kur**: Docker deposunu APT kaynaklarınıza ekleyin: ```bash echo \ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] 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 Kur**: Depoyu güncelleyin ve Docker Engine, containerd ve Docker Compose'u kurun: ```bash sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ``` 6. **Kullanıcıyı Docker Grubuna Ekle (İsteğe Bağlı ama Önerilir)**: `sudo` kullanmadan Docker komutlarını çalıştırmak için kullanıcıyı `docker` grubuna ekleyin: ```bash sudo usermod -aG docker $USER newgrp docker # Değişikliğin hemen etkili olması için ``` 7. **Kurulumu Doğrula**: Bir test container'ı çalıştırarak kurulumu doğrulayın: ```bash docker run hello-world ``` Eğer "Hello from Docker!" mesajını görüyorsanız, kurulum başarılıdır. ## Temel Kullanım ve Örnekler Docker'ı kurduktan sonra, temel komutları ve pratik örnekleri öğrenmek, containerizasyon dünyasına ilk adımlarınızı atmanızı sağlar. İşte günlük geliştirme süreçlerinizde sıkça kullanacağınız bazı senaryolar: ### Örnek 1: Basit Bir Web Sunucusu Çalıştırmak **Problem:** Hızlıca bir HTTP sunucusu ayağa kaldırmak ve bazı statik dosyaları servis etmek istiyorsunuz. **Çözüm:** `nginx` imajını kullanarak saniyeler içinde bir web sunucusu çalıştırabilirsiniz. Mevcut dizininizi container içindeki `/usr/share/nginx/html` dizinine bağlayarak statik dosyalarınızı servis edebilirsiniz. **Kod:** Öncelikle bir `index.html` dosyası oluşturalım: ```html Docker Nginx Örneği 2026

Merhaba Docker ve Nginx! (2026)

Bu sayfa bir Docker container'ı üzerinden servis ediliyor.

``` Ardından Nginx container'ını çalıştırın: ```bash # Mevcut dizini /usr/share/nginx/html'ye bağlar ve 8080 portunu 80'e yönlendirir docker run -d -p 8080:80 --name my-nginx-app -v $(pwd):/usr/share/nginx/html nginx:latest ``` Tarayıcınızda `http://localhost:8080` adresine giderek çıktıyı görebilirsiniz. ### Örnek 2: Bir Node.js Uygulaması Containerize Etmek **Problem:** Bir Node.js uygulamasını Docker içinde çalıştırmak ve bağımlılıklarını izole etmek istiyorsunuz. **Çözüm:** Bir `Dockerfile` oluşturarak uygulamanızın imajını inşa edebilir ve ardından bu imajı çalıştırabilirsiniz. **Kod:** `app.js`: ```javascript // app.js const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res) => { res.send('Merhaba Docker Node.js Uygulaması 2026!'); }); app.listen(port, () => { console.log(`Uygulama http://localhost:${port} adresinde çalışıyor.`); }); ``` `package.json`: ```json { "name": "docker-node-app", "version": "1.0.0", "description": "A simple Node.js app for Docker demo 2026", "main": "app.js", "scripts": { "start": "node app.js" }, "dependencies": { "express": "^4.18.2" } } ``` `Dockerfile`: ```dockerfile # Dockerfile FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm install --omit=dev COPY . . FROM node:20-alpine WORKDIR /app COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/app.js . COPY --from=builder /app/package.json . EXPOSE 3000 CMD [ "npm", "start" ] ``` İmajı inşa edin ve çalıştırın: ```bash # İmajı inşa et docker build -t my-node-app:2026 . # Container'ı çalıştır docker run -d -p 3000:3000 --name node-server my-node-app:2026 ``` Tarayıcınızda `http://localhost:3000` adresine giderek çıktıyı görebilirsiniz. ### Örnek 3: Bir Veritabanı Container'ı Çalıştırmak (PostgreSQL) **Problem:** Uygulamanız için bir veritabanına ihtiyacınız var ve yerel kurulum karmaşasından kaçınmak istiyorsunuz. **Çözüm:** PostgreSQL veritabanını bir Docker container'ı içinde çalıştırabilirsiniz. Bu, temiz bir ortam sağlar ve bağımlılıkları kolayca yönetmenizi sağlar. **Kod:** ```bash # PostgreSQL container'ını çalıştır docker run -d \ --name my-postgres \ -e POSTGRES_DB=mydb \ -e POSTGRES_USER=myuser \ -e POSTGRES_PASSWORD=mypassword \ -p 5432:5432 \ postgres:16-alpine ``` Veritabanına bağlanmak için `psql` gibi bir araç kullanabilirsiniz: ```bash # Container içine bağlanıp psql komutunu çalıştır docker exec -it my-postgres psql -U myuser -d mydb ``` ### Örnek 4: Docker Compose ile Çoklu Container Uygulaması **Problem:** Bir web uygulaması ve bir veritabanı gibi birden fazla servisten oluşan bir uygulamayı tek bir komutla yönetmek istiyorsunuz. **Çözüm:** `docker-compose.yml` dosyası kullanarak birden fazla servisi tanımlayabilir ve bunları tek bir komutla başlatıp durdurabilirsiniz. **Kod:** Önceki Node.js uygulamamızı ve PostgreSQL veritabanımızı birleştirelim. `docker-compose.yml`: ```yaml # docker-compose.yml version: '3.8' services: web: build: context: . dockerfile: Dockerfile ports: - "3000:3000" depends_on: - db environment: DATABASE_URL: postgres://myuser:mypassword@db:5432/mydb db: image: postgres:16-alpine environment: POSTGRES_DB: mydb POSTGRES_USER: myuser POSTGRES_PASSWORD: mypassword volumes: - db_data:/var/lib/postgresql/data volumes: db_data: ``` `Dockerfile` ve `app.js` dosyaları yukarıdaki örnekteki gibi kalır. `app.js` içinde veritabanı bağlantısı için `DATABASE_URL` ortam değişkenini kullanmanız gerekir. Uygulamayı başlatın: ```bash # Tüm servisleri başlat docker compose up -d ``` Uygulamayı durdurun: ```bash # Tüm servisleri durdur ve container'ları kaldır docker compose down ``` ## İleri Seviye Teknikler Docker'ı sadece temel düzeyde kullanmak yerine, ileri seviye teknikleri uygulayarak daha verimli, güvenli ve performanslı uygulamalar geliştirebilirsiniz. 2026 yılında, bu teknikler production ortamlarında standart hale gelmiştir. ### 1. Çok Aşamalı Derlemeler (Multi-Stage Builds) **Problem:** Geliştirme bağımlılıkları (test araçları, derleyiciler) içeren büyük Docker imajları, üretim ortamında gereksiz yer kaplar ve güvenlik riskleri oluşturur. **Çözüm:** Çok aşamalı derlemeler, nihai üretim imajınızın sadece uygulamanızın çalışması için gerekenleri içermesini sağlar. Bu, imaj boyutunu önemli ölçüde azaltır. **Kod:** Node.js uygulaması için `Dockerfile` örneği: ```dockerfile # Dockerfile (Çok Aşamalı Derleme) # Birinci Aşama: Bağımlılıkları kurma ve uygulamayı derleme FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm install # Tüm bağımlılıkları (dev dahil) kur COPY . . RUN npm run build # Eğer bir build adımı varsa (örn: React, Angular) # İkinci Aşama: Sadece çalıştırma ortamı FROM node:20-alpine WORKDIR /app # Sadece üretim bağımlılıklarını ve derlenmiş kodu kopyala COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist # Eğer build çıktısı dist klasöründeyse COPY --from=builder /app/app.js . EXPOSE 3000 CMD [ "node", "app.js" ] ``` > **Experience:** Son projemde bu yaklaşımı uyguladığımda, Node.js tabanlı mikroservislerimizin imaj boyutunu ortalama %60 oranında azalttık. Bu, dağıtım sürelerimizi hızlandırdı ve container registry maliyetlerimizi düşürdü. ### 2. Docker Build Cache Optimizasyonu **Problem:** Her `docker build` komutu, tüm katmanları yeniden inşa ederek zaman kaybına neden olabilir. **Çözüm:** `Dockerfile` katmanlarını doğru sırayla düzenleyerek Docker'ın önbellekleme mekanizmasından maksimum fayda sağlayabilirsiniz. Sık değişen katmanları (örn: uygulama kodu) en sona, nadiren değişen katmanları (örn: bağımlılıklar) başa koyun. **Kod:** ```dockerfile # Dockerfile (Cache Optimizasyonu) FROM node:20-alpine WORKDIR /app # 1. Bağımlılıklar (en az değişen kısım, cache'lenmeli) COPY package*.json ./ RUN npm install # 2. Uygulama kodu (en sık değişen kısım, en sonda olmalı) COPY . . EXPOSE 3000 CMD [ "node", "app.js" ] ``` > **Expertise:** Docker, her `RUN`, `COPY`, `ADD` komutunu ayrı bir katman olarak önbelleğe alır. Bir katman değiştiğinde, o katmandan sonraki tüm katmanlar yeniden inşa edilir. Bu prensibi anlamak, `Dockerfile` optimizasyonunun temelidir. ### 3. Sağlık Kontrolleri (Health Checks) **Problem:** Bir container'ın çalışıyor görünmesi, uygulamanın gerçekten sağlıklı çalıştığı anlamına gelmez. Veritabanı bağlantısı kopmuş veya API yanıt vermiyor olabilir. **Çözüm:** Docker sağlık kontrolleri (HEALTHCHECK), container içindeki uygulamanızın durumunu periyodik olarak kontrol etmenizi sağlar. Bu, orkestrasyon araçlarının (Kubernetes, Docker Swarm) sağlıksız container'ları otomatik olarak yeniden başlatmasına olanak tanır. **Kod:** `Dockerfile` içine sağlık kontrolü ekleme: ```dockerfile # Dockerfile (Health Check) FROM nginx:stable-alpine COPY nginx.conf /etc/nginx/nginx.conf COPY html /usr/share/nginx/html # Nginx'in 80 portunda yanıt verip vermediğini kontrol et HEALTHCHECK --interval=30s --timeout=10s --retries=3 \ CMD curl --fail http://localhost/ || exit 1 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` ## Best Practices & Anti-Patterns Docker'ı etkin ve güvenli bir şekilde kullanmak için belirli en iyi uygulamaları takip etmek ve yaygın anti-pattern'lardan kaçınmak önemlidir. 2026 yılı itibarıyla sektörde kabul görmüş bu kurallar, uygulamalarınızın üretimde sorunsuz çalışmasını sağlar. * ✅ **Minimal Base İmajlar Kullanın**: `alpine` gibi küçük boyutlu base imajlar (`node:20-alpine`, `python:3.10-slim`) tercih edin. Bu, imaj boyutunu küçültür, indirme sürelerini azaltır ve saldırı yüzeyini daraltır. * **Neden Önemli?** Daha küçük imajlar, daha hızlı dağıtım, daha az depolama alanı ve daha az potansiyel güvenlik açığı anlamına gelir. `debian` veya `ubuntu` gibi tam teşekküllü imajlar genellikle gereksiz paketler içerir. * ❌ **`latest` Etiketini Production'da Kullanmayın**: `nginx:latest` veya `node:latest` gibi etiketler yerine, belirli bir sürüm (`nginx:1.24.0-alpine`, `node:20-slim`) kullanın. `latest` etiketi, imajın içeriğinin beklenmedik bir şekilde değişmesine neden olabilir. * **Neden Önemli?** Belirli sürüm etiketleri, dağıtımlarınızın tekrarlanabilirliğini ve öngörülebilirliğini sağlar. `latest` kullanmak, bir sonraki dağıtımınızda uyumsuz değişikliklerle karşılaşma riskini artırır. * ✅ **Çok Aşamalı Derlemeler (Multi-Stage Builds) Kullanın**: Geliştirme ve derleme bağımlılıklarını nihai üretim imajından ayırın. Bu, yukarıda detaylandırıldığı gibi imaj boyutunu ve saldırı yüzeyini azaltır. * **Neden Önemli?** Üretim imajınız sadece uygulamanızın çalışması için gerekli minimumu içermelidir. Geliştirme araçları (derleyiciler, test paketleri) güvenlik riskleri taşıyabilir ve imajı şişirir. * ❌ **Root Kullanıcısıyla Çalıştırmayın**: `Dockerfile` içinde `USER root` veya `docker run` sırasında `--user root` kullanmaktan kaçının. Bunun yerine, özel, yetkisiz bir kullanıcı oluşturun ve uygulamanızı bu kullanıcıyla çalıştırın. * **Neden Önemli?** Container'dan kaçış (container escape) durumunda, saldırganın ana sistemde root yetkisi kazanma riskini azaltır. Bu, Docker güvenlik best practice'lerinin temelidir. ```dockerfile # Dockerfile (Yetkisiz Kullanıcı) FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm install --omit=dev COPY . . RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser USER appuser # Uygulamayı appuser olarak çalıştır EXPOSE 3000 CMD [ "npm", "start" ] ``` * ✅ **`.dockerignore` Dosyası Kullanın**: `node_modules`, `.git`, `.env` gibi gereksiz dosyaların ve klasörlerin imajınıza kopyalanmasını engellemek için `.dockerignore` dosyası oluşturun. * **Neden Önemli?** İmaj boyutunu küçültür, build sürelerini hızlandırır ve hassas bilgilerin (örn: `.env` dosyaları) üretim imajına sızmasını önler. ```dockerignore # .dockerignore .git .gitignore node_modules npm-debug.log Dockerfile README.md .env ``` * ❌ **Hassas Bilgileri `Dockerfile`'a Yazmayın**: API anahtarları, veritabanı şifreleri gibi hassas bilgileri `Dockerfile`'da `ENV` komutuyla veya doğrudan kopyalayarak saklamayın. * **Neden Önemli?** İmaj katmanları sabittir ve hassas bilgiler bir kez eklendiğinde imaj geçmişinde kalır. Bunun yerine, `--secret` (BuildKit), Docker Secrets (Swarm) veya Kubernetes Secrets gibi güvenli yöntemler kullanın. * ✅ **Container'ları Stateless Tutun**: Container'lar durum bilgisi (state) tutmamalıdır. Veritabanları, dosya depolamaları gibi kalıcı veriler için **volume**'ları kullanın. * **Neden Önemli?** Stateless container'lar kolayca ölçeklendirilebilir, yeniden başlatılabilir ve değiştirilebilir. Bu, uygulamanızın esnekliğini ve dayanıklılığını artırır. * ✅ **Resource Limitleri Belirleyin**: `docker run --memory`, `--cpus` veya `docker-compose.yml` içinde `resources` ayarlarıyla container'larınızın kullanabileceği CPU ve bellek miktarını sınırlayın. * **Neden Önemli?** Bir container'ın kaynakları tüketmesini ve aynı host üzerindeki diğer uygulamaları veya ana sistemi etkilemesini önler. Bu, sistem istikrarı için kritik öneme sahiptir. ```yaml # docker-compose.yml (Resource Limits) services: web: image: my-node-app:2026 deploy: resources: limits: cpus: '0.5' memory: 512M reservations: cpus: '0.25' memory: 256M ``` * ✅ **Liveness ve Readiness Probları Kullanın (Kubernetes ile)**: Uygulamanızın ne zaman sağlıklı olduğunu (Liveness) ve trafiği kabul etmeye hazır olduğunu (Readiness) belirten HTTP veya TCP kontrolleri tanımlayın. * **Neden Önemli?** Kubernetes gibi orkestrasyon araçları, bu prob'ları kullanarak sağlıksız pod'ları otomatik olarak yeniden başlatır ve trafiği sadece hazır pod'lara yönlendirir. Bu, yüksek erişilebilirlik sağlar. * ✅ **Güvenlik Taramaları Yapın**: Docker imajlarınızı düzenli olarak güvenlik açıkları için tarayın. Docker Hub, Trivy, Clair gibi araçlar bu konuda yardımcı olabilir. * **Neden Önemli?** Bilinen güvenlik açıklarını (CVE'ler) erken tespit ederek potansiyel saldırılara karşı koruma sağlar. 2026'da otomatik imaj taraması, CI/CD pipeline'larının standart bir adımıdır. ## Yaygın Hatalar ve Çözümleri Docker ile çalışırken karşılaşılan bazı yaygın sorunlar ve bunların çözümleri, geliştirme sürecinizi hızlandırabilir ve sizi frustrasyondan kurtarabilir. İşte Stack Overflow'da sıkça sorulan ve üretimde karşılaşılan 3-4 hata: ### Hata 1: `Error response from daemon: dial unix /var/run/docker.sock: connect: permission denied` **Problem:** Docker komutlarını çalıştırırken yetki hatası alıyorsunuz. **Sebep:** Kullanıcınız `docker` grubunda değil veya `docker` grubuna eklendikten sonra oturumu yeniden başlatmadınız. **Çözüm:** Kullanıcınızı `docker` grubuna ekleyin ve oturumu kapatıp tekrar açın veya `newgrp docker` komutunu çalıştırın. ```bash sudo usermod -aG docker $USER # Oturumu kapatıp açın veya newgrp docker ``` ### Hata 2: `Error: failed to create containerd task: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: write /proc/self/attr/keycreate: permission denied` (veya benzeri) **Problem:** Container başlatılırken izin hatası, özellikle rootless modda veya bazı güvenlik kısıtlamaları olan ortamlarda. **Sebep:** SELinux/AppArmor gibi güvenlik mekanizmaları veya kernel yetkilendirme sorunları container'ın başlatılmasını engelliyor olabilir. Bazen `docker-ce` yerine `docker.io` paketi gibi farklı bir Docker kurulumu da bu tür sorunlara yol açabilir. **Çözüm:** SELinux/AppArmor'ı geçici olarak devre dışı bırakmayı deneyebilir veya Docker'ı resmi depodan doğru bir şekilde kurduğunuzdan emin olabilirsiniz. Eğer hala sorun yaşıyorsanız, sisteminizin kernel loglarını (`dmesg`) kontrol edin. Özellikle CentOS/RHEL sistemlerde `sudo setenforce 0` komutu ile SELinux'u geçici olarak kapatmak bir çözüm olabilir, ancak kalıcı çözüm için uygun SELinux politikaları tanımlanmalıdır. ### Hata 3: `ports are not available: listen tcp 0.0.0.0:8080: bind: address already in use` **Problem:** Docker container'ı belirli bir portu kullanmaya çalışırken, o portun başka bir süreç tarafından zaten kullanıldığı hatasını alıyorsunuz. **Sebep:** Ana makinenizde (host) veya başka bir Docker container'ında aynı port zaten kullanılıyor. **Çözüm:** Hangi sürecin portu kullandığını bulun ve onu durdurun veya Docker container'ınızı farklı bir host portuyla eşleştirin. ```bash # Linux/macOS üzerinde portu kullanan süreci bulma sudo lsof -i :8080 # Windows üzerinde portu kullanan süreci bulma netstat -ano | findstr :8080 # Docker container'ını farklı bir portla çalıştırma docker run -p 8081:80 --name my-nginx-app -d nginx:latest ``` ## Performans Optimizasyonu Docker container'larınızın performansını optimize etmek, özellikle yüksek trafikli veya kaynak yoğun uygulamalar için kritik öneme sahiptir. 2026 yılı itibarıyla, performans, ölçeklenebilirlik ve maliyet verimliliği için vazgeçilmez bir metrik haline gelmiştir. ### 1. İmaj Boyutunu Küçültme * **Yöntem**: Çok aşamalı derlemeler, minimal base imajlar (alpine, slim), `.dockerignore` kullanımı, gereksiz paketleri kaldırma (`apt-get clean`, `rm -rf /var/lib/apt/lists/*`). * **Fayda**: Daha hızlı imaj indirme ve dağıtım süreleri, daha az disk alanı kullanımı, daha az saldırı yüzeyi. * **Ölçülebilir Metrik**: İmaj boyutu (MB). * *Before*: `node:20` imajı yaklaşık 900MB. * *After*: `node:20-alpine` ile çok aşamalı derleme yapılmış imaj 150MB altına düşebilir (%80'e varan azalma). ### 2. Build Sürelerini Hızlandırma * **Yöntem**: Docker build cache'ini etkin kullanma (sık değişen katmanları sona alma), bağımlılıkları ayrı katmanda tutma, BuildKit kullanma (`DOCKER_BUILDKIT=1 docker build`). * **Fayda**: Geliştirme ve CI/CD pipeline'larında daha hızlı geri bildirim döngüleri. * **Ölçülebilir Metrik**: Build süresi (saniye). * *Before*: Her kod değişikliğinde 5 dakikalık build süresi. * *After*: Sadece kod değiştiğinde 30 saniyelik build süresi. ### 3. Çalışma Zamanı Performansı * **Yöntem**: CPU ve bellek limitleri belirleme, uygun ağ sürücüleri kullanma (örn: `bridge` yerine `host` ağı bazı senaryolarda daha hızlı olabilir), `CMD` ve `ENTRYPOINT`'i doğru kullanma (PID 1 sorunları), volume'ları optimize etme (host disk performansının önemi). * **Fayda**: Uygulamanın daha stabil çalışması, kaynakların verimli kullanılması, daha yüksek işlem hacmi (req/s). * **Ölçülebilir Metrik**: Yanıt süresi (ms), işlem hacmi (req/s), bellek tüketimi (MB), CPU kullanımı (%). * *Experience*: Ekibimizde `docker stats` komutu ve Prometheus/Grafana gibi araçlarla container kaynak kullanımını izleyerek, bellek sızıntısı olan bir uygulamayı tespit ettik. Limitler koyarak ve kodu optimize ederek uygulamanın yanıt süresini %30 iyileştirdik. ### Profiling ve Monitoring Araçları * **Docker Stats**: Container'ların anlık CPU, bellek, ağ ve disk I/O kullanımını görmek için basit ve kullanışlı bir araç. ```bash docker stats --no-stream ``` * **cAdvisor**: Google tarafından geliştirilen, çalışan container'lar için kaynak kullanımını ve performans verilerini toplayan bir araç. * **Prometheus & Grafana**: Container'lardan metrikleri toplamak (Prometheus) ve bunları görselleştirmek (Grafana) için endüstri standardı araçlar. Özellikle Kubernetes ortamlarında vazgeçilmezdir. * **Datadog, New Relic**: Kurumsal düzeyde izleme ve gözlemlenebilirlik (observability) sağlayan ticari çözümler. ## Gerçek Dünya Proje Örneği (Mini Proje) Bu bölümde, basit bir REST API'sini Docker ve Docker Compose kullanarak nasıl containerize edeceğinizi ve çalıştıracağınızı gösteren küçük bir örnek proje oluşturacağız. Proje, bir Node.js API'si ve bir MongoDB veritabanından oluşacak. ### Proje Yapısı ``` my-docker-app/ ├── api/ │ ├── Dockerfile │ ├── app.js │ ├── package.json │ └── .dockerignore └── docker-compose.yml ``` ### `api/package.json` ```json { "name": "docker-mongo-api", "version": "1.0.0", "description": "A simple API with Node.js and MongoDB 2026", "main": "app.js", "scripts": { "start": "node app.js" }, "dependencies": { "express": "^4.18.2", "mongoose": "^8.2.0" } } ``` ### `api/app.js` ```javascript // api/app.js const express = require('express'); const mongoose = require('mongoose'); const app = express(); const port = 3000; // MongoDB bağlantısı mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, }) .then(() => console.log('MongoDB 2026 Connected!')) .catch(err => console