BuildKit, Docker'ın imaj derleme işini yapan sunucu tarafıdır; Buildx ise bu sunucuya derleme isteği gönderen istemcidir. Bir sunucuda docker build yazdığınızda aslında Buildx çalışır, isteği Docker Engine içine gömülü BuildKit'e iletir ve BuildKit Dockerfile adımlarını çözüp çalıştırır. Kısacası BuildKit motor, Buildx direksiyondur; ikisi Docker Engine ile birlikte gelir ve ek kurulum gerektirmez.

Bu yazıda BuildKit'in eski (legacy) builder'dan farkını, # syntax satırının neyi seçtiğini, builder ve driver kavramlarını, docker buildx create ile ayrı bir builder kurmayı ve küçük bir VPS'te BuildKit'i nasıl sınırlayacağınızı resmî belgelere dayanarak anlatıyoruz. Temel Dockerfile yazımı için Dockerfile yazma rehberine, Docker konularının genel haritası için Docker öğrenme rehberi sayfasına bakabilirsiniz.

İstemci ve sunucu: Buildx ile BuildKit ne iş yapar?

Docker belgeleri derleme sistemini istemci-sunucu mimarisi olarak tanımlar. İstemci olan Buildx, komut satırında verdiğiniz seçenekleri yorumlar ve bir derleme isteği (build request) hazırlar. Bu istek Dockerfile'ı, build argümanlarını, dışa aktarma (export) seçeneklerini ve önbellek seçeneklerini içerir. Sunucu olan BuildKit isteği alır, talimatları çözer ve adımları yürütür. Derleme sürerken Buildx ilerlemeyi izler ve terminale yazar. Sonuç ya istemciye geri gönderilir ya da doğrudan bir registry'ye yüklenir.

Önemli bir ayrıntı, kaynakların ne zaman taşındığıdır. BuildKit, derlemenin ihtiyaç duyduğu kaynakları yalnızca ihtiyaç anında Buildx'ten ister. Belgelerde örnek olarak yerel dosya sistemi context'i, build secret'ları, SSH soketleri ve registry kimlik doğrulama token'ları sayılır. Eski builder ise her derlemede yerel dosya sisteminin bir kopyasını baştan alırdı. Context'in nasıl gönderildiğini ve .dockerignore ile nasıl küçültüleceğini build context ve .dockerignore yazısında bulabilirsiniz.

Buildx yalnızca derleme başlatmaz. Belgelere göre BuildKit arka uçlarını, yani builder'ları oluşturmak ve yönetmek, registry'deki imajlarla çalışmak ve birden fazla derlemeyi aynı anda yürütmek de Buildx'in görevidir. Bu yüzden ileride göreceğiniz docker buildx create, docker buildx ls ve docker buildx bake komutlarının hepsi aynı istemcinin parçalarıdır.

BuildKit eski builder'a göre neler getirdi?

BuildKit eski builder'a göre neler getirdi? Kullanılmayan build stage'lerini tespit edip hiç çalıştırmaz., Birbirinden bağımsız stage'leri paralel derler., İki derleme arasında...

Belgeler BuildKit'in eski builder'ı üç ana alanda geliştirdiğini söyler: performans, depolama yönetimi ve genişletilebilirlik. Somut olarak şu davranışlar listelenir:

  • Kullanılmayan build stage'lerini tespit edip hiç çalıştırmaz.
  • Birbirinden bağımsız stage'leri paralel derler.
  • İki derleme arasında context içinde yalnızca değişen dosyaları aktarır.
  • Context içinde kullanılmayan dosyaları tespit eder ve onları göndermez.
  • Ek özellikler sunan harici Dockerfile frontend'lerini kullanabilir.
  • API'nin geri kalanında yan etki bırakmaz; ara imaj ve ara container üretmez.
  • Otomatik temizlik için build önbelleğini önceliklendirir.

