Ulaşım
- Adres:2342 Sk, İpekyol, İpek Ap 49A, 63250 Haliliye/Şanlıurfa
- Telefon:
0542 315 45 37 - eMail: info@alestaweb.com
Docker image'larınız gigabyte'larca mı yer kaplıyor? Production ortamında dev tools, test dosyaları, kaynak kodlar gereksiz yere bulunuyor mu? Alesta Web olarak yüzlerce DevOps projesinde karşılaştığımız bu probleme kesin çözüm: Docker multi-stage build. Bu rehberde, image boyutunu %80 küçülten bu tekniği (reduce Docker image size by 80%) adım adım öğreneceksiniz — Node.js, Go ve Python örnekleriyle.
Docker multi-stage build, tek bir Dockerfile içinde birden fazla FROM komutu kullanarak farklı "stage" (aşama) tanımlamanıza olanak tanıyan bir tekniktir. Alesta Web ekibi olarak bunu şöyle açıklıyoruz: bir "inşaat aşaması" ve bir "çalışma aşaması" düşünün. İnşaat aşamasında tüm derleme araçlarını kullanırsınız; çalışma aşamasında yalnızca gereken binary dosyayı kopyalarsınız.
Docker 17.05 sürümüyle 2017'de hayatımıza giren bu özellik (introduced in Docker 17.05), özellikle compiled dillerde (Go, Java, Rust) devrimsel bir etki yarattı. Ama Node.js, Python gibi yorumlanan dillerde de son derece etkili. Yani hangi stack'i kullanırsanız kullanın, docker multi-stage build işinize yarayacak.
Docker multi-stage build öncesinde geliştiriciler ayrı "builder" image'ları oluşturup shell script'lerle birleştirirdi. Bu hem karmaşık hem de bakımı zordu (maintainability issues). Multi-stage build bu süreci tek Dockerfile'a indirdi.
Somut bir örnek verelim. Standart bir Node.js uygulaması için node:18 base image kullandığınızda boyut yaklaşık 1 GB'a çıkabiliyor. Aynı uygulamayı docker multi-stage build ile node:18-alpine final stage kullanarak oluşturduğunuzda boyut 150-200 MB'a iniyor. Go uygulamalarında bu fark daha da dramatik: 800 MB → 10 MB. Yani %98 küçülme (98% size reduction).
Ama boyut tek fayda değil. Alesta Web'in DevOps projelerinde gözlemlediğimiz somut avantajlar şunlar:
| Teknoloji | Normal Image | Multi-Stage Image | Küçülme / Reduction |
|---|---|---|---|
| Node.js | ~1 GB | ~150 MB | ~85% |
| Go | ~800 MB | ~10 MB | ~98% |
| Python | ~1.2 GB | ~200 MB | ~83% |
| Java (Spring Boot) | ~700 MB | ~120 MB | ~83% |
Docker multi-stage build için Dockerfile yapısını öğrenmek sanıldığı kadar zor değil. Temel kural şu: her FROM komutu yeni bir stage başlatır. Stage'lere isim verebilirsiniz (AS builder gibi) ve son stage production image'ı oluşturur.
# Stage 1: Builder (inşaat aşaması)
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Stage 2: Production (çalışma aşaması)
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]
Dikkat edin: COPY --from=builder komutu (copy from stage), önceki stage'den dosya kopyalamanın anahtarı. Bu sayede builder stage'indeki tüm araçlar, kaynak kodlar, test dosyaları production image'ına dahil olmuyor.
Stage'leri isimle veya sıra numarasıyla belirtebilirsiniz: COPY --from=0 (0. stage) ya da COPY --from=builder (isimle). Alesta Web ekibi olarak her zaman isim kullanmanızı öneririz — daha okunabilir ve bakımı kolay (more readable and maintainable).
En yaygın kullanım senaryosu: TypeScript ile yazılmış Node.js uygulaması. Build aşamasında tsc ile derleme, production aşamasında sadece compiled JS çalıştırma.
# Stage 1: Dependencies ve Build
FROM node:20-alpine AS builder
WORKDIR /app
# Önce package.json kopyala (cache optimizasyonu / cache optimization)
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY tsconfig.json ./
COPY src ./src
RUN npx tsc --noEmit && npx tsc
# Stage 2: Production
FROM node:20-alpine AS production
ENV NODE_ENV=production
WORKDIR /app
# Sadece gerekli dosyalar / Only necessary files
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./
# Güvenlik için non-root user / Security: non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
USER nextjs
EXPOSE 3000
CMD ["node", "dist/index.js"]
Bu Dockerfile ile Node.js image boyutu 1 GB'dan 150 MB'a iniyor. Ayrıca non-root user kullanımı güvenlik açısından best practice (security best practice).
Go, docker multi-stage build için adeta yaratılmış bir dil. Derleme sonrası ortaya çıkan statik binary, scratch veya distroless base image'ı ile çalışabiliyor — yani sıfıra yakın OS katmanı.
# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /app
# Modülleri önce indir (cache optimization / önbellek optimizasyonu)
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# CGO devre dışı = statically linked binary
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o server ./cmd/server
# Stage 2: Minimal production image
FROM scratch AS production
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]
Go uygulamaları için scratch base image (empty image) kullandığınızda final image boyutu 5-15 MB oluyor. Bunu Alesta Web ekibi olarak mikroservis altyapılarında sıklıkla kullanıyoruz — Kubernetes pod startup süresi inanılmaz düşüyor (pod startup time drops significantly).
Python için multi-stage build biraz daha dikkat gerektiriyor çünkü Python yorumlanan bir dil — C extension'ları derlemek için build tools gerekebiliyor (build tools required for C extensions).
# Stage 1: Builder (bağımlılıkları derle / compile dependencies)
FROM python:3.12-slim AS builder
# Build araçları yükle (install build tools)
RUN apt-get update && apt-get install -y \
gcc \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
# Wheel dosyaları oluştur (create wheel files)
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
# Stage 2: Production
FROM python:3.12-slim AS production
# Sadece runtime bağımlılıkları / Only runtime dependencies
RUN apt-get update && apt-get install -y \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=builder /app/wheels /wheels
RUN pip install --no-cache /wheels/*
COPY ./app ./app
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Alesta Web ekibi olarak yüzlerce Dockerfile review'ından çıkardığımız en önemli best practices şunlar:
Docker, değişmeyen layer'ları cache'ler (caches unchanged layers). Bu nedenle sık değişen dosyaları (kaynak kod) sonraya, nadiren değişen dosyaları (package.json, go.mod) öne koyun.
# ❌ Kötü - kaynak kod her değiştiğinde npm install yeniden çalışır
COPY . .
RUN npm install
# ✅ İyi - package.json değişmediği sürece npm install cache'lenir
COPY package*.json ./
RUN npm install
COPY . .
Multi-stage build ile birlikte .dockerignore dosyası da şart. node_modules, .git, test dosyaları, geçici dosyalar build context'e gönderilmemeli (should not be sent to build context).
node_modules
.git
.gitignore
*.md
dist
coverage
.env
.env.local
__pycache__
*.pyc
.pytest_cache
FROM node:latest yerine FROM node:20.11.1-alpine3.19 gibi spesifik versiyon kullanın. latest tag reproducible builds'ı (tekrarlanabilir build) bozar ve güvenlik sorunlarına yol açabilir (can cause security issues).
Alpine, distroless, scratch — boyuta göre seçim yapın:
failed to solve: failed to compute cache key: failed to walk: lstat /app/dist: no such file or directory
Çözüm: Builder stage'de dosya oluştuğunu doğrulayın. Build komutu başarısız olmuş olabilir. RUN ls /app/dist ile kontrol edin.
error while loading shared libraries: libstdc++.so.6: cannot open shared object file
Çözüm: Alpine'de musl libc kullanılır, glibc ile derlenmiş binary'ler çalışmaz. apk add libstdc++ gcompat ile eksik kütüphaneyi kurun veya debian-slim base image'ına geçin.
# Linux/Mac
export DOCKER_BUILDKIT=1
docker build -t myapp .
# Windows PowerShell
$env:DOCKER_BUILDKIT=1
docker build -t myapp .
# Ya da doğrudan / or directly
DOCKER_BUILDKIT=1 docker build -t myapp .
Docker 23.0+ sürümlerinde BuildKit zaten varsayılan olarak aktif (enabled by default). Daha eski sürümlerde bu adım zorunlu. Alesta Web olarak her zaman güncel Docker sürümü kullanmanızı öneririz.
Multi-stage build ile birlikte docker-compose.yml dosyanızda da target direktifi ile hangi stage'i build edeceğinizi belirtebilirsiniz: target: production. Development için ayrı, production için ayrı stage kullanmak (separate stages for dev/prod) mükemmel bir pattern.
Bu makalede kullanılan bilgiler aşağıdaki güvenilir kaynaklardan alınmıştır (information from the following reliable sources):
Alesta Web olarak tüm bilgileri doğruladık ve gerçek projelerimizde test ettik (verified and tested in real projects).
Docker multi-stage build, modern container geliştirmenin olmazsa olmazı. Alesta Web ekibi olarak yıllardır önerdiğimiz bu teknik (we have recommended this technique for years), hem image boyutunu dramatik ölçüde küçültüyor hem de security posture'ı iyileştiriyor.
Hızlı Özet / Quick Summary:
Sorularınız mı var? alestaweb.com üzerinden bize ulaşabilirsiniz. Alesta Web DevOps ekibi, Docker ve Kubernetes projelerinizde yanınızda!
Faydalı Linkler / Useful Links:
© 2026 AlestaWeb - Tüm hakları saklıdır. / All rights reserved.