18 puan yazan xguru 2024-11-17 | 6 yorum | WhatsApp'ta paylaş
  • Docker konteyner imajları derlenirken Dockerfile Multi-Stage yapıda değilse, gereksiz dosyaların dahil edilme olasılığı yüksektir
  • Bu durum imaj boyutunun büyümesine ve güvenlik açıklarının artmasına yol açar
  • Konteyner imajlarında ortaya çıkabilen “gereksiz dosyaların” başlıca nedenleri analiz ediliyor ve bunların Multi-Stage Build ile nasıl çözülebileceği açıklanıyor

İmaj boyutunun büyüme nedenleri

  • Uygulamalar, build zamanı ve çalışma zamanı bağımlılıklarına sahiptir.
  • Build zamanı bağımlılıkları, çalışma zamanı bağımlılıklarından daha fazladır ve daha çok güvenlik açığı (CVE) içerir.
  • Aynı imaj build ve çalıştırma için kullanıldığında, gereksiz build zamanı bağımlılıkları (compiler, linter vb.) da dahil edilir.
  • Build ve runtime imajları ayrılmalıdır, ancak bu çoğu zaman gözden kaçar.

Hatalı Dockerfile yapısı örnekleri

Go uygulamaları için hatalı örnek

FROM golang:1.23  
WORKDIR /app  
COPY . .  
RUN go build -o binary  
CMD ["/app/binary"]  
  • golang:1.23 imajı derleme içindir, ancak bunu olduğu gibi production ortamında kullanırsanız tüm Go compiler'ı ve bağımlılıkları da dahil olur.
  • İmaj boyutu: 800MB üzeri, 800'den fazla güvenlik açığı mevcut.

Node.js uygulamaları için hatalı örnek

FROM node:lts-slim  
WORKDIR /app  
COPY . .  
RUN npm ci  
RUN npm run build  
ENV NODE_ENV=production  
EXPOSE 3000  
CMD ["node", "/app/.output/index.mjs"]  
  • node_modules klasörü, çalışma zamanında gerekmeyen geliştirme bağımlılıklarını da içerebilir.
  • Bu durum npm ci --omit=dev ile düzeltilemez; çünkü build sürecinde gerekli geliştirme bağımlılıkları kaldırılabilir.

Multi-Stage Build öncesinde lean imaj üretme yöntemleri

Builder pattern

  1. Uygulama Dockerfile.build içinde derlenir:
FROM node:lts-slim  
WORKDIR /app  
COPY . .  
RUN npm ci  
RUN npm run build  
  1. Derlenen artifact'ler host'a kopyalanır:
docker cp $(docker create build:v1):/app/.output .  
  1. Dockerfile.run içinde runtime imajı oluşturulur:
FROM node:lts-slim  
WORKDIR /app  
COPY .output .  
CMD ["node", "/app/.output/index.mjs"]  
•	Sorunlar: Birden fazla Dockerfile yazılması, build sırasının yönetilmesi ve ek script gereksinimi.  

Multi-Stage Build'i anlamak

  • Multi-Stage Build, Docker içinde Builder pattern'i uygulayan bir özelliktir.
    • Birden fazla FROM komutu kullanarak tek bir Dockerfile içinde build ve runtime aşamaları tanımlanabilir.
    • COPY --from=<stage> komutuyla önceki aşamada derlenen dosyalar alınabilir.

Multi-Stage Dockerfile örneği (Node.js)

# Build stage  
FROM node:lts-slim AS build  
WORKDIR /app  
COPY . .  
RUN npm ci  
RUN npm run build  
  
# Runtime stage  
FROM node:lts-slim AS runtime  
WORKDIR /app  
COPY --from=build /app/.output .  
ENV NODE_ENV=production  
CMD ["node", "/app/.output/index.mjs"]  
  • COPY --from=build ile derlenen artifact'ler doğrudan kopyalanır; böylece dosyalar host üzerinden geçmeden taşınabilir.

Multi-Stage Build pratik örnekleri

React uygulaması

# Build stage  
FROM node:lts-slim AS build  
WORKDIR /app  
COPY . .  
RUN npm ci  
RUN npm run build  
  
# Runtime stage  
FROM nginx:alpine  
COPY --from=build /app/build /usr/share/nginx/html  
ENTRYPOINT ["nginx", "-g", "daemon off;"]  
  • React uygulamaları build sonrasında statik dosyalara dönüşür ve Nginx ile sunulabilir.

Go uygulaması

# Build stage  
FROM golang:1.23 AS build  
WORKDIR /app  
COPY . .  
RUN go build -o binary  
  
# Runtime stage  
FROM gcr.io/distroless/static-debian12:nonroot  
COPY --from=build /app/binary /app/binary  
ENTRYPOINT ["/app/binary"]  
  • distroless imajı kullanılarak en aza indirilmiş bir runtime ortamı sağlanır.

Java uygulaması

# Build stage  
FROM eclipse-temurin:21-jdk-jammy AS build  
WORKDIR /build  
COPY . .  
RUN ./mvnw package -DskipTests  
  
# Runtime stage  
FROM eclipse-temurin:21-jre-jammy  
COPY --from=build /build/target/app.jar /app.jar  
CMD ["java", "-jar", "/app.jar"]  
  • Build için JDK, runtime için ise daha hafif JRE kullanılır.

Sonuç

  • Multi-Stage Build, build ve runtime ortamlarını ayırarak gereksiz geliştirme bağımlılıklarının imaj boyutunu büyütmesini önler
  • Böylece imaj boyutu küçültülebilir, güvenlik güçlendirilebilir ve build süreci sadeleştirilebilir
  • Multi-Stage Build, verimli konteyner imajları oluşturmanın standart yöntemidir ve gelişmiş özellikleri de destekler (ör. dallanma koşulları, build sırasında unit test)

6 yorum

 
savvykang 2024-11-18

Java tarafında jlink 9. sürümden beri kullanıma sunulmuş olsa da, bağımlı modülleri jdeps ile bulup tek tek belirtmek gerekmesi gibi nedenlerle kullanılabilirliği pek iyi değil. İnsanların böyle yöntemleri bilmemesi ya da JRE araması, Java araçlarının yeterince tanıtılmadığını düşündürüyor; ayrıca tek bir komutla JRE üretecek şekilde iyileştirilmesi gerekiyor gibi görünüyor.

 
brainer 2024-11-17

Ben de o şekilde kullanıyorum ama build süresinin uzun sürmesi dezavantaj gibi görünüyor.

 
kandk 2024-11-18

Build süresinde bir fark olmamalı. Fark varsa yanlış yapılandırılmıştır!

 
brainer 2024-11-18

Ah, anladım!

 
qurare 2024-11-18

Stratejiye bağlı olarak bazen bir stage’i tamamen cache’leyebildiğiniz için, benim durumumda build süresi aksine kısaldı!

 
brainer 2024-11-18

Görünüşe göre Docker hakkında biraz daha fazla şey öğrenmem gerekecek!