Merhaba arkadaşlar, bugün sizlere Docker imaj build sürelerinizi gözle görülür şekilde kısaltacak, özellikle CI/CD pipeline'larında ve büyük projelerde hayat kurtaran bir optimizasyondan bahsedeceğim: BuildKit cache'inin harici bir registry'ye veya paylaşılan bir yerel dizine yönlendirilmesi.
Normalde Docker build işlemi sırasında oluşturduğu ara katman (layer) cache'ini sadece o an çalıştığınız makinede tutar. Bu da farklı bir makinede (örneğin bir CI sunucusunda) veya cache'in temizlendiği bir ortamda her şeyi baştan build etmeniz anlamına gelir. Gereksiz zaman ve kaynak israfı! Benim sunucularda genelde kullandığım yöntem, bu cache'i dışarı taşıyarak sürekli kullanılabilir kılmak.
Optimizasyonun Avantajları
Bu yöntemi uyguladığınızda, özellikle `RUN`, `COPY` ve `ADD` gibi komutların cache'leri farklı makineler veya build işlemleri arasında paylaşılabilir hale gelir. Böylece:
CI/CD işlemleriniz çok daha hızlı çalışır.
Geliştirici makineleri arasında tutarlılık sağlanır.
Network trafiği azalır (harici registry kullanılıyorsa).
Build süreleri bazen %70-80'lere varan oranlarda düşer.
Yöntem 1: Harici Registry Kullanımı (Build Cache'ini Registry'e Push/Pull Etmek)
Bu yöntemde, build cache'inizi Docker Hub, GitLab Container Registry veya Harbor gibi özel bir registry'ye gönderip oradan çekersiniz. Build argümanı olarak `BUILDKIT_INLINE_CACHE=1` kullanmak şart.
Öncelikle, Dockerfile'ınızda `--mount=type=cache` gibi BuildKit özelliklerini kullanıyorsanız, bunlar harici cache'e dahil edilmez. Ancak image layer cache'i aktarılır.
Build sırasında cache'i oluşturup registry'e push etmek için:
Bir sonraki build'de cache'i registry'den çekmek için ise:
Şu ayara çok dikkat etmelisiniz: `--cache-to` satırındaki `mode=max` parametresi, tüm olası cache bilgilerini kaydetmenizi sağlar. Registry'nizin bu cache imajlarını depolayacağı alanı göz önünde bulundurun.
Yöntem 2: Yerel Paylaşılan Cache Dizini Kullanımı
Harici bir registry kurmak istemiyor veya network erişimi olmayan bir ortamda çalışıyorsanız, bu yöntem tam size göre. Build cache'ini bir dizine export/import edebilirsiniz. Bu, NFS paylaşımı üzerinden birden fazla sunucuya da uygulanabilir.
Öncelikle, cache'i belirli bir dizine (örn. /tmp/buildkit-cache) kaydederek build yapalım:
Artık bu cache dizinini, başka bir build işleminde kaynak olarak gösterebiliriz:
Bu dizini bir NFS sunucusuna bağlayarak tüm build makinelerinizin aynı cache'i kullanmasını sağlayabilirsiniz. Benim sunucu kümemde sıklıkla kullandığım bir yöntemdir. Dizin izinlerinin (permissions) Docker daemon'unun yazabileceği şekilde ayarlandığından emin olun.
Dikkat Edilmesi Gerekenler ve Sorun Giderme
BuildKit Aktif Mi? BuildKit'in default builder olarak ayarlandığından emin olun. /etc/docker/daemon.json dosyasında `{ "features": { "buildkit": true } }` olmalı veya `DOCKER_BUILDKIT=1` ortam değişkeni set edilmeli.
Cache Büyüklüğü: Harici registry yönteminde, cache imajları zamanla büyüyebilir. Registry depolama alanınızı takip edin ve eski tag'leri temizlemeyi unutmayın.
Gizli Dosyalar (Secrets): Cache mekanizması güvenlik nedeniyle `RUN --mount=type=secret` gibi komutların cache'ini paylaşmaz. Bu beklenen bir davranıştır.
Docker Context: `docker buildx` kullanıyorsanız, farklı bir builder context'iniz olabilir. Mevcut builder'ınızı `docker buildx ls` komutu ile kontrol edin.
Umarım bu rehber, container build sürelerinizi hızlandırmanıza yardımcı olur. Özellikle büyük monorepo'lar veya sık sık build alınan projelerde inanılmaz bir fark yaratıyor. Siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Harici registry olarak hangi çözümü tercih ediyorsunuz? Deneyimlerinizi paylaşın veya takıldığınız bir nokta olursa aşağıya yazmaktan çekinmeyin. Sorularınızı bekliyorum.
Normalde Docker build işlemi sırasında oluşturduğu ara katman (layer) cache'ini sadece o an çalıştığınız makinede tutar. Bu da farklı bir makinede (örneğin bir CI sunucusunda) veya cache'in temizlendiği bir ortamda her şeyi baştan build etmeniz anlamına gelir. Gereksiz zaman ve kaynak israfı! Benim sunucularda genelde kullandığım yöntem, bu cache'i dışarı taşıyarak sürekli kullanılabilir kılmak.
Bu yöntemi uyguladığınızda, özellikle `RUN`, `COPY` ve `ADD` gibi komutların cache'leri farklı makineler veya build işlemleri arasında paylaşılabilir hale gelir. Böylece:
CI/CD işlemleriniz çok daha hızlı çalışır.
Geliştirici makineleri arasında tutarlılık sağlanır.
Network trafiği azalır (harici registry kullanılıyorsa).
Build süreleri bazen %70-80'lere varan oranlarda düşer.
Bu yöntemde, build cache'inizi Docker Hub, GitLab Container Registry veya Harbor gibi özel bir registry'ye gönderip oradan çekersiniz. Build argümanı olarak `BUILDKIT_INLINE_CACHE=1` kullanmak şart.
Öncelikle, Dockerfile'ınızda `--mount=type=cache` gibi BuildKit özelliklerini kullanıyorsanız, bunlar harici cache'e dahil edilmez. Ancak image layer cache'i aktarılır.
Build sırasında cache'i oluşturup registry'e push etmek için:
Bash:
docker buildx build --platform linux/amd64 \
-t kullanici/imajim:latest \
-t kullanici/imajim:cache \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--cache-from=kullanici/imajim:cache \
--cache-to=type=registry,ref=kullanici/imajim:cache,mode=max \
--push .
Bir sonraki build'de cache'i registry'den çekmek için ise:
Bash:
docker buildx build --platform linux/amd64 \
-t kullanici/imajim:latest \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--cache-from=kullanici/imajim:cache \
--push .
Şu ayara çok dikkat etmelisiniz: `--cache-to` satırındaki `mode=max` parametresi, tüm olası cache bilgilerini kaydetmenizi sağlar. Registry'nizin bu cache imajlarını depolayacağı alanı göz önünde bulundurun.
Harici bir registry kurmak istemiyor veya network erişimi olmayan bir ortamda çalışıyorsanız, bu yöntem tam size göre. Build cache'ini bir dizine export/import edebilirsiniz. Bu, NFS paylaşımı üzerinden birden fazla sunucuya da uygulanabilir.
Öncelikle, cache'i belirli bir dizine (örn. /tmp/buildkit-cache) kaydederek build yapalım:
Bash:
docker buildx build \
-t yerelimaj:latest \
--cache-to=type=local,dest=/tmp/buildkit-cache,mode=max \
.
Artık bu cache dizinini, başka bir build işleminde kaynak olarak gösterebiliriz:
Bash:
docker buildx build \
-t yerelimaj:latest \
--cache-from=type=local,src=/tmp/buildkit-cache \
.
Bu dizini bir NFS sunucusuna bağlayarak tüm build makinelerinizin aynı cache'i kullanmasını sağlayabilirsiniz. Benim sunucu kümemde sıklıkla kullandığım bir yöntemdir. Dizin izinlerinin (permissions) Docker daemon'unun yazabileceği şekilde ayarlandığından emin olun.
BuildKit Aktif Mi? BuildKit'in default builder olarak ayarlandığından emin olun. /etc/docker/daemon.json dosyasında `{ "features": { "buildkit": true } }` olmalı veya `DOCKER_BUILDKIT=1` ortam değişkeni set edilmeli.
Cache Büyüklüğü: Harici registry yönteminde, cache imajları zamanla büyüyebilir. Registry depolama alanınızı takip edin ve eski tag'leri temizlemeyi unutmayın.
Gizli Dosyalar (Secrets): Cache mekanizması güvenlik nedeniyle `RUN --mount=type=secret` gibi komutların cache'ini paylaşmaz. Bu beklenen bir davranıştır.
Docker Context: `docker buildx` kullanıyorsanız, farklı bir builder context'iniz olabilir. Mevcut builder'ınızı `docker buildx ls` komutu ile kontrol edin.
Umarım bu rehber, container build sürelerinizi hızlandırmanıza yardımcı olur. Özellikle büyük monorepo'lar veya sık sık build alınan projelerde inanılmaz bir fark yaratıyor. Siz bu konfigürasyonu kendi sunucularınızda nasıl yapıyorsunuz? Harici registry olarak hangi çözümü tercih ediyorsunuz? Deneyimlerinizi paylaşın veya takıldığınız bir nokta olursa aşağıya yazmaktan çekinmeyin. Sorularınızı bekliyorum.