Bir değişiklik yaptınız, docker build çalıştırdınız ve bağımlılıklar yeniden indiriliyor. Her seferinde. Dakikalar akıp gidiyor. Docker’ın build önbelleği bunu önlemek için tasarlanmıştır, ama doğru kullanmak için nasıl çalıştığını bilmeniz gerekir. Bu yazıda katman önbelleğinin mantığını, --mount=type=cache ile paket önbelleğini ve CI’da önbelleği paylaşmayı anlatıyoruz.
Katman önbelleği nasıl çalışır?
BuildKit her talimatı çalıştırmadan önce şuna bakar: “Bu talimat ve girdileri daha önce aynı mıydı?” Aynıysa sonucu önbellekten alır (CACHED). Bir talimat geçersiz kalırsa (talimat değişti ya da COPY ettiği dosyalar değişti) ondan sonraki tüm katmanlar yeniden çalışır. Bu yüzden talimat sırası önemlidir: az değişenler üstte, çok değişenler altta.
FROM temel-imaj
WORKDIR /app
COPY deps.txt . # bağımlılık listesi: nadiren değişir
RUN kur-bagimliliklari deps.txt # pahalı adım
COPY app.txt . # kaynak kod: sık değişir
RUN derle
Denemeyle görelim
Yukarıdaki Dockerfile’ı build ettikten sonra iki farklı değişiklik yaptık. Önce yalnızca kaynak kodu (app.txt) değiştirdik:
#6 [2/6] WORKDIR /app CACHED
#7 [3/6] COPY deps.txt . CACHED
#8 [4/6] RUN kur-bagimliliklari ... CACHED
#9 [5/6] COPY app.txt . (yeniden çalıştı)
#10 [6/6] RUN derle (yeniden çalıştı)
Pahalı bağımlılık adımı önbellekten geldi. Sonra bağımlılık listesini (deps.txt) değiştirdik:
#6 [2/6] WORKDIR /app CACHED
#7 [3/6] COPY deps.txt . (yeniden çalıştı)
#8 [4/6] RUN kur-bagimliliklari ... (yeniden çalıştı)
#9 [5/6] COPY app.txt . (yeniden çalıştı)
#10 [6/6] RUN derle (yeniden çalıştı)
Bu kez COPY deps.txt‘den itibaren her şey yeniden çalıştı — kural bu: bir katman geçersiz olursa altındakilerin hepsi geçersiz olur. Bunun doğru kullanımı, bağımlılık dosyalarını (package.json, requirements.txt, go.mod) kaynak koddan önce kopyalamaktır; böylece günlük kod değişiklikleri bağımlılık kurulumunu tetiklemez.
Önbellek bağlama (cache mount): paket indirmelerini kalıcılaştırın
Katman önbelleği, bir bağımlılık değiştiğinde tüm kurulum adımını yeniden çalıştırır. RUN --mount=type=cache ile paket yöneticisinin önbellek dizinini build’ler arası kalıcı hale getirebilirsiniz; böylece değişen bir bağımlılıkta bile yalnızca farkı indirirsiniz:
RUN --mount=type=cache,target=/root/.npm npm ci
RUN --mount=type=cache,target=/var/cache/apt apt-get update && apt-get install -y paket
Davranışı doğrulamak için bir sayaç denemesi yaptık: komut metnini her seferinde değiştirerek (katman önbelleğini atlatarak) üç ardışık build çalıştırdık, komut cache dizinindeki bir dosyayı bir artırıyor:
build 1: 2
build 2: 3
build 3: 4
Sayaç build’ler arasında artarak devam etti: önbellek dizini imajın bir parçası olmadığı halde build’ler arasında yaşıyor. Önemli ayrım şu: cache mount’taki veri nihai imaja girmez (imajı şişirmez) ve başka makinelere taşınmaz; yalnızca o build motorunun yerel önbelleğidir.
Önbelleği CI’da paylaşmak
CI sunucularında her build temiz bir makinede başladığı için yerel önbellek yoktur. Çözüm, önbelleği dışa aktarıp bir sonraki build’de içe almaktır:
# Önbelleği bir dizine (veya registry'ye) yaz
docker buildx build --cache-to type=local,dest=./cache .
# Sonraki build'de oradan oku
docker buildx build --cache-from type=local,src=./cache .
# Registry üzerinden paylaşım
docker buildx build \
--cache-to type=registry,ref=registry.ornek.com/uygulama:cache \
--cache-from type=registry,ref=registry.ornek.com/uygulama:cache .
Dokümantasyona göre registry, GitHub Actions (type=gha), S3 ve Azure Blob arka uçları desteklenir. GitHub Actions örneği için CI/CD ile Docker yazısına bakın. Yukarıdaki type=local yazma komutunu varsayılan Docker 29.4 builder’ında çalıştırıp önbellek manifestinin yazıldığını doğruladık.
Önbelleği bozan yaygın hatalar
COPY . .en üstte: herhangi bir dosya değişince altındaki her şey yeniden çalışır. Önce bağımlılık dosyalarını kopyalayın. Gereksiz dosyaları .dockerignore ile bağlamdan çıkarın.- Zamana bağlı komutlar:
RUN date > build-timegibi komutlar her seferinde farklı sonuç üretir; önbellek mantıklı çalışmaz. - Tek
RUNiçinde çok fazla iş: küçük bir değişiklikte hepsi yeniden çalışır. Mantıksal olarak ayrılabilen adımları bölün. - Önbelleği sürekli sıfırlamak:
--no-cacheyalnızca gerçekten temiz bir build gerektiğinde (örneğin güvenlik güncellemelerini zorlamak için) kullanın.
Önbellek ile güncellik arasında denge vardır: önbellekli bir build, apt-get update gibi adımlardaki güvenlik güncellemelerini otomatik almaz. Düzenli aralıklarla --no-cache veya --pull ile temiz build alın.
Hızlı kontrol listesi
- Bağımlılık dosyaları kaynak koddan önce mi kopyalanıyor?
- Paket yöneticisi için
--mount=type=cachekullanıyor musunuz? - CI’da
--cache-from/--cache-totanımlı mı? - Build bağlamı küçük mü?
İmaj boyutunu küçültmek için Multi-Stage Build yazısına, katman kavramının temeline İmaj ve Container Farkı yazısına bakın.