DevOps

Docker İmajını Küçültmek: 1,58 GB’dan 186 MB’a

Bakın şimdi, Docker dünyasında en sevdiğim ama aynı zamanda en çok sinir olduğum şey şu: Herkes küçücük bir imaj görünce mutlu oluyor (kendi tecrübem). “Tamamdır, ship ederiz” deniyor. Sonra gece 23.17’de prod ortamı çat diye düşüyor… ve kimse nedenini ilk anda bilmiyor.

Şunu söyleyeyim, Bu yazı tam da o rahat anı bozmak için var (ciddiyim). Çünkü mesele sadece imajı şişirmek ya da inceltmek değil; neyi çıkardığını, neyi geride bıraktığını (ciddiyim). Hangi bedeli ödediğini de bilmek gerekiyor. Ben de bunu yıllar önce, 2023 sonbaharında Kadıköy’de küçük bir SaaS projesinde yaşadım — build boyutu yarıya indi diye ekip sevinçten havaya uçtu, tamam güzel, ama iki gün sonra loglarda eksik sertifika yüzünden saçma sapan TLS hataları görmeye başladık. Hani “küçülttük ya, mükemmel” dediğin tam o noktada iş biraz çetrefilli hale geliyor işte — valla güzel iş çıkarmışlar —

Bunu biraz açayım.

Docker İmajı Neden Şişiyor?

İşin aslı şu: Docker imajı, uygulamanızın sadece kodunu değil, çalışması için gereken runtime’ı, bağımlılıkları, işletim sistemi katmanlarını ve bazen de gereksiz olan her şeyi birlikte taşıyor. Düşünün, yerel makinede çalışan bir Node.js uygulaması var — sizde Node kurulu, doğru paketler hazır, sistem temiz. Başka bir sunucuda bunların hiçbiri yoksa, işte Docker tam burada devreye giriyor ve “al sana paketlenmiş çalışma ortamı” diyor. İlginç, değil mi? Güzel konsept.

Ama tutorial’lar genelde hikâyenin yarısında duruyor. “İmaj oluştu.” Tamam. Peki kaç megabayt? İçinde build araçları niye var? Neden test dosyaları da taşınmış? Açık konuşayım, ben de ilk zamanlar buna pek bakmıyordum — 2019’da Levent’te çalıştığım ekipte bir proje vardı, dışarıdan tertemiz görünen image aslında içinde npm cache’ten tutun da kullanılmayan OS paketlerine kadar her şeyi saklıyordu. Fark ettik mi ilk başta? Neyse, hayır.

Şimdi gelelim işin can alıcı noktasına.

Kritik nokta şu: Her katman kalıcı oluyor (ki bu çoğu kişinin gözünden kaçıyor). Yani RUN npm install ile gelen yük öyle geçici değil… imaja yapışıyor. COPY.. ile yanlışlıkla eklediğiniz dosyalar da aynı şekilde taşınıyor — bavul hazırlarken valize ütü masası koymak gibi bir şey bu; taşınır. Gerek var mı? Pek yok.

.dockerignore ile.gitignore Aynı Şey Değil

Bunu ayrı başlık yapıyorum çünkü bu hatayı kendi ellerimle yaptım. Geçen yıl Şişli’deki ofiste yeni açılan bir projede .dockerignore dosyasını ekledim ama .gitignore kısmını aceleye getirdim. Sonuç mu? node_modules klasörü repoya girdi ve Git geçmişini temizlemek için saatlerce uğraştık.

.dockerignore, Docker’ın build context içine ne almayacağını söyler. .gitignore ise Git’e neyi izlemeyeceğini anlatır. Benzer şeyleri dışarıda bırakabilirler ama görevleri farklı — biri mutfağa hangi malzemenin girmeyeceğini söylüyor, diğeri market listesine ne yazılmayacağını. Karıştırınca ortalık hafif dağılıyor, evet. Bu konuyla ilgili Butterfly CSS: 2026’da Dikkat Çeken Hafif Bir Seçenek yazımıza da göz atmanızı tavsiye ederim.

💡 Bilgi: Küçük görünen bu iki dosya, özellikle CI/CD akışlarında hayat kurtarır. Build süresi kısalır, gereksiz veri konteynere girmez ve yanlışlıkla gizli dosya taşıma riskiniz azalır.

Büyük İmajdan Hafif İmaja Giden Yol

Klasik başlangıç çoğu zaman şöyle olur: PDF Dünyasında Bir Nefes: Ücretsiz ve Limitsiz Araçlar yazımızda bu konuya da değinmiştik.

FROM node:18
WORKDIR /app
COPY package*.json./
RUN npm install
COPY..
CMD ["node", "app.js"]

