Apple Silicon (ARM64) dizüstüler, bulut tarafında ise yaygın AMD64 sunucular derken, tek bir Docker imajıyla her yerde çalışmak artık bir zorunluluk. Bu yazıda, Docker Buildx kullanarak çok mimarili (multi-arch) imaj oluşturmayı ve GitHub Actions ile her push sonrasında otomatik olarak Docker Hub’a yayınlamayı adım adım anlatıyorum.
Amaç net: Tek bir tag altında linux/amd64 ve linux/arm64 manifest’leri içeren, hafif ve güvenilir bir imaj üretmek. Böylece ister ARM tabanlı bir Raspberry Pi, ister AMD64 bir Kubernetes node’u olsun, aynı etiketi çekip sorunsuz çalıştırabileceksiniz.
Gereksinimler ve Temel Kavramlar
Buildx, Docker’ın gelişmiş build sürücüsüdür. Çok mimarili build, cache yönetimi, manifest listeleri ve daha fazlasını destekler. QEMU ise farklı mimariler için kullanıcı modunda emülasyon sağlayarak tek bir makinede çoklu platform derleme yapmaya imkan verir. Yayınladığınız imajlar tek bir tag altında toplanır; client çektiğinde mimarisine uygun katmanı indirir.
Yerelde Buildx Kurulumu ve Hızlı Test
Önce Buildx’in etkin olduğundan emin olun. Modern Docker Desktop sürümlerinde varsayılan olarak geliyor. CLI ile yeni bir builder yaratıp kullanabilirsiniz:
docker buildx create --name multiarch --use
docker buildx inspect --bootstrap
Basit bir test için iki platforma birden build alıp registry’ye push edelim. Docker Hub’a giriş yapmayı unutmayın:
docker login
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t KULLANICI_ADI/uygulama:deneme \
--push .
Bu komut, yerel makinenizde emülasyon üzerinden derleyerek manifest listesi içeren bir imaj yayınlar. İndirme sırasında doğru mimari otomatik seçilir.
Dockerfile İçin Pratik İpuçları
Çok mimarili build’lerde Dockerfile’ınızı platform farkındalığı ile yazmak önemlidir. Multi-stage kullanın ve base imajları mümkün olduğunca alpine veya distroless tercih edin. Ayrıca Buildx, bazı değişkenleri otomatik sağlar: TARGETOS, TARGETARCH, TARGETPLATFORM.
Örneğin Go tabanlı bir uygulama için minimal bir Dockerfile şöyle olabilir:
# syntax=docker/dockerfile:1.7
FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /bin/app ./cmd/server
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /bin/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
Burada GOOS/GOARCH değerlerini Buildx sağlıyor. Böylece tek seferde ARM64 ve AMD64 çıktıları üretiliyor. Node.js benzeri yorumlanan dillerde genellikle ekstra işlem gerekmese de, mimariye bağlı paketler (ör. native addon’lar) varsa platforma özel kurulum adımları eklemelisiniz.
GitHub Actions ile Otomatik Yayınlama
Her etiket veya ana dala push sonrası otomatik olarak çok mimarili imaj yayınlamak için aşağıdaki workflow’u kullanabilirsiniz. Repository > Settings > Secrets bölümünde DOCKERHUB_USERNAME ve DOCKERHUB_TOKEN sırlarını oluşturmayı unutmayın.
name: docker-multiarch
on:
push:
branches: [ "main" ]
tags: [ "v*" ]
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract tags and labels
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/uygulama
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
Bu iş akışı; QEMU ve Buildx’i hazırlar, Docker Hub’a giriş yapar, branch/semver/commit’e göre etiketler üretir, iki platform için build alır ve imajı push eder. cache-to/cache-from ile katmanlar GitHub’ın cache’inde saklandığı için tekrar derlemeler belirgin şekilde hızlanır.
Yayın Sonrası Doğrulama
Manifest’i kontrol etmek için şu komutu çalıştırın:
docker buildx imagetools inspect KULLANICI_ADI/uygulama:latest
Çıktıda hem linux/amd64 hem de linux/arm64 listeleniyorsa her şey yolunda demektir. Ayrıca bir ARM makinede docker run ile test etmek, gerçek koşulları görmek açısından faydalıdır.
İpuçları ve Sık Görülen Hatalar
- Native bağımlılıklar: OpenSSL, libc farkları gibi platforma duyarlı paketler kullanıyorsanız, base imajlarınızı ve paket yöneticinizi tutarlı seçin. Alpine ile glibc tabanlı dağıtımların farklarını göz önünde bulundurun.
- Boyut optimizasyonu: Çok aşamalı build, .dockerignore ve distroless tabanlarını kullanın. Gerekirse --target ile üretim aşamasını ayrılayın.
- Güvenlik ve tedarik zinciri: provenance: true ile SBOM/attestation üretimini açtınız; ayrıca imajları imzalamak için cosign gibi araçları değerlendirin.
- Versiyonlama: latest etiketine ek olarak semver ile tag’lemek, geriye dönüşleri kolaylaştırır. metadata-action bu süreci oldukça pratik hale getiriyor.
Sonuç olarak, Docker Buildx ve GitHub Actions birlikte kullanıldığında hem geliştirici deneyimini iyileştiriyor hem de kullanıcılarınızın farklı donanımlarda aynı imajı sorunsuzca çalıştırmasını sağlıyor. Kurulumu bir kez yaptıktan sonra, çok mimarili yayın şirketinizin CI/CD zincirinin doğal bir parçası haline gelir.