Performans tarafındaki en büyük değişiklik tamamen eşzamanlı çalışan bir derleme grafiği çözücüsüdür. BuildKit mümkün olduğunda adımları paralel çalıştırır ve sonuca etkisi olmayan komutları devre dışı bırakır. Bunun altında LLB (Low-Level Build) adlı ara bir ikili format vardır. LLB, içerik adresli bir bağımlılık grafiği tanımlar; derlemenin nasıl yürütüleceği ve nasıl önbelleğe alınacağı tamamen bu grafikte ifade edilir. Eski builder imajları karşılaştırmak için sezgisel kurallar kullanırken LLB, derleme grafiğinin ve işlemlere bağlanan içeriğin checksum'larını doğrudan izler. Belgeler bunun daha hızlı, daha kesin ve taşınabilir olduğunu vurgular; önbelleğin bir registry'ye aktarılıp başka bir makinede istek üzerine çekilebilmesi de bu modelin sonucudur. Önbelleği dışa aktarma ayrıntıları build cache backend'leri yazısının konusudur.

Somut fark: --target ile multi-stage derleme

Farkı en iyi gösteren örnek belgelerdeki multi-stage senaryosudur. Aşağıdaki Dockerfile'da stage1 ve stage2 aynı base stage'inden türer ama birbirine bağlı değildir:

dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu AS base
RUN echo "base"

FROM base AS stage1
RUN echo "stage1"

FROM base AS stage2
RUN echo "stage2"
bash
docker build --no-cache -f Dockerfile --target stage2 .

BuildKit ile stage2 hedeflendiğinde yalnızca base ve stage2 işlenir; stage1'e bağımlılık olmadığı için atlanır. Belgelerdeki karşılaştırmada aynı komut DOCKER_BUILDKIT=0 ile eski builder'da çalıştırıldığında, hedef ona bağlı olmasa bile stage1 de derlenir. Test, lint ve üretim stage'lerini tek Dockerfile'da tutan projelerde bu fark gereksiz işi doğrudan ortadan kaldırır. Multi-stage yapının kendisini burada yeniden anlatmıyoruz; temeller için Dockerfile rehberine bakın.

Frontend ve # syntax satırı

Frontend, insanın okuyabildiği bir derleme formatını alıp LLB'ye çeviren bileşendir. Dockerfile da BuildKit için bir frontend tarafından işlenir. BuildKit içinde yerleşik bir Dockerfile frontend'i bulunur, ancak belgeler harici bir frontend imajı kullanmanızı önerir: böylece builder'ı kullanan herkes aynı sürümü kullanır ve hata düzeltmeleri BuildKit ya da Docker Engine güncellemesini beklemeden gelir. Harici frontend seçmek için Dockerfile'ın ilk satırına syntax parser directive'i yazılır:

dockerfile
# syntax=docker/dockerfile:1

Parser directive'ler diğer tüm yorumlardan, boş satırlardan ve talimatlardan önce gelmelidir. Aynı # işareti başka bir yerde kullanıldığında sıradan yorum olarak okunur. Frontend imajı komut satırından da seçilebilir: önceden tanımlı BUILDKIT_SYNTAX build argümanı, Dockerfile'a dokunmadan aynı işi yapar.

bash
docker build --build-arg BUILDKIT_SYNTAX=docker/dockerfile:1 .

Resmî frontend imajları Docker Hub'daki docker/dockerfile deposunda iki kanaldan yayımlanır. Stable kanal anlamsal sürümlemeyi izler; labs kanalı ise henüz stable'a geçmemiş özelliklere erken erişim verir:

EtiketDavranış
docker/dockerfile:1En son 1.x.x sürümünü izler; minor ve patch güncellemeleri alır (önerilen)
docker/dockerfile:1.2Yalnızca 1.2.x patch sürümlerini alır; 1.3.0 çıkınca güncellenmez
docker/dockerfile:1.2.1Değişmez; hiç güncellenmez
docker/dockerfile:1-labs1 ile aynı, deneysel özellikler açık
docker/dockerfile:labsLabs kanalındaki en son sürüm

Belgeler docker/dockerfile:1 etiketini önerir; BuildKit derleme sırasında sözdizimi güncellemesini kendisi kontrol eder. Belirli bir sürüme sabitlediğinizde düzeltmeleri almak için Dockerfile'ı elle güncellemeniz gerekir; eski sürümler yeni builder'larla uyumlu kalmaya devam eder. Labs kanalındaki erken erişim özellikleri anlamsal sürümlemeye uymaz ve geriye dönük uyumlu olmayabilir; bu yüzden labs kullanıyorsanız sürümü sabitlemeniz önerilir.

Builder ve driver kavramları

Builder ve driver kavramları: docker, docker-container, kubernetes, remote