Düzgün görünüyor değil mi? Yeni başlayan biri için öğretici bile sayılır. Ama pratikte bu yapı sizi ağır bir base image’a bağlar ve üstüne tüm bağımlılıkları tek katta yığar (ciddiyim). Ben bunu ilk kez ölçtüğümde dürüst olayım, monitöre biraz boş boş baktım — sonuç yaklaşık 1,58 GB çıkmıştı. İnsan istemsiz bir “ya” sesi çıkarıyor işte o an. LCEL Nedir? LangChain’te Akış Kurmanın Temiz Yolu yazımızda bu konuya da değinmiştik.

Açıkçası, Neyse… Sorun çoğu zaman app’in kendisi değildi, sorun etrafındaki şişkinlikti. Hele bir de node:18 gibi Debian tabanlı image’lar geliştirme kolaylığı sağlıyor, bunu teslim edeyim, ama üretimde ihtiyacınız olmayan derleyicileri, yardımcı araçları. Fazladan paketleri de beraberinde getiriyor. SQL’e Dönüşün İlk Günü: Konsantrasyon, Notlar, İnat yazımızda bu konuya da değinmiştik.

Aşama Neler Var? Etkisi Bana Göre Durumu
Tutorial tarzı tek katmanlı build Tam OS + build tool + runtime + kaynak kodu Büyük boyut, yavaş deploy Kötü değil ama prod için ham kalıyor
Ayrılmış multi-stage build Sadece gerekli runtime artıkları Daha küçük image, daha hızlı çekme süresi Bayağı iyi çalışıyor
Agresif minimal base image (Alpine vb.) Mantıklı kesinti ama sınırlamalar var Küçük boyut fakat uyumluluk riski Dikkatli kullanılmalı

Neden Multi-Stage Build Fark Yaratıyor?

Lafı gevelemeden söyleyeyim: Multi-stage build güzel çünkü derleme ortamıyla çalışma ortamını birbirinden ayırıyor. Birinci aşamada her şey serbest — compiler olsun, npm olsun, test aracı olsun. İkinci aşamada ise sadece koşması gereken parçalar kalıyor. İnşaat sırasında kullanılan iskeleyle oturulacak koltuğu aynı kutuya koymuyorsunuz. Mantık bu kadar basit aslında.

2024 Mart ayında İstanbul’da lokal bir örnek kurdum, editör masasında bu konuyu yeniden test ederken — önce klasik build aldım, sonra multi-stage’e geçtim, boyut farkını görünce şaşırmadım diyemem. Bir noktada image neredeyse dörtte bire indi. Ama az önce söylediklerimi unutmayın: kazanırken bazı şeyleri de kaybediyorsunuz. Mesela debug alışkanlığınız değişiyor, container içine girip rastgele komut çalıştırmak eskisi kadar kolay olmuyor. Bu kötü mü? Hayır. Sadece disiplin istiyor.

Küçük image neredeyse her zaman daha iyi demek değil; asıl mesele ihtiyaç duyduğunuz parçayı bırakıp geri kalan gürültüyü atabilmek.

Peki Alpine Gerçekten Kurtarıcı mı?

Ne yalan söyleyeyim, Tabi herkesin aklına hemen Alpine geliyor, hafifliğiyle meşhur çünkü. Kağıt üstünde süper görünüyor: az yer kaplıyor, saldırı yüzeyi daralıyor, pull süresi düşüyor. Ama pratik biraz farklı çıkıyor bazen. Ben Alpine’i ilk kez Ankara’daki ev lab’ında denediğimde bazı native modüllerin patladığını gördüm — özellikle glibc yerine musl kullanımı yüzünden ufak sürprizler çıktı ortaya. Hayal kırıklığı dediğim tam olarak buydu: “küçük oldu” diye sevinirken birkaç kütüphanenin garipleşmesi insanın hevesini kaçırabiliyor.

Küçük startup tarafında Alpine çoğu zaman iş görür — basit API servisleri, hafif worker süreçleri, çok özel binary beklentisi olmayan projeler, bunlarda bayağı mantıklı olabilir. Ama enterprise seviyede işler değişiyor: uyumluluk testi ister, gözlemleme araçları ister, sertifika zinciri ister, hatta bazen vendor bağımlılıkları yüzünden beklenmedik patlamalar yaşarsınız (şaşırtıcı ama gerçek). O yüzden “Alpine = otomatik çözüm” kafası bana göre fazla rahatçı kalıyor. Temkinli olun.

Kazanç Nerede Başlıyor?

  • Daha hızlı pull süresi — özellikle CI/CD hattında ciddi fark yaratıyor. (bu kritik)
  • Daha düşük registry maliyeti — büyük ekiplerde sessiz sedasız bütçe yemez.
  • Daha küçük saldırı yüzeyi — gereksiz paket sayısı azalınca güvenlik tarafı nefes alıyor.
  • Daha düzenli Dockerfile — temizlik biraz zorunlu hale geliyor zaten.
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package*.json./
RUN npm ci
COPY..
RUN npm run build
FROM node:lts-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist./dist
COPY --from=builder /app/package*.json./
RUN npm ci --omit=dev && apk add --no-cache dumb-init
CMD ["dumb-init", "node", "dist/app.js"]

