Çok Aşamalı Build
Bu sayfada
Çok Aşamalı Build
Çok aşamalı build'ler standart Dockerfile sözdizimini kullanır; aşamalar
FROM komutlarıyla birbirinden ayrılır. Size en az bağımlılıkla,
tekrarlanabilir bir build verirler.
Çok aşamalı build'i her yerde görmeyeceksiniz ama araç setinizi tek merkezde toplamanın harika bir yolu: geliştiricilerin ve build sunucularının yalnızca Docker'a ve kaynak koda ihtiyacı olur, tüm araçlar Docker imajlarında paketli gelir, böylece herkes aynı sürümleri kullanır.
Kaynaklar
Örnek Dockerfile'lar
Çok aşamalı build için standart docker build komutu kullanılır. Dockerfile
sözdizimi birden fazla FROM komutu içerir; kalıp tüm diller için aynı ama
ayrıntılar dile özgüdür.
Başlıca dillerden örnekler:
Çok Aşamalı Dockerfile'lar
Eski derleme motoruyla başlayacağız; çünkü o her aşamayı sırayla çalıştırıyor ve bu, çok aşamalı bir Dockerfile'ın yapısını apaçık gösteriyor. Sonra BuildKit'e geçip karşılaştıracağız:
# macOS veya Linux'ta:
export DOCKER_BUILDKIT=0
# VEYA PowerShell ile:
$env:DOCKER_BUILDKIT=0Bir uyarı göreceksiniz: _"DEPRECATED: The legacy builder is deprecated and will be removed in a future release."_ Bu beklenen bir durum. Docker 23'ten beri varsayılan BuildKit ve eski derleyici kaldırılma yolunda — burada yalnızca tek bir build için, karşıtlığı görmek üzere kullanıyoruz.
Şöyle bir basit çok aşamalı Dockerfile:
baseaşaması Alpine kullanıyor ve birkaç bağımlılık eklemeyi simüle ediyorbuildaşaması base üzerine kurulup bir uygulama build'ini simüle ediyortestaşaması build çıktısından başlayıp otomatik testi simüle ediyor- son aşama base'den başlayıp build çıktısını kopyalıyor
📋 labs/multi-stage/simple Dockerfile'ından simple adında bir imaj
derleyin.
Nasıl yapılacağını bilmiyor musunuz?
# siradan bir build:
docker build -t simple ./labs/multi-stage/simple/Tüm aşamalar çalışıyor ama son uygulama imajında yalnızca önceki aşamalardan açıkça eklenmiş içerik var.
İmajdan bir container çalıştırın; base ve build aşamalarından gelen içeriği yazdırıyor:
docker run simpleSon imajda test aşamasından gelen ek içerik yok.
BuildKit ve build hedefleri
BuildKit, Docker'ın derleme motoru ve Docker 23'ten beri varsayılan. Çok aşamalı build'ler için ciddi şekilde optimize edilmiş: aşamaları paralel çalıştırıyor ve çıktısı kullanılmayan aşamaları atlıyor.
Ortam değişkenini ayarlayarak BuildKit'e geri dönün (ya da yukarıdakini kaldırın):
# macOS veya Linux'ta:
export DOCKER_BUILDKIT=1
# VEYA PowerShell ile:
$env:DOCKER_BUILDKIT=1Şimdi aynı Dockerfile için build'i tekrarlayın — bu kez Docker BuildKit kullanacak:
docker build -t simple:buildkit ./labs/multi-stage/simple/Farklı aşamalardan gelen çıktıyı aynı anda göreceksiniz — ve dikkatli bakarsanız test aşamasının atlandığını fark edeceksiniz.
📋 Yeni imajdan bir container çalıştırın. Çıktı aynı mı? İmaj ayrıntılarını karşılaştırın.
Nasıl yapılacağını bilmiyor musunuz?
# container'i calistirin - cikti ayni:
docker run simple:buildkit
# imajlari listeleyin - ayni boyutta ama ayni imaj degil:
docker image ls simpleBuildKit test aşamasını atlıyor çünkü çıktısı sonraki aşamalarda
kullanılmıyor. target bayrağıyla belirli bir aşamaya kadar imaj derlemeyi
açıkça isteyebilirsiniz:
docker build -t simple:test --target test ./labs/multi-stage/simple/--targethedef aşamayı belirtir; Docker, adı verilen aşamaya kadar olan(ve o aşama dahil) tüm aşamaları derler
Bu imaj, test aşamasının çıktısıdır — son aşamanın değil.
📋 Test build'inden bir container çalıştırıp build.txt dosyasının içeriğini yazdırın.
Nasıl yapılacağını bilmiyor musunuz?
# burada cikti yok - test asamasinda CMD komutu yok
docker run simple:test
# ciktiyi gormek icin cat komutunu calistirin
docker run simple:test cat /build.txtÇıktı, build aşaması artı test aşamasından geliyor.
Basit bir Go uygulaması
Gerçek çok aşamalı build'ler, build aşamasında uygulamayı derlemek için bir SDK (Software Development Kit) imajı, derlenmiş uygulamayı paketlemek için de (build araçları olmayan) daha küçük bir çalışma ortamı imajı kullanır.
Kullandığınız imajlar ve çalıştırdığınız komutlar her dil için farklı, ama başlıca platformların tamamı için Docker Hub'da resmi imaj bulabilirsiniz:
- Java uygulamalarını derlemek için maven ve
gradle — çalışma ortamı imajı olarak eclipse-temurin (Docker Hub'ın
openjdkimajı kullanımdan kaldırıldı) - python — bağımlılıklar için Pip kurulu gelir
- Node.js uygulamaları için node — NPM
içerdiği için build aşamasında paket kurabilirsiniz
- Go uygulamaları için golang — çalışma
ortamına ihtiyaç duymadıkları için son imaj scratch'ten başlayabilir
- .NET uygulamaları için
dotnet/sdk; son uygulama imajı için dotnet/runtime veya dotnet/aspnet
Dilleri tek tek ayrıntılı işlemeyeceğiz. whoami Dockerfile bir Go uygulaması üzerinden kalıbın nasıl çalıştığını gösteriyor:
- builder aşaması Go SDK imajından başlıyor
- uygulamayı derlemek için gereken işletim sistemi paketlerini kuruyor
- sonra kütüphane listesini (
go.mod) ve kilit dosyasını (go.sum) kopyalayıpuygulamanın bağımlılıklarını kurmak için
go mod downloadçalıştırıyor - ardından kaynak kodu kopyalayıp uygulamayı derliyor
- son uygulama imajı container ortamını kuruyor
- sonra builder'dan derlenmiş çıktıyı kopyalıyor
📋 labs/multi-stage/whoami klasöründen whoami adında bir imaj derleyin.
Nasıl yapılacağını bilmiyor musunuz?
docker build -t whoami ./labs/multi-stage/whoami/BuildKit'ten gelen tüm aşama çıktısını göreceksiniz.
SDK imajları tüm build araç setini taşıdıkları için genellikle çok büyüktür. Son aşamada SDK imajı kullanmak istemezsiniz; yoksa bütün o yük uygulama imajınızda kalır.
📋 whoami ve golang imajlarının boyutlarını karşılaştırın.
Nasıl yapılacağını bilmiyor musunuz?
docker pull golang:1.27.2-alpine
docker image ls -f reference=whoami -f reference=golangVay! SDK imajı yüzlerce megabayt; uygulama imajı birkaç megabayt.
Docker 29, eski
SIZEsütununuDISK USAGEveCONTENT SIZEolarak ikiye ayırıyor, yani iki sayı göreceksiniz - aradaki fark her iki ölçüde de aynı derecede büyük.
Uygulama basit bir web sunucusu. Rastgele bir port yayınlayarak bir container çalıştırın ve portu bulun:
docker run -d -P --name whoami1 whoami
docker port whoami1
EXPOSEkomutu Docker'a container'ın hedef portunu söyler;-Pbayrağını kullandığınızda Docker expose edilmiş tüm portları yayınlar.
Artık uygulamayı kullanabilirsiniz:
curl localhost:<port>Sunucu yalnızca ortam ve istek hakkında birkaç ayrıntı yazdırıyor.
Container minimal bir imajdan çalışıyor — imajda uygulamanın çalışması için gerekli olmayan hiçbir şey yok.
Bu, uygulamanın saldırı yüzeyini küçültmeye yardım ediyor. Container içinde bir shell oturumuna bağlanmayı deneyin:
# bu basarisiz olacak
docker exec -it whoami1 shShell yok; yani bir saldırgan uygulamayı ele geçirse bile bir istismarı başlatabilmek için daha çok iş yapması gerekir.
Lab
Uygulamaların standart HTTP portlarını dinlemek için özel Linux izinlerine ihtiyacı var — container içinde bile.
whoami uygulaması dinlediği portu yapılandırmak için bir seçenek sunuyor; böylece standart olmayan bir port kullanıp potansiyel olarak daha sıkı güvenlikle çalışabilirsiniz.
Bu lab'daki hedefiniz, whoami uygulamasını bir container içinde -port
uygulama argümanıyla belirli bir portu dinleyecek şekilde çalıştırmak.
Container'ı -P (--publish-all) seçeneğiyle çalıştırdığınızda ne oluyor?
Docker yeni portu doğru eşliyor mu?
Çalışan bir container için ne yapmanız gerekiyor?
Takıldınız mı? İpuçlarına bakın veya çözümü inceleyin.
Temizlik
Bu lab'ın container'larını kaldırın:
docker rm -f $(docker ps -aq)PowerShell'de komut ikamesi sözdizimi farklı:
docker rm -f @(docker ps -aq)⚠️ Her iki sürüm de makinenizdeki tüm container'ları kaldırır, yalnızca bu lab'ın container'larını değil. Başka bir işiniz çalışıyorsa önce
docker psile kontrol edin.