Apple Silicon Mac’ler (M1/M2/M3), AWS Graviton sunucuları ve Raspberry Pi gibi cihazların yaygınlaşmasıyla, artık tüm dünya x86_64 (Intel/AMD) mimarisinde çalışmıyor — ARM64 de gündelik bir gerçek. Bir imajı sadece tek bir mimari için build ederseniz, diğer mimaride çalışan bir makinede o imaj ya hiç çalışmaz ya da yavaş bir emülasyon katmanı üzerinden çalışır. Multi-arch build, aynı imaj etiketinin birden fazla mimari için otomatik olarak doğru sürümü sunmasını sağlar.

Sorunu somutlaştıralım

Bir imajı Intel tabanlı bir CI sunucusunda build edip Docker Hub’a gönderdiğinizde, o imaj sadece linux/amd64 mimarisi için üretilmiştir. Bu imajı bir M-serisi Mac’te veya bir ARM sunucusunda çalıştırmaya çalıştığınızda Docker, QEMU tabanlı bir emülasyon katmanına düşer — çalışır ama belirgin şekilde yavaştır, bazı durumlarda hiç çalışmaz.

Docker Buildx: çoklu mimari için resmi araç

Docker Buildx, güncel Docker sürümlerinde yerleşik gelir ve tek bir komutla birden fazla mimari için build yapıp bunları tek bir “manifest listesi” altında birleştirir:

# Buildx'in QEMU tabanlı emülatörlerini bir kerelik kurun
docker run --privileged --rm tonistiigi/binfmt --install all

# Çoklu platform destekleyen bir builder oluşturun ve kullanın
docker buildx create --name coklu-mimari --use
docker buildx inspect --bootstrap

# amd64 ve arm64 için aynı anda build edip doğrudan push edin
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t kullanici-adi/benim-api:1.0 \
  --push .

Bu komut çalıştığında Docker Hub’da kullanici-adi/benim-api:1.0 etiketinin altında aslında iki farklı imaj yayınlanır (biri amd64, biri arm64) ve bunları tek bir “manifest listesi” birbirine bağlar. Birisi docker pull kullanici-adi/benim-api:1.0 dediğinde, Docker istemcisi otomatik olarak kendi mimarisine uygun sürümü indirir — kullanıcı hangi mimarinin çekildiğini bilmesine bile gerek kalmaz.

i

--push bayrağı zorunludur çünkü çoklu platform manifest listeleri yerel Docker imaj deposunda (docker images) tam olarak saklanamaz — doğrudan bir registry’ye gönderilmeleri gerekir. Sadece yerelde test etmek isterseniz tek seferde tek bir platform için --load bayrağını kullanabilirsiniz.

GitHub Actions’ta multi-arch build

- name: QEMU kur
  uses: docker/setup-qemu-action@v3

- name: Buildx kur
  uses: docker/setup-buildx-action@v3

- name: Çoklu mimari build ve push
  uses: docker/build-push-action@v5
  with:
    context: .
    platforms: linux/amd64,linux/arm64
    push: true
    tags: kullanici-adi/benim-api:latest

Her imaj multi-arch olmalı mı?

Hayır — bazı durumlarda gerek yoktur:

  • Uygulamanız sadece belirli, bilinen bir mimaride (örn. şirket içi tek tip x86_64 sunucular) çalışacaksa ekstra karmaşıklığa gerek yok.
  • Build süresi kritikse: iki mimari için build etmek, tek mimari build etmekten belirgin şekilde daha uzun sürer (QEMU emülasyonu build sırasında da devreye girer, özellikle derleme gerektiren dillerde).

Buna karşılık, açık kaynak bir imaj yayınlıyorsanız, ekibinizde hem Intel/AMD hem Apple Silicon Mac kullanan geliştiriciler varsa, veya ARM tabanlı bulut sunucularına (maliyet avantajı için giderek daha popüler) deploy ediyorsanız multi-arch build neredeyse zorunlu hale gelir.

Dockerfile’da mimariye özgü davranış gerekiyorsa

Bazı build adımları mimariye göre farklılaşabilir (örn. farklı bir binary indirmek). Buildx, bunun için otomatik olarak TARGETARCH gibi build argümanlarını sağlar:

FROM alpine:3.20
ARG TARGETARCH
RUN echo "Bu imaj şu mimari için build ediliyor: $TARGETARCH"
# TARGETARCH değeri: amd64, arm64 vb. — buildx tarafından otomatik doldurulur

İmajınız artık farklı donanım mimarilerinde de sorunsuz ve hızlı çalışıyor. Şimdi öğrendiğimiz tüm parçaları (build, volume, network, registry, CI/CD, izleme, multi-arch) bir araya getirip uçtan uca gerçek bir projeyi sıfırdan production’a taşıyalım — bunu bir sonraki, seri sonu yazımızda yapıyoruz.