Bunu doğrudan çalışan örnek gibi düşünmeyin; fikir vermesi için koyuyorum. Buradaki oyun şu: ilk aşamada derliyorsun, ikinci aşamada sadece çıktıyı taşıyorsun. Evden eve taşınırken bütün evi kamyonete doldurmak yerine yalnızca lazım olan eşyaları almak gibi bir şey — kolay görünür, ama fark büyük olur. Ben bunu geçen ay İzmir’deki bir freelance projede kullandım; build süresi aşağı yukarı %35 düştü, image boyutu da ciddi biçimde küçüldü. Tabi burada dependency ağacının yapısı — itiraz edebilirsiniz tabi — önemliydi, her proje aynı sonucu vermez. Az önce söyledim ya — küçülme etkileyici, ama sihir değil. Bu konuyla ilgili Apple Watch’a Nisan Sürprizi: İki Yeni Aktivite Mücadelesi yazımıza da göz atmanızı tavsiye ederim.

Peki Ne Bozuluyor?

Şimdi gelelim can sıkıcı tarafa. Image küçülünce bazen debug araçlarını kaybediyorsunuz, bazen shell bile beklediğiniz gibi davranmıyor, bazen de sertifika paketi eksik olduğu için HTTPS çağrıları tökezliyor. Yani optimizasyon güzel… ama üretimde minik bir kıymık gibi batabiliyor.

Bir startup’ta hız önceliklidir; kurumsalda ise stabilite çoğu zaman hızdan önde gelir. O yüzden aynı Dockerfile’ı iki yere aynen taşımak pek mantıklı olmaz — bence çok yerinde bir karar —. Startup tarafında slim veya Alpine ile gayet yol alınabilir, enterprise tarafında ise daha kontrollü base image seçimi yapmak, security scanning eklemek ve smoke test’i sıklaştırmak gerekiyor.

Ben kendi adıma artık şuna dikkat ediyorum: kodu küçültmeden önce ölç, sonra değiştir, sonra tekrar ölç. Bunu yapmadan atılan her adım biraz kumar gibi oluyor (en azından benim deneyimim böyle). Neyse…

Sıkça Sorulan Sorular

Docker imajını küçültmek neden önemli?

Daha hızlı indirme, daha kısa deploy süresi ve daha az depolama tüketimi sağlar.

Multi-stage build herkese uygun mu?

Evet sayılır ama özellikle production’a çıkan uygulamalarda en faydalıdır.

Alpine kullanmak güvenli mi?

Bazı projelerde evet; fakat native modüller veya glibc bağımlılığı varsa dikkat etmek gerekir.

.dockerignore gerçekten şart mı?

Evet! Gereksiz dosyaların build context’e girmesini engeller ve işleri temiz tutar.

Kaynaklar ve İleri Okuma


Docker Multi-Stage Builds Dokümantasyonu
Docker Ignore Dosyaları Rehberi
Node Resmi Docker Image Sayfası

Aşkın KILIÇ

20+ yıl deneyimli Azure Solutions Architect. Microsoft sertifikalı bulut mimari ve DevOps danışmanı. Azure, yapay zekâ ve bulut teknolojileri üzerine Türkçe teknik içerikler üretiyor.

AZ-305AZ-104AZ-500AZ-400DP-203AI-102

Bu içerik işinize yaradı mı?

Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.

Haftalık Bülten

Her pazar özenle seçilmiş teknoloji yazıları doğrudan e-postanıza gelsin.

← Onceki Yazi
Baby Steps Ekibinin Speedrun Şakası: Map Verip Dalga Geçtiler
Sonraki Yazi →
GA4’ü Bırakıp Next.js + Supabase’e Geçmek: Neden?

Yorum Yaz

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Haftalık Bülten

Azure, DevOps ve Yapay Zeka dünyasındaki en güncel içerikleri her hafta doğrudan e-postanıza alın.

Spam yok. İstediğiniz zaman iptal edebilirsiniz.
📱
Uygulamayı Yükle Ana ekrana ekle, çevrimdışı oku
Kategoriler
Ara
Paylaş
İçindekiler
← Baby Steps Ekibinin Speedrun Ş...
GA4’ü Bırakıp Next.js + Supaba... →
📩

Gitmeden önce!

Her pazar özenle seçilmiş teknoloji yazıları ve AI haberleri doğrudan e-postanıza gelsin. Ücretsiz, spam yok.

🔒 Bilgileriniz güvende. İstediğiniz zaman ayrılabilirsiniz.

📬 Haftalık bülten: Teknoloji + AI haberleri