Docker İmage boyutlarını küçültmenin 6 yolu
bu yazımda docker imagelarının boyutlarını küçültüp nasıl daha efektif kullanabileceğimizden bahsedeceğim.

bildiğiniz gibi docker image yapabilmek için bir Dockerfile yaratıp build alıyoruz. bir Dockerfile yapısı aşağıdaki şekildedir,

bu yapının üzerinde değişiklikler yaparak docker image imiz boyunu küçülteceğiz. 6 başlık altında inceleyeceğiz, bunlar:
- daha küçük boyutlu base image kullanmak (smaller base image)
- layer sayısını azaltmak (minimize layers)
- install aşamasında kullanılan gereksiz paketleri silme
- install sonrası paketleri silme
- dockerignore kullanmak
- multistage build yapmak
smaller base image
bir Dockerfile da yapacağımız işlemler için base bir image kullanıyoruz bu imageler offical olarak dockerhub da bulunmaktadır.

mesela bir web sayfası için nginx çalıştıracaksınız “FROM nginx” diyerek en çok bilinen image i kullanıyorsunuz. bu image 56MB boyutunda eğer burada daha küçültmek istiyorsanız “alpine” versiyonunu tercih edeceksiniz. genellikle her image in bir alpine versiyonu da oluyor daha lightweight bir image.
“FROM nginx:alpine” diyerek kullandığınız image 10MB boyutunda.
bir pythıon uygulaması yapalım ve imageler arasındaki farka bakalım. bir hello world uygulaması yaptım. app.py diye.
FROM python:latestWORKDIR /usr/src/appCOPY requirements.txt
RUN pip install requirements.txtCOPY app.py .CMD ["python", "./app.py"]
bu şekilde kullanımda 930MB boyutuna yaklaşık bir image elde edersiniz bu da dev ve production ortamları için büyük bir boyut özellikle gün içinde fazla build alıyorsunuz repo tarafında fazladan bir yer kaplarsınız.
eğer FROM python:alpine yaparsanız. boyutun 60MB a yakın olacağını görebilirsiniz.
minimize layers
bir docker image yaratırken uygulamanızın kullanacağı bazı dependency leri RUN komutu ile elle kurarsınız mesela örnek verirsek, bir tane ubuntu base image üzerine container içinde kullanmak için curl, dns ve net-tools yükleyelim.
FROM ubuntu:latest
RUN apt-get update -y
RUN apt-get install curl -y
RUN apt-get install net-tools -y
RUN apt-get install dnsutils -y
bu image oluşurken 5 layer yapacak her yaptıgımız işlem bir layer olarak tanımlar.
build aldıktan sonra image boyutumuzu kontrol edersek 168MB gibi bir şey çıktı.
biz bu dockerfile ı optimize şöyle ederiz normal bash kullanıyormuşuz gibi sonuçta bu da bir linux dağıtımı,
FROM ubuntu:latest
RUN apt-get update && \
apt-get install curl -y && \
apt-get install net-tools -y && \
apt-get install dnsutils -y
burada docker 2 layer kullanacak ve şimdi boyutuna baktığımızda 166MB olduğunu göreceğiz.

çok büyük bir fark oluşmasa da çok fazla layer olan bir yapınızda size biraz da olsa optimizasyon sağlayacaktır.
clean unnecesary package and dependencies
uygulamanızda genellikle RUN ile yükleme yaparken bu programların yanında yüklenen bazı paketleri devre dışı bırakabiliriz.
FROM ubuntu:latest
RUN apt-get update -y && \
apt-get install --no-install-recommends curl dnsutils net-tools -y
ve biraz daha küçüldüğünü göreceksiniz.

