Giriş: Neden Çok Mimarili İmaj?
Apple Silicon (ARM64) cihazların, bulut sağlayıcıların ve edge cihazların yükselişi, tek mimariye derlenmiş konteyner imajlarının yeterli olmadığı bir dönemi başlattı. Uygulamanızı hem linux/amd64 hem de linux/arm64 üzerinde sorunsuz çalıştırmak istiyorsanız, Docker Buildx ve QEMU emülasyonu devreye giriyor. Bu yazıda, yerelde hızlıca çok mimarili imaj üretecek, ardından GitHub Actions ile her push veya tag’de otomatik olarak registry’ye yayınlayacak bir kurulum yapacağız.
Önkoşullar ve Temel Kavramlar
Başlamadan önce sisteminizde Docker Engine veya Docker Desktop’ın güncel bir sürümü kurulu olmalı. Buildx varsayılan olarak Docker ile gelir, ancak Linux kullanıcıları için docker buildx komutunun aktif olduğundan emin olun. Yerelde farklı mimariler için derleme yaparken QEMU desteği gerekir; Buildx bunu otomatik konfigüre edebilir. Ayrıca Docker Hub veya GHCR (GitHub Container Registry) gibi bir kayıt defterinde hesabınız ve kimlik bilgisi gerekecek. “Mimari” derken kastedilen: Intel/AMD tabanlı sunucular için amd64, Apple M serisi ve çoğu ARM tabanlı cihaz için arm64.
Dockerfile: Çok Aşamalı ve Mimariden Bağımsız
Örnek olarak küçük bir Go uygulaması için çok aşamalı bir Dockerfile kullanalım. Go, cross-compile’a yatkın olduğu için çok mimarili imajlarda pratiktir. Buildx, derleme sırasında TARGETPLATFORM ve TARGETARCH gibi değişkenleri otomatik olarak geçirir.
# syntax=docker/dockerfile:1.6
FROM golang:1.22-alpine AS build
WORKDIR /src
COPY . .
# CGO'yu kapatıp hedef mimariyi Buildx'ten alıyoruz
ARG TARGETARCH
ENV CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -o /out/app .
FROM alpine:3.20 AS runtime
RUN adduser -D -u 10001 app
USER app
COPY --from=build /out/app /app
EXPOSE 8080
ENTRYPOINT ["/app"]
Yukarıdaki Dockerfile, cache mount’larını kullanarak derlemeleri hızlandırır, root olmayan bir kullanıcı ile çalıştırır ve minimum imaj boyutu sağlar. Benzer bir yaklaşımı Node.js, Python veya Rust projelerinde de çok aşamalı yapı ile uygulayabilirsiniz.
Buildx’i Etkinleştirme ve Yerelde Test
Önce Buildx builder’ını oluşturun ve QEMU’yu başlatın:
docker buildx create --name xbuilder --use
docker buildx inspect --bootstrap
Ardından çok mimarili imajı derleyip bir kayıt defterine itin. Örnek olarak Docker Hub kullanıyorsanız:
docker login
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t KULLANICI_ADI/uygulama:1.0.0 \
-t KULLANICI_ADI/uygulama:latest \
--push .
İmajı emülasyonla farklı mimarilerde çalıştırmayı test edebilirsiniz:
docker run --rm --platform linux/arm64 KULLANICI_ADI/uygulama:1.0.0 --help
GitHub Actions ile Otomatik Yayın
Süreci otomatikleştirmek için depo köküne .github/workflows/build.yml adında bir iş akışı ekleyin. Aşağıdaki örnek, GHCR’ye push eder; Docker Hub için registry ve kimlik bilgilerini uyarlayın.
name: build-and-push-multi-arch
on:
push:
branches: ["main"]
tags: ["v*"]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: meta
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=ref,event=branch
type=raw,value=latest,enable={{is_default_branch}}
- 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
Bu iş akışı; QEMU’yu kurar, Buildx’i etkinleştirir, GHCR’ye giriş yapar, semantik veya branch tabanlı etiketleri otomatik üretir ve iki mimari için imajı derleyip yayınlar. Docker Hub kullanıyorsanız registry satırını kaldırıp username/password için DOCKERHUB_USERNAME ve DOCKERHUB_TOKEN gibi secret’lar tanımlayın.
İnce Ayar: Performans, Güvenlik ve Boyut
Derlemeleri hızlandırmak için cache kullanımı kritik önemdedir. Yerelde --cache-to ve --cache-from bayrakları veya GitHub Actions’ta type=gha ile katmanları önbelleğe alın. .dockerignore dosyası ile gereksiz dosyaları dışarıda bırakın. Güvenlik açısından root olmayan kullanıcı kullanmak, yalnızca gerekli portları açmak, en küçük taban imajlarını (ör. alpine veya distroless) tercih etmek, SBOM ve kaynak kanıtı için --sbom=true ve --provenance=true kullanmak iyi pratiklerdir. İmajlarınızı imzalamak için cosign ile CI adımı ekleyebilirsiniz. Etiket stratejisinde hem latest hem de v1.2.3 gibi sürüm etiketlerini birlikte yayınlamak, geriye dönük izleme ve hızlı geri dönüş (rollback) sağlar.
Yayına Alındıktan Sonra Doğrulama
Yayınlanan imajın manifest listesine bakarak gerçekten çok mimarili olup olmadığını doğrulayın: docker buildx imagetools inspect ghcr.io/HESAP/REPO:latest. Çıktıda hem linux/amd64 hem de linux/arm64 gördüğünüzde her şey yolundadır. Üretim ortamında çekme yapan sistemlerin doğru mimariyi otomatik seçeceğini unutmayın.
Sonuç
Docker Buildx, modern çok mimarili dünyada tek komutla iki farklı platforma hitap eden imaj üretmeyi kolaylaştırır. GitHub Actions ile birleştirildiğinde, her commit veya sürümde otomatik ve tekrarlanabilir bir yayın hattı elde edersiniz. Bu yaklaşım, M serisi Mac’lerde yerel geliştirmeyi hızlandırırken, bulut ve edge ortamlarında tutarlı dağıtım sağlar. Küçük dokunuşlarla (önbellek, minimal taban imaj, imzalama) performansı artırabilir ve güvenliği güçlendirebilirsiniz.