DOCKER NEDİR? CONTAİNER VE IMAGE MANTIĞI, LAYER YAPISI VE ÇALIŞMA PRENSİBİ
Bir uygulamayı “benim bilgisayarımda çalışıyordu” cümlesinden kurtaran en popüler yaklaşım, onu bulunduğu ortamdan bağımsız şekilde paketlemek. Docker tam olarak bu ihtiyacın pratik cevabı: Uygulamanızı bağımlılıklarıyla birlikte standart bir biçimde paketler, çalıştırır ve farklı ortamlarda tutarlı davranmasını sağlar.
Bu makalede Docker nedir sorusunu sadece tanımla geçmeyeceğiz; container ve image kavramlarını, image’ların katmanlı (layer) yapısını ve Docker’ın arka planda nasıl çalıştığını adım adım ele alacağız. Ayrıca gerçekçi Dockerfile ve komut örnekleriyle build ve run süreçlerini birlikte göreceğiz.
Hedefimiz; Docker’ı ezber komutlardan çıkarıp, mantığını kavradığınız bir araca dönüştürmek. Böylece performans, güvenlik ve bakım açısından daha doğru kararlar verebilir, troubleshooting sırasında da “neden böyle oldu?” sorusuna daha hızlı yanıt verebilirsiniz.

Docker nedir ve hangi problemi çözer?
Docker; uygulamaları, çalışma zamanı (runtime), bağımlılıklar ve temel yapılandırmalarla birlikte taşınabilir bir paket halinde çalıştırmayı sağlayan bir platformdur. Sanal makine mantığına benzetilse de Docker’ın temel farkı, tüm işletim sistemini kopyalamak yerine işletim sisteminin çekirdeğini (kernel) paylaşarak daha hafif bir izolasyon sağlamasıdır.
Bu yaklaşım, geliştirme ortamı ile test/üretim ortamı arasındaki farkları minimize eder. Aynı image, laptop’ta, CI/CD hattında ve Kubernetes üzerinde benzer şekilde çalışır. Böylece sürümleme, dağıtım ve geri dönüş (rollback) süreçleri daha öngörülebilir hale gelir.
Sanal makine ile container arasındaki temel fark
Sanal makineler hipervizör üzerinden ayrı işletim sistemi örnekleri çalıştırır. Container ise kernel’i paylaşır; izolasyonu namespaces ve kaynak sınırlamasını cgroups ile sağlar. Bu yüzden container başlatma süresi genellikle çok daha kısadır ve aynı sunucuda daha yoğun iş yükü taşımak mümkün olur.
Docker’ın günlük hayattaki kullanım senaryoları
- Uygulamayı tek bir artefact ile dağıtmak (image sürümleme)
- Yerel geliştirme ortamını standardize etmek (aynı bağımlılıklar, aynı runtime)
- CI/CD aşamalarında tekrarlanabilir build ve test ortamı sağlamak
- Mikroservis mimarisinde servisleri izole şekilde yönetmek
- Hızlı geri dönüş için immutable release mantığı uygulamak
Image nedir? Container nedir? Aralarındaki ilişki
Docker dünyasında iki temel kavram sürekli karşınıza çıkar: image ve container. Image; uygulamanın çalışması için gereken dosya sistemi içeriğini ve meta bilgileri barındıran, sürümlenebilir bir şablondur. Container ise bu image’ın çalışan (runtime) örneğidir.
Basit bir benzetme: Image bir kalıp, container o kalıptan üretilen ürün gibidir. Aynı image’dan birden fazla container başlatabilirsiniz. Bu sayede ölçekleme (scale out) mantığı da doğal şekilde oluşur.
Immutable image yaklaşımı neden önemlidir?
Image’lar “değişmez” varsayımıyla yönetildiğinde dağıtım süreci daha güvenilir olur. Üretimde çalışan sürümü düzeltmek için container içine girip dosya değiştirmek yerine yeni bir image üretip onu dağıtırsınız. Bu, sürüm kontrolünü netleştirir ve “o sunucuda özel bir ayar vardı” tarzı görünmez farklılıkları azaltır.
Container yaşam döngüsü: create, start, stop, rm
Container’lar bir yaşam döngüsüne sahiptir: oluşturulur, başlatılır, durdurulur ve gerekirse silinir. Çalışan container geçici bir process gibi ele alınır. Kalıcı veri ihtiyacı olduğunda genellikle volume gibi mekanizmalar devreye girer. Bu ayrım, stateful ve stateless bileşenleri doğru konumlandırmanıza yardım eder.
Layer yapısı: Docker image’lar neden katmanlıdır?
Docker image’ların en kritik tasarım özelliklerinden biri layer (katman) mimarisidir. Bir image, üst üste eklenen dosya sistemi değişiklikleri (diff) şeklinde katmanlardan oluşur. Her katman, bir öncekinin üzerine “sadece farkı” ekler. Böylece hem depolama hem de ağ üzerinden çekme (pull) süreci optimize olur.
Katman mantığı, yeniden kullanımın temelidir. Örneğin aynı base image’ı kullanan birden fazla proje, ortak katmanları tekrar tekrar indirmek zorunda kalmaz. Docker, mevcut katmanları cache’ten kullanır ve sadece eksik olanları indirir.
Copy-on-write ve union filesystem mantığı
Çoğu Linux sistemde Docker, overlay2 gibi sürücülerle union filesystem yaklaşımını uygular. Üst katmanda yazma olduğunda, değişen dosya copy-on-write ile container’a ait yazılabilir katmana taşınır. Bu sayede image katmanları değişmeden kalır; container ise kendi yazılabilir katmanına sahip olur.
Katman sıralaması performansı nasıl etkiler?
Dockerfile’daki her komut (özellikle RUN, COPY, ADD) yeni bir layer oluşturabilir. Sık değişen dosyaları daha alta koymak, cache kullanımını bozar. Bu nedenle bağımlılık kurulumları gibi daha stabil adımları önce; uygulama kaynak kodu gibi sık değişen adımları daha sonra konumlandırmak, build süresini ciddi şekilde iyileştirir.