Belgelerde builder, derlemelerinizi çalıştırmak için kullandığınız bir BuildKit daemon'u olarak tanımlanır. Docker Engine kurulduğunda otomatik olarak default adlı bir builder oluşur. Bu builder, daemon'a gömülü BuildKit kütüphanesini kullanır, yapılandırma gerektirmez ve doğrudan Docker daemon'una ve aktif Docker context'ine bağlıdır. Docker context'ini değiştirdiğinizde default builder da yeni context'i gösterir; uzak sunucu yönetimi için docker context yazısına bakabilirsiniz.

Builder'ın nerede ve nasıl çalıştığını driver belirler. Buildx şu driver'ları destekler:

  • docker: Docker daemon'una gömülü BuildKit kütüphanesini kullanır. Varsayılan builder budur.
  • docker-container: Docker ile ayrı bir BuildKit container'ı oluşturur.
  • kubernetes: Bir Kubernetes kümesinde BuildKit pod'ları oluşturur.
  • remote: Elle yönetilen bir BuildKit daemon'una doğrudan bağlanır.
  • cloud: Docker Build Cloud'daki yönetilen bir builder'a bağlanır.

Belgelerdeki karşılaştırma tablosu, varsayılan docker driver'ının basitliği öne aldığını ve gelişmiş özelliklerde sınırlı kaldığını gösterir:

Özellikdockerdocker-containerkubernetesremote
İmajı otomatik yüklemeEvetHayırHayırHayır
Önbellek dışa aktarmaKısmiEvetEvetEvet
Tarball çıktısıHayırEvetEvetEvet
Çok mimarili imajHayırEvetEvetEvet
BuildKit yapılandırmasıHayırEvetEvetDışarıdan yönetilir

Tablodaki "kısmi" ifadesi şunu anlatır: docker driver'ı tüm önbellek dışa aktarma seçeneklerini desteklemez. Önbellek backend belgelerine göre inline, local, registry ve gha backend'leri bu driver'da yalnızca containerd image store açıksa çalışır. Docker Engine 29 ile yeni kurulumlarda containerd image store varsayılan hâle geldiği için bu koşul birçok yeni sunucuda zaten sağlanır; ayrıntılar containerd image store yazısında. docker driver'ında BuildKit sürümünü seçemez, ek BuildKit parametresi veremezsiniz; bunlar Docker Engine tarafından içeride sabitlenir.

Yeni builder oluşturma ve yönetme

docker driver'ı kullanan builder'lar elle oluşturulamaz, yalnızca Docker context'inden otomatik doğar. Diğer driver'lar için docker buildx create kullanılır. --driver bayrağını vermezseniz Buildx varsayılan olarak docker-container driver'ını seçer. Tipik bir akış şöyledir:

bash
docker buildx create --name benim-builder --driver docker-container --bootstrap --use
docker buildx ls
docker buildx inspect benim-builder
docker buildx du --builder benim-builder

--use yeni builder'ı seçili builder yapar; docker buildx ls çıktısında seçili olanın adının yanında yıldız (*) görünür. docker buildx inspect yalnızca aktif bir builder'ı inceleyebilir; --bootstrap builder'ı hemen başlatır. İlk başlatmada Buildx varsayılan olarak moby/buildkit imajını çeker ve buildx_buildkit_ önekiyle adlandırılmış bir container oluşturur. docker buildx du builder'ın diskte ne kadar önbellek tuttuğunu gösterir; sunucu diski dolduğunda ilk bakılacak yerlerden biridir. Önbelleği temizleme komutları docker prune yazısında ele alınıyor.

Builder'ı kaldırmak için docker buildx rm benim-builder kullanılır. Seçili builder'ı kaldırırsanız varsayılan docker builder'ı otomatik olarak seçilir; varsayılan builder'ın kendisi kaldırılamaz. Dikkat edilmesi gereken nokta, kaldırma işleminin builder'ın yerel önbelleğini de silmesidir. docker-container driver'ı tüm BuildKit durumunu ayrı bir Docker volume'ünde tuttuğu için, önbelleği koruyarak builder'ı yeniden oluşturmak isterseniz --keep-state bayrağını kullanabilirsiniz:

bash
docker buildx rm --keep-state benim-builder
docker buildx create --name benim-builder --driver docker-container --use --bootstrap

