Docker Compose build ve image farkı nedir?
Docker Compose dosyasında image ve build anahtarlarının VPS üzerindeki işlevlerini öğrenin. Dockerfile değişikliklerinin neden yansımadığını ve build komutunu çözün.
Docker Compose build ve image: kısa cevap
Bir Docker Compose dosyasında image:, bir kayıt defterinden (registry) çekilecek imajı belirtir; build: ise Compose'a bu makinede bir Dockerfile üzerinden imaj oluşturmasını söyler. Yalnızca image: ayarlandığında, Compose ilgili etiketi çeker ve çalıştırır. Yalnızca build: ayarlandığında, Compose imajı yerel olarak oluşturur ve projeyle servis isminden türetilen bir ad verir. Her ikisi de ayarlandığında, Compose yerel olarak oluşturma işlemini yapar ve sonucu image: içindeki isimle etiketler; bu yöntem, bir imajı oluşturup seçtiğiniz bir isimle göndermenizi sağlar.
Ayrım tamamen bundan ibarettir. Aşağıdaki tüm bilgiler, sunucu üzerindeki operasyonel süreçlerle ilgilidir. Bu açıklamalar, Docker Engine ve Compose eklentisinin halihazırda kurulu olduğunu varsayar; VPS üzerinde Docker çalıştırma bölümü bu konuyu ele almaktadır.
Üç formun tamamı
Yayınlanmış bir etiketi çekin ve çalıştırın. Bu süreçte hiçbir aşamada Dockerfile kullanılmaz.
services:
web:
image: nginx:1.27
restart: unless-stopped
ports:
- "80:80"Mevcut dizindeki bir Dockerfile dosyasından derleme yapın. FROM içinde belirtilen temel imaj dışında hiçbir şey çekilmez.
services:
web:
build: .
restart: unless-stopped
ports:
- "80:80"Yerel olarak derleyin ve sonucu etiketleyin. docker compose push, bu etiketi daha sonra bir kayıt defterine (registry) gönderebilir.
services:
web:
build:
context: .
dockerfile: Dockerfile
image: registry.example.com/acme/web:1.4.2
restart: unless-stopped
ports:
- "80:80"context, derleyiciye gönderilen dizindir. dockerfile, bu bağlama göre çözümlenir; bu nedenle dockerfile: docker/prod.Dockerfile ile context: . kullanımı normal ve doğrudur. Her servis container'ının arkasındaki imaj adını ve imaj ID'sini görmek için docker compose images komutunu çalıştırın; bu, yazdığınız üç formdan hangisini kullandığınızı doğrulamanın en hızlı yoludur.
Docker Compose up komutu Dockerfile dosyasını değiştirdikten sonra neden yeniden derleme yapmıyor?
Çünkü up, imajın güncel olup olmadığını değil, mevcut olup olmadığını kontrol eder.
Compose, build: bölümüne sahip bir servisi başlattığında, yerel imaj deposunda ilgili imajı arar. Eğer o isimde bir imaj zaten mevcutsa, Compose onu kullanır. Dockerfile dosyanızı okumaz, kaynak dosyalarınızı karşılaştırmaz veya herhangi bir zaman damgasına bakmaz. Compose spesifikasyonu bu kuralı pull_policy özniteliği olarak tanımlar ve varsayılan davranış, imaj yalnızca eksik olduğunda derleme yapmaktır. Mevcut olması yeterli kabul edilir.
Bu nedenle app.py dosyasını düzenleyip docker compose up -d komutunu çalıştırdığınızda, Compose konteynerin çalıştığını raporlar ancak eski kodu sunmaya devam eder. Hiçbir işlem başarısız olmadığı için herhangi bir uyarı da almazsınız. Bu, Compose ile ilgili en yaygın "yaptığım değişiklik etkili olmadı" raporudur. İpucu, Compose'un konteyner isminin yanında yazdırdığı durum kelimesidir: Compose tarafından değiştirilen bir konteyner "recreated" (yeniden oluşturuldu) veya "started" (başlatıldı) olarak raporlanırken, Compose'un dokunmamaya karar verdiği bir konteyner "running" (çalışıyor) olarak raporlanır.
İki kontrol bu durumu netleştirir. docker compose images her konteynerin kullandığı imaj kimliğini (ID) yazdırır; bu yüzden dağıtım öncesinde not alın ve sonrasında karşılaştırın. docker image ls komutunun bir CREATED sütunu vardır; son commit işleminizden önce oluşturulmuş bir imaj, dağıtım betiği ne yazdırırsa yazdırsın eski (stale) bir imajdır.
Hangi bayraklar yeniden derlemeyi zorunlu kılar
docker compose up -d --buildönce derleme yapar, ardından imajı değişen tüm container'ları yeniden oluşturur. Çoğu kullanıcının aradığı bayrak budur.docker compose build webtek bir servisi derler ve hiçbir şeyi başlatmaz. Sadece o container'ı değiştirmek ve yığının geri kalanını çalışır durumda bırakmak için ardındandocker compose up --no-deps -d webkomutunu kullanın.docker compose build --no-cache webtüm önbelleğe alınmış katmanları atar ve ilk talimattan itibaren yeniden derler.docker compose build --pullFROMiçindeki temel imajın daha yeni bir sürümünü çekmeye çalışır; böylecenode:22gibi değişken bir etiket, Mart ayında indirdiğiniz kopyayı değil, güncel içeriği alır.docker compose up -d --force-recreatecontainer'ları halihazırda kullandıkları imajdan yeniden oluşturur. Asla derleme yapmaz.--buildkullanmanız gereken yerde buna başvurmak yaygın bir çıkmazdır.
Kararı dosya içine de taşıyabilirsiniz. Compose spesifikasyonuna göre pull_policy: build, Compose'un imajı derlediği ve zaten mevcutsa yeniden derlediği anlamına gelir. Bu durumda her up bir derleme maliyeti doğurur; bu dizüstü bilgisayarlarda istediğiniz, ancak sunucularda nadiren tercih ettiğiniz bir durumdur.
services:
web:
build: .
image: registry.example.com/acme/web:dev
pull_policy: buildBir etkileşimi daha bilmekte fayda var. docker compose pull, build bölümüne sahip servisler için de imajları çekmeye çalışır; çekme işlemi başarısız olursa imajın derlenmesi gerektiğini bildirir. Bu servisleri sessizce atlamak için --ignore-buildable bayrağını kullanın.
Derleme önbelleğinin dağıtım süresini belirleme yöntemi
Dockerfile içindeki her komut bir katman oluşturur; derleyici, komut ve girdileri değişmediği sürece önbelleğe alınmış bir katmanı yeniden kullanır. COPY için girdiler, kopyalanan dosyaların içeriğidir. Bir katman önbelleği ıskaladığında, kendisinden sonra gelen tüm katmanlar yeniden oluşturulur; çünkü her katman, bir öncekinin ürettiği dosya sistemi üzerine inşa edilir.
Dağıtımınızın saniyeler mi yoksa dakikalar mı süreceğini belirleyen kural budur. Dockerfile dosyasını, nadiren değişenlerden her commit işleminde değişenlere doğru sıralayın.
FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]npm ci, COPY . . üzerinde yer alır; bu nedenle bir kaynak dosyasını düzenlemek, kurulum katmanının önbellekte kalmasını sağlar ve derleme kopyalama adımından devam eder. Bu iki satırın yerini değiştirirseniz, tek karakterlik bir değişiklik tüm bağımlılıkları yeniden kurar; çünkü COPY . ., npm ci komutunun üzerine inşa edildiği katmanı geçersiz kılar. Aynı mantık pip install -r requirements.txt ve go mod download için de geçerlidir.
Eski bir katmanın düzeltmenizi gizlediğinden şüphelendiğinizde --no-cache doğru araçtır. Ancak bu kötü bir varsayılan tercihtir; çünkü Dockerfile sıralamasının kazandırdığı yeniden kullanım avantajını tamamen ortadan kaldırır.
İmajın belirlediği ve Compose ile geçersiz kılınabilen bir nokta vardır: Dockerfile içindeki CMD, imajın varsayılan olarak çalıştırdığı komuttur ve servisteki bir command: anahtarı bunun yerini alır. Komut ve entrypoint etkileşimi burada önem kazanır; çünkü bir Compose geçersiz kılma işlemi, yeni derlenmiş bir imajın tıpkı eski imaj gibi davranmasına neden olabilir.
Derleme bağlamı ve .dockerignore
context: ., Compose'un o dizini paketleyip ilk komut çalışmadan önce derleyiciye göndermesi anlamına gelir. .git ve kaynak kodunuzun yanında tuttuğunuz tüm veri dizinleri dahil olmak üzere altındaki her şey gönderilir. Aksi takdirde değişmeyen bir projenin "transferring context" adımında duraklaması, bağlamın çok büyük olduğunu gösterir.
Bağlamın kök dizinindeki bir .dockerignore dosyası, belirtilen yolları bu transferin dışında tutar. Sözdizimi .gitignore ile benzerdir.
.git
node_modules
*.log
data/
.envBunun iki faydası vardır. Transfer küçülür, böylece her derleme daha hızlı başlar. Ayrıca COPY . ., .env dosyasını imajın içine kopyalayamaz; aksi takdirde imajı çeken herkes bu dosyayı okuyabilirdi.
Zamanla yavaşlayan derleme süreçlerinin temel nedeni bind mount kullanımıdır. Adlandırılmış bir volume proje dizininizin dışında yaşar, ancak ./data:/var/lib/postgresql/data gibi bir bind mount derleme bağlamının içinde yer alır; bu nedenle veritabanı büyüdükçe derlemeleriniz her hafta daha da yavaşlar. .dockerignore içindeki tek bir satır bunu düzeltir. Adlandırılmış volume'lere karşı bind mount kullanımı konusu, bu iki yöntem arasındaki farkları daha geniş kapsamda ele alır.
Derleme argümanları (build arguments) aynı riskin daha küçük bir versiyonunu taşır. args: üzerinden aktarılan değerler, imaja sahip olan herkes tarafından imaj geçmişinde görülebilir; bu nedenle oraya yalnızca sürüm numarası gibi veriler yazın, asla bir token eklemeyin. Compose'da env dosyaları ve gizli veriler konusu, kimlik bilgilerinin nerede tutulması gerektiğini açıklar.
Derleme işlemini VPS üzerinde mi yapmalı yoksa başka bir yerde yapıp çekmeli mi?
Trafiğinizi karşılayan sunucu üzerinde derleme yapmak, en kısa yol olduğu için varsayılan yöntemdir: git pull, ardından docker compose up -d --build. Henüz kimsenin bağımlı olmadığı küçük bir sunucuda bu yöntem sorun yaratmaz. Ancak ölçebileceğiniz iki neden ve sadece kötü bir günde ortaya çıkan bir neden yüzünden bu yöntem sürdürülebilirliğini yitirir.
Bellek. Bir derleme işlemi, canlı uygulamanızın yanında derleyicileri ve paketleyicileri çalıştırır; bunlar çoğu yığının en çok bellek tüketen parçalarıdır. 1 GB RAM'e sahip bir VPS üzerinde bir JavaScript paketleyicisi veya Rust derlemesi, genellikle sunucudaki en büyük süreçtir. Çekirdek belleği tükendiğinde en büyük süreci sonlandırır: Ya derleme Killed hatası ve 137 çıkış koduyla durur ya da veritabanınız sonlandırılır ve dağıtım sırasında siteniz erişilemez hale gelir. dmesg -T | grep -i oom, süreç adıyla birlikte sonlandırma satırını yazdırır; böylece tahmin yürütmek yerine hangisinin gerçekleştiğini anlayabilirsiniz.
Disk. Her derleme geride katmanlar bırakır ve derleyici, kendi önbelleğini imajlarınızdan ayrı tutar. docker system df her ikisini de gösterir ve derleme önbelleği satırı sürekli büyür. Kullanılmayan imajlar için docker image prune, önbelleğe alınmış katmanlar için docker builder prune komutuyla disk alanını geri kazanın. Tamamen dolan bir disk, sadece derlemeyi durdurmakla kalmaz. Veritabanı da yazma işlemini durdurur ve bu hata, yavaş bir dağıtımdan çok daha maliyetlidir.
Tekrarlanabilirlik. Sunucu üzerinde oluşturulan bir imaj, yalnızca o sunucuda mevcuttur. Geri alma işlemi, eski commit'i kontrol edip yeniden derlemeyi gerektirir; ancak temel etiket (base tag) ve paket yansımaları değiştiği için bu derlemenin elinizdekiyle aynı sonucu vereceğinin garantisi yoktur. Başka bir yerde derleyip bir etiketle göndermek, geri alma işlemini bir düzenlemeye dönüştürür: image: değerini önceki etikete yönlendirin ve docker compose up -d komutunu çalıştırın.
Sürdürülebilir olan yapı nettir. Sürekli entegrasyon (CI) süreciniz derlemeyi yapar ve registry.example.com/acme/web:<git-sha> değerini gönderir; VPS üzerindeki Compose dosyası ise image: değerini taşır ve hiçbir build: anahtarı içermez. Dağıtım, neredeyse hiç bellek gerektirmeyen iki komuttan ibaret hale gelir.
docker compose pull
docker compose up -dSunucuda docker login registry.example.com komutunu bir kez çalıştırın; Compose bundan sonra özel etiketleri çekebilir.
Derleme bölümünü silmek yerine geliştirme aşaması için saklayın ve bunu kendi adlandırdığınız bir dosyada tutun.
# compose.dev.yaml
services:
web:
build:
context: .
pull_policy: builddocker compose -f compose.yaml -f compose.dev.yaml up -d --buildBu dosyayı compose.override.yaml değil, compose.dev.yaml olarak adlandırın. Compose, mevcut olduğunda bir geçersiz kılma (override) dosyasını otomatik olarak yükler; bu nedenle sunucuya kopyalanan başıboş bir geçersiz kılma dosyası, derlemenin sessizce orada tekrar başlamasına neden olabilir. Birden fazla Compose dosyasını katmanlama bölümü, birleştirme işleminin her anahtarı nasıl çözümlediğini açıklar.
Başka bir yerde derleme yaparken mimari tuzağı
Bir imaj, derlendiği CPU mimarisini taşır. Apple Silicon dizüstü bilgisayarda derleme yapıp imajı gönderdikten sonra, bu etiketi bir x86_64 VPS üzerinde çekerseniz, Docker talep edilen imaj platformunun algılanan ana makine platformuyla eşleşmediği konusunda uyarı verir. İşlem daha sonra exec format error hatasıyla sonlanır; bu hata bozuk bir ikili dosya gibi görünse de aslında öyle değildir. Derlemeyi hedef platform için açıkça belirtin:
docker buildx build --platform linux/amd64 \
-t registry.example.com/acme/web:1.4.2 --push .Aynı uyumsuzluk, dizüstü bilgisayarınız x86 ise ve x86 yerine bir ARM VPS çalıştırıyorsanız tersi yönde de gerçekleşir. CI sürecinin, dağıtım yaptığınız mimari üzerinde derleme yapmasına izin vermek bu sorunu ortadan kaldırır.
Dağıtım sonrası kontrol edilecekler
docker compose images, çalışan her container'ın arkasındaki imajı ve etiketi yazdırır. Değişen bir imaj ID'si, yeni derlemenin devrede olduğunun kanıtıdır.docker compose config, değişken değişiminden sonra birleştirilmiş dosyayı yazdırır; böylece herhangi bir işlem yapmadan önce Compose'un kullanacağı nihai imaj adını okuyabilirsiniz.docker compose logs -f web, geçişten sonraki ilk yarım dakika için kullanılır. Başlayıp hemen kapanan bir container, çalışır durumda kalmak yerine döngüsel olarak yeniden başlatılır; siz bakmadığınız sürece bu döngü sessiz kalır.docker image ls, CREATED sütununu gösterir. Son commit işleminizden daha eski bir imaj hiçbir zaman yeniden derlenmemiştir.
Bu kontrollerin karşılaştırıldığı dosyayı henüz oluşturuyorsanız, VPS üzerinde Compose dosyası temelleri bölümü ilgili anahtarları, Compose komutları kopya kağıdı ise alt komutların geri kalanını listeler.
FAQ
Aynı serviste hem build hem de image kullanabilir miyim?
Evet, bu kendi geliştirdiğiniz bir proje için standart yapılandırmadır. Compose, build: bölümündeki talimatlarla derleme yapar ve sonucu image: değerindeki etiketle isimlendirir. docker compose push komutu, bir kayıt defterine gönderirken ve başka bir makine çekerken bu etiketi kullanır. image: anahtarı olmadan Compose yine derleme yapar, ancak imajı proje ve servis adına göre isimlendirir ve eksik özniteliğin imajın gönderilmesini engelleyeceği konusunda uyarı verir.
Neden docker compose up komutu Dockerfile değişikliklerimi algılamıyor?
Çünkü up yalnızca o isimde bir imajın mevcut olup olmadığını kontrol eder. Bir imaj mevcut olduğunda, Compose onu başlatır ve Dockerfile veya kaynak dosyalarınızla karşılaştırma yapmaz. docker compose up -d --build komutunu çalıştırın veya tek bir servisi değiştirmek için docker compose build web komutunu takiben docker compose up --no-deps -d web komutunu kullanın. Servis üzerinde pull_policy: build ayarını yapmak, her up komutunun yeniden derleme yapmasını sağlar; bu, geliştirme ortamları için uygundur.
--build ve --force-recreate arasındaki fark nedir?
--build imajı yeniden derler ve ardından imajı değişen container'ları yeniden oluşturur. --force-recreate ise container'ları mevcut imajlarından yeniden oluşturur, bu nedenle kod değişikliklerini asla algılayamaz. Değişikliğiniz kaynak kodda veya Dockerfile içindeyse, kullanmanız gereken bayrak --build'tür. --force-recreate, container'ın kendisini sıfırlamak içindir; örneğin, aynı imajı korurken yazılabilir katmanını temizlemek için kullanılır.
Docker imajlarımı VPS üzerinde mi yoksa başka bir yerde mi derlemeliyim?
Başka bir yerde derleyip imajı çekmek, sunucu trafik sunmaya başladığında daha sağlıklıdır. Derleme işlemi, bellek kullanımı konusunda uygulamanızla rekabet eder; küçük bir VPS'te bu rekabet, çekirdeğin en büyük süreci (bu bir derleme süreci veya veritabanınız olabilir) sonlandırmasına yol açabilir. Derlemeler ayrıca diskte otomatik olarak temizlenmeyen önbellek dosyaları bırakır. Kullanıcısı olmayan küçük projeler için sunucuda derleme yapmak sorun yaratmaz; ileride geçiş yapmak isterseniz build: bölümünü yalnızca geliştirme ortamına özel bir Compose dosyasında tutmanız yeterlidir.
Docker derleme önbelleğinin diskimi doldurmasını nasıl engellerim?
İmajlarınızın ve derleme önbelleğinizin ne kadar yer kapladığını görmek için docker system df komutunu çalıştırın. docker builder prune önbelleğe alınmış katmanları, docker image prune ise önceki derlemelerden kalan sahipsiz imajları kaldırır. Her ikisine de -a eklemek daha agresif bir temizlik sağlar ve bir sonraki derlemenizin sıfırdan başlamasına neden olur. Sunucuda docker system prune -af --volumes komutunu zamanlanmış görev olarak çalıştırmayın; çünkü --volumes, hiçbir container tarafından kullanılmayan tüm volume'ları siler. Bakım için durdurduğunuz bir stack, veritabanını tam olarak böyle bir volume içinde tutuyor olabilir.