S3'ü konteyner registry'si olarak kullanmak
(ochagavia.nl)- Konteyner imajları genellikle özel registry'lere yüklenir; ancak bir S3 bucket'ını HTTP üzerinden erişilebilir hale getirip dosyaları beklenen yollara yerleştirirseniz,
docker pullhedefi gibi kullanılabilir - Özel imaj builder'da pull edilebilir imajları birkaç saniye içinde oluşturma süreci darboğaz hâline geldi ve layer push süresi bunun önemli bir bölümünü oluşturdu
- 198 MiB'lik layer yükleme benchmark'ında ECR 24–28 MiB/s, S3 ise 115–190 MiB/s olarak ölçüldü; S3 en fazla 8 kat daha hızlıydı
- Fark, S3'ün tek bir layer'ın chunk'larını paralel yükleyebilmesinden, OCI Distribution Spec tabanlı ECR'nin ise chunk'ları sıralı işlemek zorunda olmasından kaynaklanıyor
- Bu yöntem
docker push, imaj doğrulama, güvenlik taraması, private depo erişim kontrolü gibi registry özelliklerinin yerine geçmez; bu yüzden deneysel bir optimizasyon olarak görülmeli
S3 bucket'ından docker pull yapılabilmesinin koşulları
- S3'ü konteyner registry'si gibi kullanmak için bucket'ı HTTP üzerinden erişilebilir hâle getirmeniz ve imaj dosyalarını Docker'ın beklediği yollara yüklemeniz gerekir
- Koşullar sağlanırsa imaj, normal bir registry'den olduğu gibi
docker pullile alınabilir - Demo imajı cowsay çalıştırır ve bucket URL'si imaj adı gibi kullanılarak
docker run --rm .../cowsayile çalışır - Demoda Cloudflare R2 kullanıldı
- Ücretsiz egress tercih sebebiydi
- R2 ve S3 API uyumlu olduğundan imaj AWS SDK ile R2'ye yüklendi
Neden özel registry yerine S3 değerlendirildi?
- Konteyner imajları genellikle DockerHub, GitHub Container Registry, ECR gibi özel registry'lerde barındırılır
- Özel imaj builder'ın hedefi, gereksinimlerden pull edilebilir imaja birkaç saniye içinde ulaşmaktır
- AWS ortamında ECR en kolay seçenek olsa da gerçek yükleme hızında S3 ile ECR arasındaki fark belirgin biçimde ortaya çıktı
- Performans optimizasyonu için koda execution trace eklendiğinde, layer'ları konteyner registry'sine push etme süresinin büyük bir darboğaz olduğu görüldü
198 MiB layer yükleme sonuçları
- Küçük benchmark, 198 MiB'lik bir layer'ı ECR ve S3'e ayrı ayrı yükleyerek geçen süreyi ve throughput'u karşılaştırdı
- Gözlemlenen hızlar şöyleydi
- ECR: minimum 24 MiB/s, 8,2 saniye
- ECR: maksimum 28 MiB/s, 7,0 saniye
- S3: minimum 115 MiB/s, 1,7 saniye
- S3: maksimum 190 MiB/s, 1,0 saniye
- Sonuçlara göre S3, ECR'den en fazla 8 kat daha hızlı seviyede
- Deney kodu AWS üzerinde çalıştırıldı; S3 ve ECR, public internete çıkmadan VPC üzerinden dahili olarak bağlandı
- Bu koşul, mümkün olan iyi gecikme süresi ve bant genişliğini sağlıyor
Hız farkını yaratan paralel chunk yükleme
- S3 yüklemesi, tek bir layer'ın chunk'larını paralel olarak yükleyebilir
- Yeterli bant genişliği varsa paralel chunk yükleme throughput'u ciddi ölçüde artırır
- AWS belgeleri de bant genişliği kullanımını maksimize etmek için paralel chunk yüklemeyi önerir
- ECR, OCI Distribution Spec'i uygular
- Bu spesifikasyon,
docker pullvedocker pushkomutlarının birden fazla registry'de çalışmasını sağlayan standarttır - Layer push işlemi sıralı ilerlemek zorundadır; chunk yükleme yapılsa bile önceki chunk bitmeden sonraki chunk'a geçilemez
- Bu spesifikasyon,
- S3'te de sıralı yükleme test edildiğinde throughput ECR ile benzer seviyeye düşer
docker pullun gerçek istek yapısı
docker pullun dahili istekleri birden çok HEAD ve GET isteğinden oluşur- Örnek akış şöyledir
- İmaj manifest'inin varlığını kontrol etme:
HEAD /v2/my-image/manifests/latest - İmaj manifest'ini indirme:
GET /v2/my-image/manifests/latest - Manifest hash'iyle yeniden indirme:
GET /v2/my-image/manifests/sha256:... - İmaj metadata blob'unu indirme:
GET /v2/my-image/blobs/sha256:... - İmaj layer blob'unu indirme:
GET /v2/my-image/blobs/sha256:...
- İmaj manifest'inin varlığını kontrol etme:
- Sonuçta
docker pull, gerekli dosyaları HTTP üzerinden indirme sürecine oldukça yakındır - Statik dosya sunucusu gerekli dosyaları beklenen yollara koyar ve her isteğe uygun Content-Type header'ını ayarlarsa konteyner imajı pull edilebilir
- S3 bucket'ı bu iki koşulu karşılayabildiği için dikkatli yapılandırıldığında konteyner registry'si gibi davranır
Deneysel yaklaşımın sınırları
- Bu yöntem hâlâ deneysel ve daha fazla araştırma yapılmadan güçlü sonuçlara varmak zor
- S3, kesin anlamda bir konteyner registry'si değildir
docker pushyapılamazdocker pullyapılabilmesi, HTTP istek yapısı ile statik dosya sunma biçiminin örtüşmesinin sonucudur
- Mevcut konteyner registry'leri, dosyaları bir bucket'a yükleme yönteminden daha fazla özellik sunar
- Standart push yöntemiyle yüklenen imajın gerçekten geçerli olduğuna güvenilebilir
- Layer'lar için otomatik güvenlik taraması ve uyarılar sunabilir
- Private depo erişim izinleri native olarak tanımlanabilir
- Beklendiği gibi çalışırsa public konteyner imajlarını Cloudflare R2'de barındırma yöntemi de mümkün hâle gelebilir
1 yorum
Hacker News yorumları
OCI Distribution Spec iyi tasarlanmış bir şartname gibi okunmadığı için üzücü
Şartnameye göre katman push işlemleri sıralı yapılmak zorunda; bu yüzden chunk olarak yükleseniz bile her chunk bitmeden sonrakine geçilemiyor. DockerHub ve GHCR üzerinde yaptığım testlere göre chunk upload zaten bozuk ve istemciler de her blob/katmanı tek parça olarak yükleme eğiliminde. Şartname ayrıca RFC7233 biçimiyle uyumlu olmayan bir
Content-Rangedeğer biçimini de öneriyorElbette blob düzeyinde paralellik var, ama blob içi paralellik yok. Bir diğer şikâyetim de tag listesinin sayfalandırmasını standartlaştırma fırsatının kaçırılmış olması. Standarttaki ilgili ifade yanlışlıkla silinince [1], her registry bunu kendi kafasına göre uygulamaya başladı
[1] https://github.com/opencontainers/distribution-spec/issues/4...
Bunu tamamen kötülemek için söylemiyorum. Gerçekten devrim niteliğindeydi; Linux namespace kullanımını eskisine göre çok daha kolay hâle getirdi ve dünyayı daha iyi bir yöne değiştirdi. Sadece teknik olgunluktan ziyade her zaman kullanıcı deneyimini öne koydu; bu da başlı başına kötü bir şey değil. Perl ya da FTP ile gönderilip alınan CSV'lerle pahalı sorunları çözen pek çok sıkıcı şirket olduğu gibi, sıkıcı hatta kötü teknolojiler bile iyi bir paketle sunulduğunda büyük değer yaratabiliyor
Yine de bazen bugünkünden çok daha iyi olabilirdi diye düşününce burukluk hissediyorum
Örneğin
.dkr.ecr..amazonaws.com/foo/bar/baz:taggibi bir biçim çalışmıyor; yalnızca düz depolama mümkün olduğu için image adları veya tag'ler gereğinden fazla uzuyor. Teoride Terraform'da ECR repository nesnesi oluşturarak benzer bir şeyi taklit edebilirsiniz, ama sonuç image yolu dinamik olan pipeline'larda pek iyi değil. CI pipeline'ının IAM rolüne rahatsız edici derecede fazla yetki vermek gerekiyor ve AWS kaynaklarının merkezi Terraform deposunun dışında yönetilmesi de hoşuma gitmiyor[1] https://stackoverflow.com/questions/64232268/storing-images-...
Cloudflare bir zamanlar R2 kullanan container registry server'ını açık kaynak olarak yayımlamıştı
Kullanan var mı merak ediyorum
[1]: https://github.com/cloudflare/serverless-registry
Bazı kullanım alanlarında büyük sorun olmayabilir, ama bazı durumlarda doğrudan elenme sebebi olabilir
Yazarıyım. OCI spesifikasyonunda katman push işleminin neden sıralı olması gerektiğini bilen varsa anlatırsa sevinirim
Bunun basitçe tarihsel bir tesadüf mü, yoksa gizli bir nedeni mi var merak ediyorum. Açık söylemek gerekirse, birden çok katman elbette paralel push edilebilir; burada bahsettiğim, tek bir katman içeriğinin sıralı push edilmesi gereken kısım
N+Timeoutsonrasında bunun tamamlanmamış bir upload olduğu açıktır; dolayısıyla silinmesi yeterlidirKısmi upload’ların nasıl ele alınacağına dair uygulama ayrıntısını basitleştirmiş olur. Aksi halde her chunk’ın sonunda diğer tüm chunk’ların mevcut olup olmadığını kontrol edip tamamlama işlemi yapmak gerekir. Yine de bu bir uygulama ayrıntısı ve anlamlı ya da bilinçli bir tasarım olup olmadığı şüpheli. S3 yaklaşımı iyi çalışacak gibi görünüyor; geçmişte büyük imajlar dağıtan bir şirkette benzer bir şeyi denemiştim. Aylık GB başına 0,10 dolar epey birikiyordu
ECR’nin ek özelliklerini kaybediyorsunuz ama şahsen bu özelliklerin oldukça sınırlı olduğunu düşünüyorum
İstemci blob upload’ını bitirirken tüm blob’un digest’ini sağlamalı. Bu gereksinim, sunucunun aldığı baytların bütünlüğünü doğrulayabilmesi için var gibi görünüyor. Sunucu digest kontrolüne ancak son HTTP isteğinde başlarsa, önceki HTTP isteklerinde depoya yazılmış blob içeriğinin tamamını tekrar okuması gerekir. Büyük katmanlarda bu gecikme kabul edilemeyebilir. Belirli bir istemci gereksinimi nedeniyle 150GiB blob’lara kadar çalıştığını doğruladık
Bunun yerine bizim uygulamada digest hesaplamasını tüm istek dizisi boyunca sürdürürüz. Blob verisini chunk’lar halinde alırken aynı anda digest hesaplaması yapar ve blob deposuna stream ederiz. Her istek arasında digest hesaplama durumunu,
Locationheader’ıyla istemciye döndürülen upload URL’sinin içinde serileştiririz. Kabaca şu kodda ele alınıyor: https://github.com/sapcc/keppel/blob/7e43d1f6e77ca72f0020645...Bildiğim kadarıyla referans uygulama da aynı yaklaşımı kullanıyor. Digest hesaplaması yalnızca sıralı yapılabildiği için upload’ın da sıralı ilerlemesi gerekiyor
[1] https://github.com/sapcc/keppel
[2] https://github.com/distribution/distribution
Bir GitHub deposu bağlantısı bile olsa iyi olur. Arka plan şu:
$PROGRAMMING_LANGUAGEiçinden programatik olarak OCI imajları oluşturmanın bir yolunu arıyorum ya da kendim uygulamayı düşünüyorum. Buildah gibi olsun, ama komut satırı arayüzü değil de gerçek bir programlama dili için API olsun istiyorum. Elbette Buildah’ı alt süreç olarak çağırmak mümkün, ama bu biraz zahmetli; ayrıca Buildah’ın iç durumu ile etkileşmek veya temizlik yapmak gibi konuları da düşünmek gerekiyor ve Buildah şu anda Mac’i de desteklemiyorEskiden Docker’a paralel push eklemiş olabilirim, ama pull ile push’u karıştırıyor da olabilirim. Sonradan baktığımda çalışmamın nihai push değil, kontrol paralelleştirme tarafında olduğunu gördüm. Bir katmanın hangi katmanın “üstüne” geldiğini açıkça belirtiyorsa, işaret edilen ID’nin zaten mevcut olması gerektiğinden böyle olabilir
Oldukça güzel bir kullanım senaryosu
Şahsen sadece Nexus kullanıyorum. Yeterince iyi çalışıyor ve OCI imajlarından apt paketlerine, özel Maven, NuGet, npm depolarına kadar pek çok şeyi destekliyor. Ancak yapılandırması ve kaynak kullanımı biraz can sıkıcı; özellikle de temizlik politikaları tarafı: https://www.sonatype.com/products/sonatype-nexus-repository
Yine de
docker pull’un “sadece” birHEADveGETisteği demeti olması gerçekten hoş. Uzun zamandır iyi çalışan şeyi aynen kullanıp gereksiz yere karmaşıklaştırmayan bu tür sağduyulu kararları daha fazla teknolojide görmek isterim. Kimlik doğrulama ve temizlik işlevleri de olan basit konteyner depolarının daha fazla olmaması şaşırtıcı. Nexus ve Harbor, gerçek kullanım için ikisi de epey karmaşıkBu başlıkta kimsenin bahsetmemiş olmasına şaşırdım
CNCF’nin Distribution’ı, eski Docker Registry, registry’yi S3’ten alan CloudFront imzalı URL’lerle destekleme özelliğini içeriyor [1]
https://distribution.github.io/distribution/storage-drivers/...
https://github.com/distribution/distribution ile ilgili sorunun ne olduğunu merak ediyorum
Bu yöntem oldukça pahalı görünüyor; yazıda maliyet konusunun da ele alınmış olmasını isterdim. Hem S3 hem de R2’yi merak ediyorum
Ücretsiz internete giden trafik maliyeti aynı, ancak herkese açık ECR depolarında AWS içi kullanım için dışa giden trafiği ücretsiz yapan bir istisna var
GET/PUTmaliyeti ve bant genişliği maliyeti AWS web sitesinden görülebilir: https://aws.amazon.com/s3/pricing/Geliştirme araçları dışında Docker’ı pek kullanmıyorum, ama neden özel container registry diye bir şeyin var olması gerektiğini hiç anlayamadım
Bana sadece rant kollama gibi geliyor. Kendi yönettiğiniz bir imaj dosyası benzeri bir şey oluşturup istediğiniz gibi kullanmaya kıyasla pratikte ne gibi bir avantajı var, merak ediyorum
docker savevedocker importkullanabilirsinizdocker save alpine:3.19 > alpine.tardocker load < alpine.tarAma bu kez o tar dosyasını yönetmeniz gerekir ve tüm sistemlerin onun nerede olduğunu ve nasıl erişileceğini bilmesi gerekir. Ya da tekerleği yeniden icat etmeden Docker’ın zaten sunduğu yöntemi kullanabilirsiniz
Bu yüzden ya kendi registry’nizi kurmanız ya da birine para ödeyip bunu yaptırmanız gerekir. Elbette imajları yalnızca geliştirme için kullanıyorsanız bunların hiçbiri anlamlı değildir; imajları geliştirme makinesinde saklamanız yeterli
Tüm eski sürümlerin bulunduğu ve birden fazla tüketicinin kolayca erişebildiği merkezi bir depoya ihtiyaç vardır. Uygulamayı derledikten sonra çalışabileceği her yere tek tek itmek istemezsiniz. Bir kez derleyip merkezi depoya push edersiniz, her yerin de o depoyu referans almasını sağlarsınız
Özel depo barındırma için mutlaka para ödemeniz de gerekmez. Kendi kendinize barındırabileceğiniz pek çok araç var
Ortam bazında her şeyi Terraform, Bicep, Pulumi ile yapılandırabilirsiniz
ECR gerçekten de imaj katmanlarını birden çok parça halinde yüklemeye imkân verecek şekilde tasarlanmış gibi görünüyor
İlgili ECR API’leri arasında her imaj katmanı yüklemesinin başında çağrılan
InitiateLayerUpload API, her katman parçası için çağrılanUploadLayerPart API(en fazla 20 MB) ve katman yüklemesinden sonra imaj katmanı referanslarını içeren imaj manifest’ini push edenPutImage APIvar. Tuhaf olan, katman parçalarını base64 kodlamasıyla yüklemek zorunda olmanız; bu da veriyi yaklaşık %33 artırıyorDosya yolu yerleşimini endpoint kontrol mekanizması olarak kullanma fikri ilginç
Ancak
Docker-Content-Digestheader’ının nasıl ele alınacağını merak ediyorum. Zorunlu değil ama yanıta eklenmesi öneriliyor; birçok istemci bunu bekler ve header’ı olmayan katmanları reddedebilir. Ayrıca OCI 1.1 spesifikasyonundaki referrers API gibi özellikleri de kaçırabilirsiniz. Uygulaması epey zahmetli olacak gibi