Belgelere göre aynı adla yeniden oluşturulan builder önceki durumun tamamını devralır. Uzak (remote) builder'larda ise kaldırma işlemi uzak önbelleği etkilemez ve uzak BuildKit daemon'unu durdurmaz; yalnızca sizin o builder'a olan bağlantınızı siler.

docker build ile docker buildx build aynı şey mi?

Belgeler docker build komutunun docker buildx build için bir takma ad olduğunu, ama aralarında ince farklar bulunduğunu belirtir. docker build, eski CLI sürümleriyle geriye dönük uyumluluk için her zaman Docker Engine ile gelen varsayılan builder'ı kullanır. docker buildx build ise derlemeyi göndermeden önce farklı bir builder seçip seçmediğinize bakar. Yani docker buildx use benim-builder çalıştırdıktan sonra bile düz docker build varsayılan builder'a gider.

docker build ile varsayılan olmayan bir builder kullanmak için builder'ı açıkça belirtmeniz gerekir:

bash
docker build --builder benim-builder .
BUILDX_BUILDER=benim-builder docker build .

Belgelerin genel önerisi, özel builder kullanırken docker buildx build komutunu tercih etmenizdir; böylece seçili builder yapılandırması doğru yorumlanır. BUILDX_BUILDER ortam değişkeni CI betiklerinde builder seçimini tek bir yerde sabitlemek için de kullanışlıdır.

Derleme sonucu nereye gidiyor? --load ve default-load

Yeni başlayanların en sık karşılaştığı şaşkınlık, docker-container builder'ıyla derlenen imajın docker image ls listesinde görünmemesidir. Belgelere göre yalnızca docker driver'ı sonucu yerel imaj deposuna otomatik yükler. Diğer driver'larda çıktı belirtmezseniz sonuç yalnızca build önbelleğinde kalır ve Buildx bunu bir uyarıyla bildirir. İmajı yerel depoya almak için --load, registry'ye göndermek için --push kullanılır:

bash
docker buildx build --load -t benim/uygulama:dev --builder benim-builder .
docker buildx build --push -t registry.example.com/benim/uygulama:1.0 --builder benim-builder .

Bu davranışı varsayılan driver'a benzetmek isterseniz builder'ı default-load driver seçeneğiyle oluşturabilirsiniz. Belgelerdeki not önemlidir: --output ile farklı bir çıktı biçimi verirseniz, ayrıca --output type=docker ya da --load belirtmedikçe sonuç imaj deposuna yüklenmez. Çıktı türlerinin tamamı build output ve exporter yazısında anlatılıyor.

bash
docker buildx create --name benim-builder --driver docker-container --driver-opt default-load=true

Küçük bir VPS'te BuildKit'i yapılandırmak

docker-container veya kubernetes builder'larına özel BuildKit yapılandırması, docker buildx create komutuna --buildkitd-config bayrağıyla bir TOML dosyası verilerek uygulanır. Belgelerde düşük güçlü makineler için özellikle faydalı olduğu belirtilen ayar, çözücünün paralelliğini sınırlamaktır:

ini
# /etc/buildkitd.toml
[worker.oci]
  max-parallelism = 4
bash
docker buildx create --use \
  --name benim-builder \
  --driver docker-container \
  --buildkitd-config /etc/buildkitd.toml

Aynı dosyayla registry aynası (mirror) da tanımlanabilir. Belgelerdeki örnek docker.io isteklerini mirror.gcr.io adresine yönlendirir; debug = true ise aynanın kullanıldığını BuildKit günlüklerinde görmenizi sağlar. Docker Hub pull limitine takılan sunucular için bu bir seçenektir; limitlerin kendisi Docker Hub pull limiti yazısında.

ini
debug = true
[registry."docker.io"]
  mirrors = ["mirror.gcr.io"]

docker-container driver'ı ayrıca container'ın kaynaklarını --driver-opt ile sınırlamanıza izin verir. Belgelerdeki tabloda memory, memory-swap, cpu-quota, cpu-period, cpu-shares, cpuset-cpus ve cpuset-mems seçenekleri yer alır; restart-policy seçeneği varsayılan olarak unless-stopped değerindedir. Aynı sunucuda web uygulamanız da çalışıyorsa derleme container'ına bu seçeneklerle bir tavan koyabilirsiniz. Bellek ve CPU sınırlarının genel davranışı için CPU ve bellek limiti yazısına bakın.