clean up after installation
burada bir önceki kısma benzer iş yapacağız. bundan önceki bölümde paket install aşamasında gelecek olan yardımcı paketlerin yüklenmesini engelleyip paket boyunu küçültmüştük şimdi install aşamasından sonra programı image haline getirirken kullandığımız library leri sileceğiz. komutumuz şöyle olacak;
FROM ubuntu:latest
RUN apt-get update -y && \
apt-get install --no-install-recommends curl dnsutils net-tools -y && \
rm -rf /var/lib/apt/lists/*
image boyutunun daha da düştüğünü göreceksiniz.

.dockerignore kullanmak
bu ignore dosyasına .gitignore dan aşinasınızdır muhtemelen aynı işi docker image yaparkan .dockerignore ile yapıyoruz. yani bir image oluşurken directory de bulunan sadece kullandığımız ve almak istemediğimiz dosyaları image içine koymuyoruz. bu sadece boyut olarak da değil güvenlik olarak da işimize yarayan bir uygulama olup sürekli kullanmanız size fayda sağlar.
multi-stage build
bu en çok tercih edilen yöntemlerden biridir ve en etkilisi diyebilirim.
bu artifact üretilen uygulamalarda kullanılır. java, go, nodejs gibi bir artifact çıktısı üreten programlama dillerin kullanılır.
normal dockerfile da mesela nodejs örnek alırsak öncelikle npm install yaparak uygulamamızın kullandığı dependenciesler ve library ler yüklenior daha sonra oluşan artifact en son node komutu ile çalıştırılır ve image oluşturulur. farkettiyseniz oluşan image in içinde bu uygulamayı yaparken kullandığımız her şey duruyor. bu yüzden 2 adımda bu işi yapacağız.
ilk adımda artifact i oluşturan base image kullanırken ikinci adımda sadece bu artifacti çalıştıran bir image kullanacağız.

öncelikle tek adımda bir yapalım ve aradaki farkı görelim. basit bir node.js uygulaması olsun. bunun 2 tane dosyası olacak biri index.js diğeri de dependency leri belirttiğimiz package.json
repoya iki Dockerfile ı da koydum. clone yapıp deneyelim.

FROM node:16
COPY . .
RUN npm install
EXPOSE 8080
CMD [ "node", "index.js" ]
ilk dockerfile ımızı çalıştıralım.

zaten node base image i 900MB civarında bu yüzden oluşan imageimiz. 913 MB olmuş.

peki ilk söylediğimiz gibi artifact ı başka bir image e çalıştırma kısmını başka image e yaptırısak,
FROM node:16 as builder
WORKDIR /app
COPY package.json index.js ./
RUN npm install
FROM node:alpine as main
COPY --from=builder /app /
CMD ["index.js"]
dockerfile ı incelersek başta yine artifact üretmek için node imagei kullanmışız daha sonra yine FROM diyerek bu image içinde üretilen artifacti küçük dağıtım olan alpine ile çalıştırmasını söylemişiz. çünkü çalıştırırken build aldığı zamanda kullandığı herhangi bir library ihtiyaç duymayacak.
bunu çalıştıralım,

tekrar image boyutlarını karşılaştırırsak,

gerçekten iyi bir optimizasyon yaptığımızı görebilirsiniz.
!!! bunların dışında google tarafından geliştirilen, multi stage buildler de kullanılan shell ve paket yöneticisi içermeyen distroless image dediğimiz base imageler da mevcut bunlar dosya boyutumuzu daha da küçültür.
FROM node:16 as builder
WORKDIR /app
COPY package.json index.js ./
RUN npm install
FROM gcr.io/distroless/nodejs
COPY --from=builder /app /
EXPOSE 8080
CMD ["index.js"]
bunu denersek boyutun daha da düştüğünü görebilirsiniz.

distroless imageler boyut küçültme yanında güvenlik olarak da çok iyi olanaklar sağlamaktadır, distroless imageler gün geçtikçe sayısı artmakta aşağıdaki linkten detaylı bilgi alabilirsiniz.
umarım faydalı bir yazı olur. bir sonraki yazımda görüşmek üzere.
sağlılı günler
h.a.s.