8 min read

Docker Temelleri: Temelden Gerçek Proje Kullanımına

Mustafa Kürşad BaşerMustafa Kürşad BAŞER
March 5, 2025
Docker Temelleri: Temelden Gerçek Proje Kullanımına

Docker Temelleri: Temelden Gerçek Proje Kullanımına

Docker’ı öğrenirken ilk eşik kolay: image çek, container çalıştır, port aç, bitti. Asıl değer, aynı projeyi her seferinde aynı şekilde ayağa kaldırabildiğinde ortaya çıkıyor. Tek makinede değil, ekipte. Sadece local’de değil, prod’a yakın davranışlarla.

Bu yazı, Docker’ın temel yapı taşlarını netleştiriyor ve sonra Dockerfile ile docker compose üzerinden gerçekçi bir akış kuruyor. Araya debug rutini, sık yapılan hatalar ve iki tane kontrol listesi de ekledim. Amaç komut ezberi değil, pratik refleks.


Problem: Teoride biliyorum, pratikte takılıyorum

Docker tarafında en çok zaman yediren şey genelde şu oluyor: Kavramlar tam oturmadan kurulum büyüyor. Sonra bir yerde port çakışıyor, DB bağlantısı kopuyor, veri kayboluyor ve debug uzuyor.

  • “Bende çalışıyor” ama ekipte aynı şekilde kalkmıyor
  • DB datası uçuyor, container restart sonrası her şey sıfırlanıyor
  • Servisler konuşmuyor, localhost yüzünden yanlış yere bağlanılıyor
  • Build yavaş, her değişiklikte cache bozuluyor
  • Prod’a yakın davranış yok, restart ve sağlık yaklaşımı düşünülmemiş

Yaklaşım: Kavramları netleştir, sonra kurulum akışını standartlaştır

Docker’ı pratikte anlaşılır kılan şey, birkaç kavramı doğru ayırmak. Sonra da bu kavramları Compose ile tek bir tarifte birleştirmek. Aşağıdaki parçalar netleşince “Docker karmaşık” hissi ciddi azalıyor.

Docker Engine, Docker Daemon ve Docker CLI

Neden önemli? Docker komutlarını yazan taraf CLI. Asıl işi yapan taraf ise arka planda çalışan daemon. Bunların hepsi Engine üzerinden container, image, network ve volume operasyonlarını yürütüyor. Komut çalışmıyorsa bazen sorun Dockerfile değil, daemon veya Engine tarafındaki durum olabiliyor.

Pratik ipucu
  • Sorun anında önce şuna bakmak çoğu şeyi hızlandırır: Docker çalışıyor mu, container’lar ayakta mı, log ne diyor
  • “Komut bende çalışmıyor” durumlarında daemon tarafı da ihtimal dahilinde

Docker Image ve Docker Container

Neden önemli? Image paket. Container çalışan instance. Container’ı silmek uygulamayı “yok etmez”, sadece o instance gider. Kalıcı veri gerekiyorsa çözüm container değil volume olur.

Yaygın hata
  • Image ile container’ı aynı şey sanmak ve veri kaybını container üzerinden çözmeye çalışmak

Dockerfile: Image’ı üreten tarif

Neden önemli? Dockerfile iyi değilse image şişer, build uzar, cache çalışmaz. Bu da günlük geliştirmede sürekli zaman kaybı demek.

Pratik ipucu
  • Bağımlılık dosyalarını önce kopyalayıp yüklemek, cache tarafında en büyük kazanç
  • .dockerignore yoksa image gereksiz büyür ve build süresi uzar

Docker Hub ve Registry mantığı

Neden önemli? Docker Hub bir registry. Postgres, Redis gibi hazır image’ların geldiği yer. Aynı mantıkla kendi image’larını da push edersin. Registry tarafı, özellikle prod’da versiyonlama ve geri dönüş planı için kritik.

Yaygın hata
  • latest kullanmak ve “dün çalışan bugün bozuldu” sürprizini davet etmek

Docker Compose: Çoklu servisi tek komutla kaldırmak

Neden önemli? Gerçek hayatta uygulama tek servis değil. Web, DB, cache, worker gibi parçalar var. Compose, bu parçaları tek dosyada tarifleyip tek komutla çalıştırır. Ekip içinde tutarlı ortam kurmanın en pratik yolu burada.

Yaygın hata
  • Compose ortamında servisler arası bağlantıda localhost kullanmak. Container içindeki localhost, o container’ın kendisi

Volume ve Network: Veri kalıcılığı ve servis iletişimi

Neden önemli? DB verisi gibi kalıcı şeyleri volume ile yönetmek gerekir. Network tarafında ise Compose, servisleri aynı ağda konuşturur ve servis adları DNS gibi çalışır.

Pratik ipucu
  • DB datası için named volume kullanmak, ekipte taşınabilirliği artırır
  • Bağlantı string’inde host olarak servis adını kullanmak çoğu bağlantı sorununu çözer
Hızlı Özet
  • Dockerfile image üretir
  • Image’dan container çalışır
  • Container geçicidir, kalıcı veri için volume gerekir
  • Compose servisleri aynı network’e koyar, servis adı DNS gibi çalışır
  • CLI komut gönderir, daemon işi yapar

Uygulama: Dockerfile + Compose ile gerçekçi bir kurulum