Dockerfile mantığı: Build süreci nasıl işler?
Dockerfile, bir image’ın nasıl üretileceğini tarif eden deklaratif bir dosyadır. Docker build sırasında her adımı uygular, ortaya çıkan sonucu katmanlar halinde saklar ve mümkün olduğunda build cache kullanır. Bu cache, hem yerel geliştirmede hem de CI ortamında zaman kazandırır.
Dockerfile yazarken amaç; güvenli, küçük boyutlu ve hızlı build edilen image üretmektir. Bunun için base image seçimi, katmanların düzeni, gereksiz dosyaların dışarıda bırakılması (ör. .dockerignore) ve multi-stage build gibi teknikler önemli rol oynar.
Gerçekçi bir Dockerfile örneği (Node.js)
FROM node:20-alpine AS build
WORKDIR /app
# Bağımlılıkları önce kopyalayarak cache verimini artır
COPY package*.json ./
RUN npm ci
# Uygulama kaynak kodu
COPY . .
RUN npm run build
# Daha küçük bir runtime katmanı
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package.json ./
EXPOSE 3000
CMD ["node", "dist/server.js"]Bu örnekte multi-stage build ile derleme araçları ve geçici dosyalar final image’a taşınmaz. Sonuç: daha küçük image boyutu, daha az saldırı yüzeyi ve daha hızlı dağıtım.
.dockerignore ve bağlam (build context) yönetimi
Docker build, bulunduğunuz dizini “build context” olarak alır ve Docker daemon’a gönderir. Büyük context, build’i yavaşlatır ve gereksiz dosyaların image’a sızma riskini artırır. Bu yüzden node_modules, test çıktıları, yerel cache dosyaları gibi klasörleri .dockerignore ile dışarıda bırakmak iyi bir pratiktir.
Çalışma prensibi: Docker engine arka planda ne yapar?
Docker Engine; image yönetimi, container runtime ve ağ/volume gibi bileşenleri koordine eder. Container çalıştırdığınızda aslında bir process başlatırsınız; Docker ise bu process’i namespaces ile izole eder, cgroups ile kaynaklarını sınırlar ve image katmanlarını birleştirerek container’ın dosya sistemini hazırlar.
Modern kurulumlarda Docker, container runtime olarak containerd/runc gibi bileşenleri kullanır. Bu katmanlı mimari, ekosistemde standardizasyonu artırır ve orchestration araçlarıyla entegrasyonu kolaylaştırır.
Namespaces: izolasyonun temel taşları
PID, network, mount, UTS ve user namespaces gibi mekanizmalar; container’ın kendi process ağacını, ağ arayüzlerini ve mount alanını ayrı bir dünya gibi görmesini sağlar. Bu izolasyon sayesinde aynı makinede çalışan iki container birbirinin process’lerini doğal olarak görmez.
Cgroups: kaynak sınırları ve adil paylaşım
Cgroups ile CPU, bellek ve I/O gibi kaynaklar için limitler tanımlanabilir. Örneğin bellek sınırı koymadığınız bir container, yoğun yük altında host sistemin kararlılığını etkileyebilir. Üretim ortamında kaynak yönetimi, performans kadar güvenilirlik için de kritiktir.