Varsayılan docker driver'ı TOML dosyası kabul etmez. Bu builder'ın önbellek temizleme (garbage collection) ayarları Docker daemon yapılandırma dosyasındaki builder anahtarı altında yapılır; bu ayar build cache yazısında, daemon.json dosyasının kendisi ise daemon.json yapılandırma yazısında anlatılıyor.

Docker Engine 29 ve BuildKit sürümü

Docker Engine, gömülü BuildKit'i kendi sürümleriyle birlikte günceller. Engine 29 sürüm notları her ara sürümde BuildKit güncellemesini ayrıca belirtir; örneğin 29.9.3 sürümü BuildKit'i v0.34.2'ye yükseltir ve bu güncelleme iki BuildKit güvenlik açığını kapatır. Önceki 29.x sürümlerinde de BuildKit güncellemeleriyle gelen güvenlik düzeltmeleri listelenmiştir. Varsayılan builder kullanıyorsanız BuildKit'i güncel tutmanın yolu Docker Engine'i güncel tutmaktır. docker-container builder'ında ise BuildKit ayrı bir imajdan çalışır; image driver seçeneğiyle hangi BuildKit imajının kullanılacağını belirleyebilirsiniz. Engine 29 değişikliklerinin özeti Docker Engine 29 yenilikleri yazısında.

Sık yapılan hatalar

Sık yapılan hatalar: Seçili builder'ın docker build ile kullanıldığını sanmak, --load unutmak, Builder'ı silip önbelleğin kaldığını varsaymak, Varsayılan driver'dan her şeyi...
  • Seçili builder'ın docker build ile kullanıldığını sanmak: docker build varsayılan builder'a gider; özel builder için docker buildx build, --builder ya da BUILDX_BUILDER kullanın.
  • --load unutmak: docker-container builder'ında çıktı belirtmezseniz imaj yalnızca önbellekte kalır ve docker run onu bulamaz.
  • Builder'ı silip önbelleğin kaldığını varsaymak: docker buildx rm yerel önbelleği de siler; korumak için --keep-state gerekir.
  • Varsayılan driver'dan her şeyi beklemek: tarball çıktısı ve çok mimarili imaj için docker driver tek başına yetmez; containerd image store ya da docker-container builder gerekir. Çok mimarili derleme multi-platform build yazısında.
  • # syntax satırını ikinci satıra yazmak: parser directive yalnızca dosyanın en başında tanınır; önünde yorum veya boş satır varsa sıradan yorum sayılır.

Sık Sorulan Sorular

BuildKit'i ayrıca kurmam gerekir mi?

Hayır. Belgelere göre Buildx ve BuildKit, Docker Engine ve Docker Desktop ile birlikte kurulur ve BuildKit varsayılan builder'dır. Ayrı bir BuildKit container'ı istiyorsanız docker buildx create bunu sizin yerinize oluşturur.

DOCKER_BUILDKIT=0 ile eski builder'a dönmeli miyim?

Belgeler bu değişkeni iki builder arasındaki farkı göstermek için kullanır; eski builder kullanılmayan stage'leri de derler ve BuildKit'in yukarıda sayılan özelliklerinden yararlanamaz. Compose belgeleri de DOCKER_BUILDKIT=0 verildiğinde docker compose build komutunun klasik builder'ı kullandığını belirtir.

Hangi driver'ı seçmeliyim?

Tek sunucuda imaj derleyip aynı sunucuda çalıştırıyorsanız varsayılan docker driver çoğu zaman yeterlidir. Önbelleği her backend'e aktarmak, tarball üretmek, BuildKit sürümünü seçmek veya kaynakları sınırlamak istiyorsanız docker-container uygundur. Kubernetes kümeniz varsa kubernetes, kendi yönettiğiniz bir BuildKit daemon'u varsa remote driver'ı kullanılır.

Builder ne kadar disk kullanıyor, nasıl görürüm?

docker buildx du tüm builder'ların toplam disk kullanımını, --builder ile tek bir builder'ınkini gösterir. Otomatik temizlik kuralları ve sınırlar build cache yazısında anlatılıyor.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Docker öğrenme rehberi · Multi-platform build · Build cache backend'leri · Build output ve exporter · docker buildx bake · Dockerfile yazma rehberi