Basit ama gerçekçi bir örnek üzerinden gidelim: web uygulaması ve Postgres. Amaç şu: tek komutla ortam kalksın, DB datası kaybolmasın, servisler doğru konuşsun.

Mini örnek Dockerfile
bash
1FROM node:20-alpine
2WORKDIR /app
3
4# Cache için önce bağımlılıklar
5COPY package*.json ./
6RUN npm ci --omit=dev
7
8# Sonra kaynak kod
9COPY . .
10
11EXPOSE 3000
12CMD ["node", "server.js"]
docker-compose.yml örneği
bash
1services:
2  api:
3    build: .
4    ports:
5      - "3000:3000"
6    environment:
7      - DATABASE_URL=postgres://app:app@postgres:5432/appdb
8    depends_on:
9      - postgres
10
11  postgres:
12    image: postgres:16
13    environment:
14      - POSTGRES_USER=app
15      - POSTGRES_PASSWORD=app
16      - POSTGRES_DB=appdb
17    volumes:
18      - pgdata:/var/lib/postgresql/data
19    ports:
20      - "5432:5432"
21
22volumes:
23  pgdata:
Neden önemli?
  • DATABASE_URL içinde host postgres. Çünkü servis adı bu
  • pgdata named volume. Container silinse bile data kalır
  • Port çakışırsa host portu değiştirilebilir, container portunu sabit tutmak daha az karıştırır
Komutlar
bash
1docker compose up -d
2docker compose logs -f api
3docker compose exec api sh
4docker compose down

Yaygın hatalar ve anti-pattern’ler

“Her şeyi tek container yapayım”
  • Belirti: Debug zorlaşır, sorumluluklar karışır, küçük bir değişiklik büyük etki yaratır
  • Çözüm: Servisleri ayırmak. API ayrı, DB ayrı, gerekiyorsa worker ayrı
latest kullanmak
  • Belirti: Dün çalışan bugün bozulur, geri dönüş zorlaşır
  • Çözüm: Versiyon pinlemek. Örnek: postgres:16, node:20-alpine
Secret’ı image içine gömmek
  • Belirti: Registry’ye push sonrası geri dönüş yok, sızıntı riski büyür
  • Çözüm: Secret runtime’da verilir. Repo’ya yazılmaz, image içine gömülmez
“DB datası nereye gitti”
  • Belirti: Container yeniden başlayınca tablo yok, data yok
  • Çözüm: Named volume kullanmak. DB için bu genelde en temiz yol

Ne zaman Docker Run, ne zaman Docker Compose

İhtiyaçDocker runDocker Compose
Tek servis, hızlı denemeUygunFazla gelebilir
API + DB + cache gibi çoklu servisZorlaşırUygun
Ekipte ortak kurulumTutarsız olurUygun
Ortamı dokümante etmekKomutlar dağılırYAML net olur
Tek komutla kaldır indirZayıfGüçlü

Debug rutini: ps → logs → exec → inspect

Sorun çıktığında çoğu kez yeniden build almak yerine şu sırayı izlemek daha hızlı sonuç veriyor:

1. Container ayakta mı
bash
1docker ps
2. Log ne diyor
bash
1docker logs -f <container_name>
3. İçeriden kontrol
bash
1docker exec -it <container_name> sh
4. Detaylı teşhis
bash
1docker inspect <container_name>

Bu akış genelde port, env, host adı, volume ve network kaynaklı problemleri hızlı yakalatıyor.


Checklist: Minimum standart

Local geliştirme için
  • docker compose up ile tüm servisler tek komutla kalkıyor
  • DB için named volume var, restart sonrası data duruyor
  • Servis bağlantıları localhost değil servis adıyla çalışıyor
  • .dockerignore var, image gereksiz şişmiyor
  • Log takibi net: docker compose logs -f
Prod yaklaşımı
  • Image tag’leri pinli, latest yok
  • Secret’lar repo ve image içinde değil
  • Servis sınırları net, web ayrı db ayrı
  • Basit bir debug rutini dokümante edilmiş

Kısa sonuç / takeaway

  • Dockerfile image üretir, image’dan container çalışır
  • Container geçicidir, kalıcı veri volume ile çözülür
  • Compose ekip için standart ortam sağlar
  • Compose network’ünde servis adı DNS gibidir, localhost tuzağına düşme
  • Debug sırası zaman kazandırır: ps → logs → exec → inspect

Sonuç

Docker’ın pratikte fark yarattığı yer, tek seferlik çalıştırma değil; aynı kurulumu tekrar tekrar, farklı makinelerde, aynı sonuçla üretebilmek. Kavramlar net olunca iş basitleşiyor: Dockerfile image üretir, image container olarak çalışır, veri kalıcı olacaksa volume’a taşınır, birden fazla servis varsa Compose düzeni kurar. Bu temel oturduktan sonra geriye iki şey kalıyor: versiyonları sürpriz çıkarmayacak şekilde yönetmek ve sorun anında kısa bir debug akışıyla hızlı teşhis yapmak. Local’de başlayan bu disiplin, prod’a yaklaşırken de en çok yükü alan kısım oluyor.

Share this post

Link copied!
Mustafa Kürşad Başer

Mustafa Kürşad Başer

Software Engineer

A passionate software engineer who enjoys creating elegant solutions to complex problems. Beyond coding, I am deeply interested in exploring the intersections of technology, art, and human consciousness.

Cookie Preferences

We use cookies to provide you with a better experience. You can customize your settings for detailed information about analytic and advertising cookies.