deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak dev.to (home feed)

Docker'ın graphdriver deposu, zstd olarak etiketlenmiş gzip image katmanlarını yeniden push'luyor

dev.to'da yayımlanan bir rapor, overlay2 graphdriver deposunu kullanan Docker daemon'larının push sırasında zstd katman blob'ları için gzip media type'ı yazdığını ve etikete güvenen BuildKit build'lerini bozduğunu gösteriyor. Henüz bir düzeltme yayınlanmadı.

Docker'ın graphdriver deposu, zstd olarak etiketlenmiş gzip image katmanlarını yeniden push'luyor

Hata

dev.to'da yayımlanan bir rapor, Docker'ın graphdriver image deposunda bir dağıtım hatasını tarif ediyor: bu depoyu kullanan bir daemon, daha önce zstd sıkıştırmalı katmanlarla pull ettiği bir image'i push ederken, yazdığı manifest bu katmanları gzip media type'ı olan application/vnd.docker.image.rootfs.diff.tar.gzip ile etiketliyor. Katman blob'ları değiştirilmeden yeniden kullanıldığı için zstd sıkıştırılmış kalıyor — yalnızca etiket yanlış. Registry push'u kabul ediyor ve yeniden etiketlenen image'in docker run'ı hâlâ çalışıyor; çünkü Docker ve containerd sıkıştırmayı media type'tan değil, blob'un başındaki magic byte'lardan tespit ediyor.

Söz konusu depo overlay2. Rapora göre bu; her Docker 28 kurulumunu, 28'den yükseltilmiş herhangi bir Docker 29 daemon'unu (overlay2'yi korur ve başlangıçta "using prior storage driver: overlay2" loglar) ve containerd-snapshotter kapalı olan her daemon'u kapsıyor. Yeni Docker 29 kurulumları varsayılan olarak containerd image deposunu kullanıyor ve aynı push'ları doğru şekilde ele alıyor. docker info ikisini ayırt eder: "overlay2" graphdriver deposunu, "overlayfs" containerd deposunu gösterir.

Nasıl yeniden üretildi

Yazar, bu davranışı Docker CE 29.9.1 ve 29.9.2'de docker-in-docker daemon'lar, yerel bir registry ve curl ile zstd CLI kullanılarak oluşturulmuş tek katmanlı bir zstd image ile yeniden üretti. Bir graphdriver daemon bu image'i pull etti, yeniden etiketleyip geri push etti: blob digest aynıydı ama yeni manifest gzip beyan ediyordu. Aynı pull-etiketle-push dizisini gerçekleştiren bir containerd deposu daemon'u ise özgün tar+zstd media type'ını korudu. Yeniden etiketlenen blob hâlâ zstd magic byte'ları 28 b5 2f fd ile başlıyordu.

Nerede kırılıyor

Docker'ın kendi iş akışı hiçbir zaman başarısız olmuyor ve hatayı kolayca gözden kaçıran da bu. Maliyet, etikete güvenen araçlarda ortaya çıkıyor — genellikle de daha sonra, başka bir makinede. Rapor bunu BuildKit ile gösteriyor: yeniden etiketlenmiş image'den compression=zstd ve force-compression=true ile yapılan bir build, "failed to get compression blob "zstd": not found" hatasıyla başarısız oluyor. moby/buildkit#7308'ye göre force-compression, bir katmanın media type'ını gerçek sıkıştırması olarak ele alıyor; dolayısıyla gzip etiketli bir zstd blob, dönüştürme gerektiren gzip sanılıyor ve zstd varyantı için yapılan arama hiçbir şey bulamıyor.

force-compression olmadan build başarılı oluyor — ama yeni image iki yanlış etiketi devraldığı için, onun üzerine build yapan bir sonraki kişi de bunları alıyor.

Bir de cache tuzağı var. Yanlış etiketlenmiş image'den yapılan tek bir build'den sonra, aynı builder üzerinde doğru etiketlenmiş özgün image'den yapılan build'ler bile başarısız oldu; çünkü katman gzip etiketi altında cache'lenmişti. Yalnızca o builder üzerinde docker buildx prune -af çalıştırmak temel image için doğru davranışı geri getirdi.

Kök neden ve durum

Rapora göre graphdriver deposu, registry'nin zaten tuttuğu ya da başka bir repository'den mount edebildiği bir katmanı push ederken hiçbir şey yüklemez ve yalnızca manifest girdisini yazar — ve bu iki kod yolundaki media type, daemon/internal/distribution/push_v2.go içinde Docker'ın gzip türüne sabitlenmiş durumda. Bu, özgün halinde gzip olan katmanlar için doğru, registry'den pull edilmiş zstd katmanları için sessizce yanlış; doğrulayan hiçbir şey yok. Containerd deposu katmanın özgün descriptor'ını, media type dahil, koruduğu için doğru push ediyor. Sorun yukarı akışta moby/moby#53999 olarak takip ediliyor, help wanted etiketli ve yazı zamanında yayınlanmış bir sürümde düzeltme yok.

Geçici çözümler

Rapor, bir containerd deposu daemon'undan push yapmayı öneriyor: ya yeni bir Docker 29 kurulumu, ya da /etc/docker/daemon.json içine "features": {"containerd-snapshotter": true} yazıp yeniden başlatmak. Eski depoda saklanan image'ler yeni depoda görünmüyor, bu yüzden yeniden pull edilmeleri gerekiyor. Alternatifler arasında, pull edilmiş zstd image'leri bir graphdriver daemon'undan yeniden push etmek yerine yeniden build almak ve BuildKit hatasına takıldıktan sonra builder cache'ini temizlemek yer alıyor. Rapordaki yardımcı bir script, her image'in manifest'ini ve her katmanın ilk byte'larını fetch edip etiketi içerikle karşılaştırarak bir registry'yi denetliyor; Docker Hub'ın alpine:3.24 ve nginx:alpine image'lerine karşı çalıştırıldığında kontrol edilen her katman sorunsuz çıktı.

Neden önemli

Bu bir crash değil, dağıtım metadata'sının sessiz bir bozulması. Docker kendi başına byte'ları kokladığı için, yanlış etiketlenmiş manifest'ler — yeniden etiketleme, mirroring veya repository'ler arası promotion yoluyla — media type'lara güvenen bir araç onlara çarpıp başka bir yerde başarısız olana kadar registry'lerde yayılabiliyor. Docker 29 dağıtımlarının ve yükseltilmiş 29 daemon'ların yaygınlığı göz önüne alındığında, bugün pek çok registry bu manifest'leri üretebiliyor. Raporun çıkardığı daha geniş ders: etiket bir iddiadır, gerçek değil; ve verinin yanına kaydedilen metadata ondan uzaklaşabilir — o yüzden içerik doğrulaması ucuzken yapın ve bu hatanın gerçekten ısırdığı yeri, yani bildirilen adımdan sonraki adımı test edin.

  • #docker
  • #containers
  • #buildkit
  • #oci
  • #devops

İlgili yazılar