Registry ve dağıtım: Image’lar nasıl paylaşılır?
Image’lar genellikle bir registry üzerinde saklanır: Docker Hub, GitHub Container Registry veya kurumsal private registry çözümleri gibi. Temel akış basittir: build ile image üretirsiniz, tag’lersiniz, push edersiniz; hedef ortamda pull edip çalıştırırsınız.
Tag stratejisi burada önem kazanır. Sadece “latest” kullanmak yerine semver (örn. 1.4.2) ve commit hash gibi izlenebilir etiketler kullanmak, geri dönüş ve izleme süreçlerini kolaylaştırır.
Build, tag, push, pull akışı
# Image üret
docker build -t myapp:1.0.0 .
# Alternatif tag ekle (registry hedefiyle)
docker tag myapp:1.0.0 registry.example.com/team/myapp:1.0.0
# Registry'ye gönder
docker push registry.example.com/team/myapp:1.0.0
# Başka bir ortamda çek ve çalıştır
docker pull registry.example.com/team/myapp:1.0.0
docker run -d --name myapp -p 3000:3000 registry.example.com/team/myapp:1.0.0Kurumsal ortamlarda image imzalama, vulnerability scanning ve policy enforcement gibi adımlar da bu akışa eklenir. Böylece hem güvenlik hem de uyumluluk (compliance) açısından daha kontrollü bir dağıtım hattı oluşur.
Volume ve network: Kalıcı veri ve iletişim nasıl ele alınır?
Container’lar doğası gereği geçicidir; yeniden başlatıldığında yazılabilir katmandaki veriler kaybolabilir. Kalıcı veriler için volume kullanılır. Volume; host üzerinde veya bir storage sürücüsü üzerinde tutulur ve container’lara mount edilerek uygulamanın verisini image’dan ayırır.
Network tarafında Docker; bridge, host, overlay gibi farklı sürücüler sunar. Yerel geliştirmede bridge yaygındır; orchestrated ortamlarda overlay benzeri çözümlerle servisler arası iletişim yönetilir.
Volume kullanımı hangi durumlarda kritik olur?
Veritabanları, dosya yükleme alanları, queue sistemlerinin kalıcı kuyruğu gibi bileşenlerde veri kaybı kabul edilemez. Bu tip stateful servislerde volume planlaması; yedekleme, erişim izinleri ve performans kriterleriyle birlikte düşünülmelidir.
Servis keşfi ve container’lar arası iletişim
Container’lar aynı network içinde DNS tabanlı ad çözümleme ile birbirine erişebilir. Bu da “IP adresi değişti” problemini azaltır. Daha ileri senaryolarda reverse proxy, ingress ve service mesh gibi yaklaşımlar devreye girer; ancak temel mantık, network izolasyonu ve kontrollü iletişim etrafında şekillenir.
En iyi pratikler: Küçük, güvenli ve hızlı image üretmek
Docker’ı etkin kullanmak, sadece container çalıştırmak değil; doğru image üretmekle başlar. Image boyutu büyüdükçe çekme süreleri artar, güvenlik taramasında daha fazla paket ortaya çıkar ve bakım yükü büyür. Bu yüzden basit ama etkili pratikler büyük fark yaratır.
Base image seçimi ve saldırı yüzeyi
Alpine gibi minimal tabanlar image’ı küçültür; ancak bazı kütüphane uyumluluklarında ek çalışma gerektirebilir. Distroless gibi yaklaşımlar, runtime’ı daha da sadeleştirir. Seçim yaparken performans, uyumluluk ve güvenlik gereksinimlerini birlikte değerlendirmek gerekir.
Cache verimi için katman stratejisi
Bağımlılık dosyalarını önce kopyalamak, build cache’ten maksimum fayda sağlar. Ayrıca tek bir RUN komutunda paket kurulumlarını birleştirmek, layer sayısını azaltabilir. Gereksiz dosyaları temizlemek ve multi-stage kullanmak da image’ı optimize eder.
Docker’ı daha hızlı öğrenmek için yön haritası
Eğer Docker kavramları oturmaya başladıysa, bir sonraki adım pratik kası geliştirmektir: Dockerfile yazma, image optimizasyonu, registry süreçleri ve container troubleshooting. Bu noktada yapılandırılmış bir müfredat, deneme-yanılma süresini ciddi ölçüde azaltır.
İsterseniz Docker eğitimi sayfasından, temelden ileri düzeye uzanan bir akışla container, image, network, volume ve CI/CD entegrasyonunu birlikte ele alan programı inceleyebilirsiniz.
Özetle; Docker nedir sorusunun cevabı sadece bir araç tanımı değildir. Docker; uygulamayı taşınabilir, sürümlenebilir ve tutarlı bir şekilde çalıştırma yaklaşımıdır. Image ve layer mantığını kavradığınızda, hem build süreçleriniz hızlanır hem de üretim ortamında daha kontrollü bir operasyon yürütürsünüz.


