Docker konteynerleştirmede multi-stage build mimarisi: İmaj boyutunu %80 küçültme, alpine/distroless kullanımı ve non-root güvenlik yapılandırma rehberi.
Hızlı Özet (TL;DR)
Geleneksel tek aşamalı (Single-Stage) Dockerfile yapılarında derleyiciler (SDK, GCC, Maven, TypeScript Compiler), ham kaynak kodlar, test paketleri ve geliştirme araçları (git, curl, wget, bash) son konteyner imajının içine gömülerek 1 GB’ı aşan hantal ve yüzlerce işletim sistemi güvenlik açığı (CVE) barındıran imajlar üretilir. Docker Multi-Stage Build (Çok Aşamalı Derleme) mimarisi, derleme (Build) ortamı ile çalışma zamanı (Runtime) ortamını birbirinden tamamen ayırır. Uygulama ilk aşamada geniş araç setine sahip bir imajda derlenir; nihai aşamada ise yalnızca derlenmiş çalıştırılabilir çıktı (binary veya bundle) ultra hafif ve sıkılaştırılmış bir tabana (Alpine Linux, Google Distroless veya scratch) kopyalanarak imaj boyutu 20–60 MB seviyesine indirilir.
1. Neden Tek Aşamalı (Single-Stage) Konteyner İmajları Tehlikelidir?
Kurumsal mikroservis ve on-premise sunucu mimarilerinde konteyner imajının şişkin olması yalnızca disk alanı sorunu değildir; doğrudan bir siber güvenlik ve operasyonel süreklilik riskidir:
- Geniş Saldırı Yüzeyi (Attack Surface) ve “Living off the Land” Tehdidi: Üretim konteynerinin içinde
curl,wget,nc(netcat),gccveya paket yöneticisi (apt/apk) bırakıldığında, uygulamada bir Uzaktan Kod Çalıştırma (RCE) açığı bulan saldırgan bu hazır araçları kullanarak dışarıdan kripto madencilik veya fidye yazılımı indirebilir ve iç ağdaki diğer sunuculara sıçrayabilir. - Yavaş CI/CD Dağıtımı ve Auto-Scaling Gecikmesi: 1.4 GB boyutundaki bir imajın Container Registry üzerinden çekilmesi (Pull), disk katmanlarının açılması ve Kubernetes/Docker Swarm düğümlerinde başlatılması dakikalar sürer. Oysa 35 MB’lık bir Multi-Stage imaj saniyeler içinde ayağa kalkar.
- Kaynak Kod ve Yapılandırma Sızıntısı: Tek aşamalı imajlarda derleme öncesi TypeScript, C# veya Go kaynak kodları ve ara katmanlardaki (Layer History) önbellek dosyaları imajın içinde unutulabilir.
2. Geleneksel Build ve Multi-Stage Build Karşılaştırması
İki konteynerleştirme yaklaşımı arasındaki mimari, performans ve güvenlik farkları aşağıdaki tabloda detaylandırılmıştır:
| Değerlendirme Kriteri | Standart Tek Aşamalı Dockerfile | Multi-Stage Build (Alpine / Distroless) Mimarisi |
|---|---|---|
| Nihai İmaj Boyutu | 850 MB – 1.6 GB (SDK ve devDependencies dahil) | 15 MB – 75 MB (%85 ila %95 oranında boyut tasarrufu) |
| İçerilen Sistem Paketleri | gcc, git, python, npm, apt/apk, bash, curl | Yalnızca derlenmiş çıktı (Binary/Dist) ve zorunlu çalışma zamanı |
| Güvenlik Açığı (CVE) Sayısı | Trivy/Grype taramalarında 150–400 arası OS zafiyeti | Sıfır veya sıfıra yakın işletim sistemi zafiyeti |
| Kabuk (Shell) Erişimi | Tam interaktif /bin/bash erişimi (Saldırıya açık) | Distroless/scratch tabanlarda kabuk yoktur (Reverse Shell imkansız) |
| CI/CD ve Ölçeklenme Hızı | Registry’den indirme ve başlatma 2–5 dakika sürer | 3–8 saniye içinde düğüme çekilir ve trafiği karşılar |
| Konteyner Kullanıcısı | Genellikle varsayılan root (UID 0) yetkisi | Ayrıcalıksız non-root (Örn: UID 10001) ve salt okunur kök dizin |
3. Üretim Ortamı İçin Multi-Stage Dockerfile Örnekleri
Çok aşamalı derleme mimarisinde her FROM satırı yeni ve temiz bir inşa aşaması başlatır. Önceki aşamada üretilen dosyalar COPY --from=<asama_adi> komutuyla seçici olarak son aşamaya aktarılır; geride kalan tüm derleme çöpleri nihai imaja dahil edilmez.
1. Kurumsal Node.js / TypeScript Mikroservis Mimarisi
Aşağıdaki yapılandırma, bağımlılık önbelleklemesini, derlemeyi ve ayrıcalıksız üretim çalışma zamanını üç katmanda ayırmaktadır:
# 1. Aşama: Yalnızca Üretim Bağımlılıkları (Prod Dependencies)
FROM node:20-alpine AS prod-deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force
# 2. Aşama: TypeScript Derleme (Builder)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json tsconfig.json ./
RUN npm ci
COPY src ./src
RUN npm run build
# 3. Aşama: Sıkılaştırılmış Çalışma Zamanı (Production Runner)
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Güvenlik: Varsayılan root yerine ayrıcalıksız node kullanıcısına geç
USER node
# Yalnızca temiz üretim modüllerini ve derlenmiş JS çıktısını kopyala
COPY --from=prod-deps --chown=node:node /app/node_modules ./node_modules
COPY --from=builder --chown=node:node /app/dist ./dist
COPY --from=builder --chown=node:node /app/package.json ./
EXPOSE 3000
CMD ["node", "dist/main.js"]
2. Go ve .NET / C# İçin Ultra Hafif Distroless Mimarisi
Go veya Rust gibi statik derlenen dillerde ya da .NET AOT projelerinde işletim sistemi paket yöneticisine dahi ihtiyaç yoktur. Google tarafından geliştirilen distroless taban imajları içinde /bin/sh veya /bin/bash bile bulunmaz:
# 1. Aşama: Go SDK ile Statik Binary Derleme
FROM golang:1.22-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o /build/fabrika-api ./cmd/api
# 2. Aşama: Kabuksuz (Shell-less) Google Distroless Tabanı
FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /app
COPY --from=builder /build/fabrika-api /app/fabrika-api
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app/fabrika-api"]
Bu imajın nihai boyutu yaklaşık 12 MB’tır ve içinde bir kabuk (Shell) bulunmadığı için saldırganların konteyner içinde komut satırı açması (Reverse Shell) mimari olarak imkansız hale gelir.
4. Konteyner Güvenliği ve BuildKit Optimizasyonu İçin 5 Kritik Kural
Kurumsal yazılım projelerinde Savunma Sanayii ve İmalat Siber Güvenlik standartlarını sağlamak için Multi-Stage Build yanında şu beş güvenlik ve performans kuralı uygulanmalıdır:
- Asla
rootOlarak Çalıştırmayın: Konteyner içindeki işlemroot(UID 0) yetkisine sahipse, olası bir Linux çekirdek veya çalışma zamanı (runc) kaçış zafiyetinde saldırgan ana fiziksel sunucuya (Host) tam yetkiyle erişebilir. Her zamanUSERdirektifi ile yetkisiz kullanıcı atanmalıdır. - Katı
.dockerignorePolitikası:.gitklasörü, yerel.envyapılandırma dosyaları,node_modules, test raporları ve IDE ayarları.dockerignoredosyasına eklenerek derleme bağlamına (Build Context) girmesi engellenmelidir. - Katman (Layer) Önbellekleme Sırası: Dockerfile içinde en az değişen dosyalar (
package.json,go.mod,.csproj) en üstte kopyalanmalı, sık değişen kaynak kodlar (COPY src ./src) ise bağımlılıklar indirildikten sonraki satıra konulmalıdır. Böylece tek satırlık kod değişikliğinde yüzlerce paket baştan indirilmez. - Salt Okunur Kök Dosya Sistemi (Read-Only Root Filesystem): Konteyner çalışırken kendi dosya sistemine yeni bir dosya yazamamalıdır (
--read-only). Geçici dosyalar için yalnızca bellekte çalışantmpfsbağlanmalıdır. - İmaj Taraması ve İmzalı Dağıtım: Üretilen her imaj CI/CD hattında Trivy veya Cosign ile taranmalı; kritik CVE bulunan imajların üretim sunucularına geçişi otomatik olarak durdurulmalıdır.
Yüksek performanslı, güvenli ve mikroservis uyumlu kurumsal yazılım altyapıları için Özel Yazılım Geliştirme, konteyner ve uygulama güvenliği denetimleri için Sızma Testi ve Pentest ve kurumsal sunucu çözümlerimiz için Ortak Dosya Sunucusu ve Yedekleme sayfalarımızı ziyaret edebilirsiniz.
Sıkça Sorulan Sorular
Alpine Linux tabanlı imajlar ile Distroless imajlar arasında nasıl seçim yapılmalıdır?
Alpine Linux, yaklaşık 5 MB boyutunda, musl libc kullanan ve içinde apk paket yöneticisi ile ash kabuğu barındıran çok hafif bir dağıtımdır; hata ayıklama (debugging) kolaylığı istediğimiz genel mikroservislerde idealdir. Ancak bazı Python (C eklentili) veya Node.js yerel modülleri glibc yerine musl kullanıldığında performans veya uyumluluk sorunu yaşayabilir. Distroless imajlar ise standart Debian glibc kütüphanelerini barındırmasına rağmen kabuk (sh/bash) ve paket yöneticisi içermez; maksimum güvenliğin hedeflendiği üretim (Production) ortamları için en güvenli seçenektir.
Derleme aşamasında özel (Private) Git veya NPM depolarına erişmek için kullanılan anahtarlar imaj katmanlarında kalır mı?
Eğer Dockerfile içinde ARG veya ENV ile erişim anahtarı tanımlarsanız ya da anahtar dosyasını kopyalayıp aynı aşamada silerseniz, ara katmanlarda veya derleme önbelleğinde izi kalabilir. Multi-Stage Build kullanıldığında önceki aşamada kalan dosyalar son aşamaya geçmese de, en güvenli ve modern yöntem Docker BuildKit Secret Mounts (RUN --mount=type=secret,id=npmrc) özelliğini kullanmaktır. Bu yöntemde kimlik bilgisi yalnızca komut çalışırken geçici olarak bellekte bağlanır ve hiçbir imaj katmanına asla yazılmaz.
Multi-Stage Build kullanmak CI/CD derleme (Build) süresini uzatır mı?
Hayır, doğru katman sıralaması ve Docker BuildKit önbellek bağlama (--mount=type=cache,target=/root/.npm) özellikleri kullanıldığında derleme süresi aksine kısalır. Ayrıca BuildKit, bağımsız aşamaları (örneğin ön yüz derlemesi ile arka uç derlemesini) paralel olarak aynı anda çalıştırır ve küçülen nihai imajın ağ üzerinden Registry’ye yüklenme (Push) ve sunuculara indirilme (Pull) süresini %80 oranında hızlandırır.