Image Boyut Optimizasyonu — Alpine, distroless, scratch
Bu bölümün son dersine geldik. Multi-stage build ile build araçlarını ayırdık, layer caching ile build süresini düşürdük, dil bazlı optimizasyon tekniklerini öğrendik. Bu derste son parçayı yerine koyacağız: base image seçimi, minimal image stratejileri ve güvenlik taraması.
Bir ev yapıyorsun diyelim. İnşaat bitti, boyandı, mobilyalar konuldu. Ama avluda hâlâ inşaat molozları duruyor. Bahçe düzenlenmemiş, gereksiz malzemeler toplanmamış. İç güzel ama dış bakımsız — hem kötü görünür hem de güvenlik açığı (birisi molozların arkasına saklanabilir). Docker image'ın da öyle: çalışıyor ama içinde gereksiz paketler, shell, debug araçları varsa — hem büyük hem de saldırı yüzeyi geniş.
Base Image Seçimi — Her Şeyin Temeli
Base image seçimi, image boyutunu ve güvenliğini belirleyen en temel karar. Aynı uygulamanın farklı base image'larla boyutu:
Base Image Boyut Güvenlik Debug
────────────────────────────────────────────────────────────
ubuntu:22.04 77 MB Orta Kolay
debian:bookworm 124 MB Orta Kolay
debian:bookworm-slim 74 MB İyi Orta
alpine:3.19 7 MB İyi Zor
distroless/base-debian12 20 MB Çok iyi Çok zor
scratch 0 MB Mükemmel İmkansızDebian Slim
"Slim" varyantlar, full Debian'dan gereksiz dosyaları çıkarır (man pages, docs, bazı kütüphaneler):
FROM python:3.12-slim
# python:3.12 → 1.0 GB
# python:3.12-slim → 130 MB (7x daha küçük!)Çoğu proje için slim en iyi denge noktasıdır. Çoğu paket sorunsuz çalışır, boyut makul.
Alpine
Alpine Linux musl libc + BusyBox kullanır — çok kompakt ama bazı uyumsuzluklar olabilir:
FROM node:20-alpine
# node:20 → 1.1 GB
# node:20-alpine → 130 MB (8x daha küçük!)Alpine ile karşılaşabileceğin sorunlar:
musl vs glibc uyumsuzluğu: Bazı native binary'ler (özellikle pre-built olanlar) glibc bekler ama Alpine musl kullanır. bcrypt, sharp, grpc gibi paketlerde sorun olabilir:
# Hata: Error loading shared library: libc.musl-x86_64.soÇözüm: bu paketleri Alpine'da source'dan compile et veya alpine uyumlu versiyonunu kullan:
FROM node:20-alpine
RUN apk add --no-cache python3 make g++ # Native build araçları
COPY package*.json ./
RUN npm ciDNS çözümleme farklılığı: Alpine'ın DNS resolver'ı bazı kurumsal DNS yapılandırmalarında sorun çıkarabilir.
Alpine ne zaman kullanmalı? Basit Go/Rust binary'ler ve sorunsuz çalıştığını test ettiğin projeler için.
Google Distroless
Distroless image'lar Google tarafından üretilir. İçinde sadece uygulamanın çalışması için gereken minimum bileşenler var — shell yok, paket yöneticisi yok:
# Go için
FROM gcr.io/distroless/static-debian12
# 2 MB — statik binary'ler için
# Java için
FROM gcr.io/distroless/java21-debian12
# ~200 MB — JRE dahil
# Node.js için
FROM gcr.io/distroless/nodejs20-debian12
# ~130 MB — Node.js runtime dahil
# Python için
FROM gcr.io/distroless/python3-debian12
# ~50 MB — Python runtime dahilShell olmadığı için docker exec -it container sh çalışmaz! Debug etmek için "debug" varyantını kullan:
# Production
FROM gcr.io/distroless/static-debian12
# Debug (shell dahil — sadece development/debugging için)
FROM gcr.io/distroless/static-debian12:debugscratch
Tamamen boş image. İçinde hiçbir şey yok — dosya sistemi bile yok. Sadece statik binary'ler için (Go, Rust):
FROM scratch
COPY --from=builder /myapp /myapp
ENTRYPOINT ["/myapp"]Karar Matrisi
Senaryo Önerilen Base Image
────────────────────────────────────────────────────────
Go/Rust statik binary scratch veya distroless/static
Java Spring Boot eclipse-temurin:XX-jre-alpine
Node.js production node:XX-alpine veya distroless
Python production python:3.XX-slim
Genel amaçlı, debug kolaylığı debian:bookworm-slim
Maximum güvenlik, minimum boyut distrolessGereksiz Dosyaları Temizle
Image'da kalmaması gereken şeyleri temizlemek boyutu önemli ölçüde düşürür.
apt Cache Temizliği
# ❌ KÖTÜ — cache kalıyor
RUN apt-get update
RUN apt-get install -y curl
# apt cache image'da kalır — 50-100MB boşa gider
# ✅ İYİ — tek layer'da temizle
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*--no-install-recommends önerilen ama gerekli olmayan paketleri yüklemez — ciddi boyut tasarrufu.
apk (Alpine) Temizliği
RUN apk add --no-cache curl wget
# --no-cache: index cache'i tutmazpip Cache
RUN pip install --no-cache-dir -r requirements.txtnpm Cache
RUN npm ci && npm cache clean --force
# Veya daha iyisi: multi-stage build ile production node_modules ayrıTemp Dosyaları
# Build sonrası gereksiz dosyaları sil
RUN npm run build && \
rm -rf src/ test/ .eslintrc .prettierrc tsconfig.json && \
npm prune --productionNon-Root User — Güvenlik Temeli
Container'lar varsayılan olarak root kullanıcıyla çalışır. Bu büyük bir güvenlik riski — container'dan kaçılırsa (container escape) host'ta root yetkisi elde edilebilir:
# ❌ KÖTÜ — root olarak çalışıyor
FROM node:20-alpine
WORKDIR /app
COPY . .
CMD ["node", "server.js"]# ✅ İYİ — non-root user
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
CMD ["node", "server.js"]Bazı resmi image'lar zaten non-root user tanımlar:
# Node resmi image'ında "node" user'ı var
FROM node:20-alpine
USER node
# PostgreSQL'de "postgres" user'ı var
FROM postgres:16-alpine
# Zaten postgres olarak çalışırVolume izin sorunu çıkarsa (permission denied):
RUN mkdir -p /app/data && chown appuser:appgroup /app/data.dockerignore Optimizasyonu
Kapsamlı bir .dockerignore hem build hızını hem de güvenliği artırır:
# .dockerignore
# Version control
.git
.gitignore
# Dependencies (container'da yeniden yüklenecek)
node_modules
vendor
__pycache__
*.pyc
.venv
# Build artifacts
dist
build
target
*.jar
# IDE
.vscode
.idea
*.swp
*.swo
# Docker
Dockerfile*
docker-compose*
.dockerignore
# Docs & tests
*.md
LICENSE
docs
test
tests
coverage
.nyc_output
# Environment & secrets
.env
.env.*
*.pem
*.keyGüvenlik açısından en kritik satırlar: .env, *.pem, *.key — bunlar asla image'a girmemeli!
Güvenlik Taraması — Vulnerabilities
Image'ını build ettin, boyutu küçülttün. Ama içinde bilinen güvenlik açıkları olabilir — eski bir OpenSSL, zafiyetli bir kütüphane. Bunları taramak zorunlu.
Docker Scout
# Image'ı tara
docker scout cves myapp:latest
# Öneriler
docker scout recommendations myapp:latestTrivy (Aqua Security)
# Kurulum
docker pull aquasec/trivy
# Image tara
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image myapp:latest
# Sadece HIGH ve CRITICAL
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --severity HIGH,CRITICAL myapp:latestÇıktı:
myapp:latest (alpine 3.19)
Total: 2 (HIGH: 1, CRITICAL: 1)
┌──────────────┬────────────────┬──────────┬───────────────────┐
│ Library │ Vulnerability │ Severity │ Fixed Version │
├──────────────┼────────────────┼──────────┼───────────────────┤
│ libcrypto3 │ CVE-2024-XXXX │ CRITICAL │ 3.1.4-r5 │
│ curl │ CVE-2024-YYYY │ HIGH │ 8.5.0-r1 │
└──────────────┴────────────────┴──────────┴───────────────────┘CI/CD'de Otomatik Tarama
# GitHub Actions
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:latest
format: 'table'
exit-code: '1' # CRITICAL varsa pipeline fail
severity: 'CRITICAL,HIGH'exit-code: '1' sayesinde CRITICAL güvenlik açığı bulunursa deploy engellenir.
Image Metadata — Labels
Image'a metadata eklemek yönetim kolaylığı sağlar:
LABEL maintainer="team@example.com"
LABEL org.opencontainers.image.source="https://github.com/org/repo"
LABEL org.opencontainers.image.version="1.2.3"
LABEL org.opencontainers.image.description="Blog Platform API"docker inspect myapp:latest --format='{{json .Config.Labels}}' | jqTam Optimizasyon Checklist
Şimdi bu bölümde öğrendiğimiz her şeyi bir checklist'te toplayalım:
☐ Multi-stage build kullan — build araçları final image'da olmasın
☐ Minimal base image seç — alpine, slim veya distroless
☐ Non-root user ile çalıştır
☐ .dockerignore kapsamlı olsun — .git, node_modules, .env
☐ Layer cache'i optimize et — dependency dosyalarını önce kopyala
☐ RUN komutlarını birleştir ve cache temizle
☐ BuildKit cache mount kullan
☐ Gereksiz dosyaları sil — docs, test, cache
☐ Güvenlik taraması yap — Trivy veya Docker Scout
☐ HEALTHCHECK tanımla
☐ Resource limitleri koy (Compose'da)
☐ Labels ekle — maintainer, version, sourceGerçek Dünya Optimizasyon Örneği
Optimizasyon öncesi ve sonrasını karşılaştıralım:
# ❌ ÖNCE — 1.2 GB, root user, güvenlik açıkları
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/server.js"]# ✅ SONRA — 150 MB, non-root, güvenli, cache-friendly
# syntax=docker/dockerfile:1
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci --only=production
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
USER nonroot
EXPOSE 3000
CMD ["dist/server.js"]Metrik Önce Sonra
─────────────────────────────────────────────
Image boyutu 1.2 GB 150 MB
Build süresi (ilk) 4 dakika 3 dakika
Build süresi (cache) 4 dakika 20 saniye
Güvenlik açığı 47 3
Root çalışma Evet Hayır
Shell erişimi Evet HayırImage boyutu %88 küçüldü, cache'li build 12x hızlandı, güvenlik açıkları %94 azaldı. Ve bunu yapmak için sadece Dockerfile'ı değiştirmemiz yetti — uygulama koduna dokunmadık.
Bu Derste Ne Öğrendik?
Base image seçimi her şeyin temeli — alpine (7MB), slim (74MB), distroless (20MB), scratch (0MB).
Distroless image'lar shell içermez — saldırı yüzeyi minimum ama debug zor.
Alpine'ın musl/glibc uyumsuzluğuna dikkat — test et.
Non-root user ile çalıştır — güvenlik açısından zorunlu.
Cache'leri temizle:
rm -rf /var/lib/apt/lists/*,--no-cache-dir,npm cache clean.Güvenlik taraması (Trivy, Docker Scout) CI/CD pipeline'ına entegre et.
Tam optimizasyon 1.2GB → 150MB, 47 CVE → 3 CVE düşüş sağlayabilir.
Bu, Docker image optimizasyonu bölümünün son dersiydi. Artık küçük, hızlı ve güvenli Docker image'ları oluşturmayı biliyorsun. Tebrikler — Docker'ın temellerinden ileri seviye optimizasyona kadar uzun bir yol kat ettin!
AI Asistan
Sorularını yanıtlamaya hazır