docker build . yazdığında terminalde saniyelerce transferring context: 412.83MB satırını izliyorsan, projende .dockerignore dosyası ya yok ya da yanlış yazılmış demektir. Docker derlemeye başlamadan önce bulunduğun dizindeki her şeyi paketleyip derleyici tarafına gönderir: node_modules, .git geçmişi, vendor klasörü, yerel veritabanı dökümleri, .env dosyan ve o unuttuğun 300 MB'lık log arşivi dahil. Bu dosyaların çoğu imaja hiç girmeyecek olsa bile transfer maliyetini her derlemede ödersin.
.dockerignore dosyası bu transferi filtreleyen tek mekanizmadır ve etkisi üç yönlüdür: derleme belirgin biçimde hızlanır, katman önbelleği çok daha isabetli çalışır ve en önemlisi, hassas dosyaların yanlışlıkla imaja kopyalanma riski ortadan kalkar. Bu rehberde build context kavramını, .dockerignore söz dizimini, dile göre hazır örnekleri, güvenlik boyutunu ve "yazdım ama işe yaramadı" durumunun sebeplerini tek tek ele alacağım. Dockerfile disiplinini genel olarak gözden geçirmek istersen Dockerfile en iyi pratikler yazısı bunun tamamlayıcısı.
Build Context Tam Olarak Nedir#
docker build -t firmaniz/api:1.0 . komutundaki son nokta, çoğu kişinin sandığı gibi "burada çalıştır" demek değildir; derleme bağlamının (build context) kök dizinini belirtir. Docker istemcisi bu dizinin içeriğini bir arşive koyar ve derleme motoruna gönderir. Motor bu arşivin dışındaki hiçbir dosyaya erişemez — COPY ../gizli/dosya yazamamanın sebebi budur.
Bağlamın büyüklüğü doğrudan zaman demektir. Tipik bir Node.js projesinde:
| İçerik | Tipik boyut | İmaja gerekli mi |
|---|---|---|
Kaynak kod (src/) | 2-15 MB | Evet |
node_modules/ | 150-600 MB | Hayır (imajda yeniden kurulur) |
.git/ | 20-500 MB | Genelde hayır |
dist/, build/ | 5-80 MB | Genelde hayır (imajda üretilir) |
| Yerel dökümler, loglar | Değişken | Kesinlikle hayır |
Yani gerçekte 10 MB'lık koda ihtiyacın varken 400 MB gönderiyor olabilirsin. Uzak bir derleme sunucusu ya da CI koşucusu kullanıyorsan bu transfer ağ üzerinden yapılır ve her derlemeye onlarca saniye ekler.
Kendi projenin bağlam boyutunu ölçmek için:
# Dizinin ham boyutu (dockerignore uygulanmadan önce)
du -sh .
# 431M .
# En büyük ilk on klasör
du -sh ./* .[!.]* 2>/dev/null | sort -rh | head -n 10
# 287M ./node_modules
# 96M ./.git
# 31M ./dist
BuildKit ile derlerken ekrandaki [internal] load build context adımının yanında transfer edilen gerçek boyutu görürsün; .dockerignore eklemeden önce ve sonra bu sayıyı karşılaştırmak, yaptığın işin etkisini ölçmenin en net yoludur.
Söz Dizimi ve Eşleşme Kuralları#
.dockerignore dosyası, derleme bağlamının kök dizininde durur — yani docker build komutuna verdiğin yolun içinde. Söz dizimi .gitignore'a benzer ama birebir aynı değildir; eşleşme Go dilinin dosya yolu kalıplarına dayanır.
| Kalıp | Anlamı | Örnek eşleşme |
|---|---|---|
node_modules | Bu adı taşıyan dosya/klasör (kökte) | node_modules/ |
*.log | Kökteki tüm .log dosyaları | hata.log |
**/*.log | Her seviyedeki .log dosyaları | src/app/hata.log |
temp? | Tek karakterlik joker | temp1, tempA |
*/gecici* | Bir alt seviyedeki eşleşmeler | src/gecici-veri |
!README.md | İstisna (önceki kuraldan muaf tut) | README.md dahil edilir |
# yorum | Yorum satırı | — |
Bilmen gereken en önemli iki kural şunlar. Birincisi, son eşleşen satır kazanır; yani ! ile yaptığın istisnayı, onu kapsayan geniş kuraldan sonra yazmalısın. !README.md satırını *.md satırının üstüne koyarsan hiçbir etkisi olmaz. İkincisi, kalıplar bağlam köküne göre değerlendirilir; başa / koyman gerekmez ama koyarsan da davranış değişmez.
Basit ama işe yarayan bir örnek:
# Tüm markdown dosyalarını dışla...
*.md
# ...ama README'yi bağlama dahil et
!README.md
# Her seviyedeki log ve geçici dosyalar
**/*.log
**/*.tmp
# Bağımlılık klasörleri
node_modules
vendor
.venv
Sıralamayı test etmeden varsayma; büyük bir projede tek bir yanlış sıralanmış ! satırı, dışlamak istediğin 200 MB'lık klasörü sessizce geri getirebilir.
Dile Göre Hazır Başlangıç Dosyaları#
Aşağıdaki örnekler üretimde kullandığım şablonların sadeleştirilmiş hâlleri. Kendi projene uyarlarken "bu dosya imajın çalışması için gerekli mi?" sorusunu her satır için sor.
Node.js / TypeScript:
# Bağımlılıklar imajın içinde npm ci ile yeniden kurulur
node_modules
npm-debug.log*
yarn-error.log*
# Derleme çıktısı imajda üretilir
dist
build
coverage
# Sürüm kontrolü ve editör
.git
.gitignore
.vscode
.idea
# Ortam ve sırlar
.env
.env.*
*.pem
*.key
# Konteyner ve CI dosyaları
Dockerfile*
docker-compose*.yml
.dockerignore
.github
PHP / Laravel:
vendor
node_modules
storage/logs/*
storage/framework/cache/*
bootstrap/cache/*
.env
.env.*
.git
tests
phpunit.xml
*.sql
*.sql.gz
Python:
__pycache__
**/__pycache__
*.py[cod]
.venv
venv
.pytest_cache
.mypy_cache
.git
.env
*.sqlite3
Node örneğinde node_modules satırı yalnızca hız için değil, doğruluk için de gereklidir. Yerel makinende kurulmuş bağımlılıklar senin işletim sistemine göre derlenmiştir; bunlar imaja kopyalanırsa Linux tabanlı konteynerde invalid ELF header gibi hatalar alırsın. Doğru yol, imajın içinde npm ci çalıştırıp bağımlılıkları hedef platforma göre kurmaktır.
Güvenlik Boyutu: İmaja Sızan Sırlar#
.dockerignore yalnızca bir performans aracı değildir; en değerli işlevi belki de güvenliktir. COPY . . satırı yazan bir Dockerfile, bağlamda ne varsa imaja kopyalar. Bu şu demek: .env dosyan, id_rsa özel anahtarın, .git klasöründeki tüm geçmiş ve o geçmişte bir kez commit edilip sonra silinmiş parolalar imajın içine girer.
Kritik nokta şudur: bir dosyayı sonraki bir katmanda RUN rm ile silmen onu imajdan silmez. Katmanlar yığındır; dosya alt katmanda durmaya devam eder ve imajı indiren herkes onu çıkarabilir. Bunu kendi imajında sınamak için:
# İmajın katmanlarını dışa aktar ve .env ara
docker save firmaniz/api:1.0 -o /tmp/imaj.tar
mkdir -p /tmp/imaj && tar -xf /tmp/imaj.tar -C /tmp/imaj
find /tmp/imaj -name '*.tar' -exec tar -tf {} \; 2>/dev/null | grep -E '\.env|id_rsa|\.git/' | head
Çıktıda bir şey görüyorsan imajın sır taşıyor demektir; o imajı yayınladıysan yapılacak ilk iş sırları döndürmektir (rotate). .git klasörünün ifşasının neye mal olduğunu görmek istersen .git klasörü ve .env dosyası ifşası yazısı iyi bir uyarı niteliğinde.
En sağlam yaklaşım katmanlıdır: .dockerignore ile sırların bağlama hiç girmemesini sağla, Dockerfile'da COPY . . yerine ihtiyacın olan yolları açıkça kopyala, derleme sırasında gerçekten bir sır gerekiyorsa BuildKit'in --mount=type=secret mekanizmasını kullan. Son adımda imajı Trivy ile tarayarak --scanners secret kontrolünü otomatikleştirebilirsin.
Katman Önbelleğiyle İlişkisi#
.dockerignore dosyasının en az bilinen faydası, önbellek isabet oranını artırmasıdır. Docker bir COPY adımının önbelleğini, kopyalanan dosyaların içeriğinden hesapladığı bir özet ile karşılaştırır. Bağlamda node_modules varsa, orada değişen tek bir dosya bile COPY . . adımının önbelleğini geçersiz kılar ve sonraki tüm katmanlar yeniden çalışır.
Aynı şekilde, .git klasörü bağlamdaysa her git işlemi (bir fetch bile) bağlamı değiştirmiş sayılır. Sonuç şudur: hiçbir kaynak dosyaya dokunmadığın hâlde derleme tam sürede tekrar koşar. Bu ikisini dışladığın anda önbellek isabet oranın belirgin biçimde yükselir. Önbelleğin nasıl çalıştığını ve COPY sırasını nasıl optimize edeceğini BuildKit ve katman önbelleği yazısında ayrıntılı anlattım.
Küçük bir ayrıntı: BuildKit, Dockerfile'a özel bir ignore dosyasını da destekler. Dockerfile.prod için Dockerfile.prod.dockerignore dosyası oluşturursan, o Dockerfile ile derleme yaparken bu dosya kullanılır. Aynı depoda birden fazla imaj üreten projelerde çok işe yarar.
Doğrulama: Bağlamda Gerçekten Ne Var#
"Yazdım ama işe yaramadı" durumunun sebebini bulmanın en hızlı yolu, bağlamı gerçekten listelemektir. Bunun için minicik bir yardımcı imaj kurabilirsin:
# Geçici bir Dockerfile ile bağlamın içeriğini listele
cat > Dockerfile.context << 'DOCKERFILE'
FROM busybox
COPY . /ctx
RUN du -sh /ctx && find /ctx -maxdepth 2 | head -n 40
DOCKERFILE
DOCKER_BUILDKIT=0 docker build -f Dockerfile.context --no-cache -t ctx-test .
rm Dockerfile.context
Çıktıda node_modules ya da .git görüyorsan filtren tutmuyor demektir. En sık üç sebebi var:
.dockerignoredosyası bağlam kökünde değil. Örneğindocker build -f docker/Dockerfile ..ile üst dizini bağlam yaptıysan, ignore dosyası da o üst dizinde olmalıdır.- Dosya adı yanlış yazılmış:
dockerignore,.dockerIgnoreya da.dockerignore.txtişe yaramaz. Adı tam olarak.dockerignoreolmalıdır. - Compose kullanıyorsan
build.contextalanında belirttiğin dizin farklı olabilir; ignore dosyası oraya konur. Compose yapısını gözden geçirmek istersen Docker Compose kullanımı yazısına bakabilirsin.
Sık Yapılan Hatalar ve Tuzaklar#
.gitignoredosyasını olduğu gibi kopyalamak. İkisinin amacı farklıdır..gitignoreiçinde olmayan ama bağlamda duran.gitklasörünün kendisi,.dockerignoretarafında mutlaka dışlanmalıdır. Tersine, sürüm kontrolüne girmeyen ama derleme için gereken bazı dosyalar.gitignore'da yer alır.*yazıp sonra istisna eklemeye çalışmak.*ile her şeyi dışlayıp!srcile geri almak, kalıp sırası doğru olmadığında beklenmedik sonuçlar üretir. Beyaz liste yaklaşımını gerçekten istiyorsan davranışı yukarıdaki listeleme yöntemiyle doğrula..gitdışlarken sürüm bilgisini kaybetmek. Bazı derlemeler sürüm numarasınıgit describeile üretir..gitdışlandığında bu komut çalışmaz. Çözüm, sürümü CI tarafında hesaplayıp--build-arg VERSION=...ile geçirmektir.- Test dosyalarını körlemesine dışlamak. İmajı derlerken testleri de çalıştırıyorsan (
RUN npm test),testsklasörünü dışlarsan derleme kırılır. Çok aşamalı derlemede testleri ilk aşamada çalıştırıp son imaja almamak daha temiz bir çözümdür. - Büyük ikili varlıkları dışlamayı unutmak. Tasarım dosyaları, örnek videolar, örnek veri setleri genelde depoda durur ve imaja hiç girmez ama bağlamda taşınır.
**/*.psd,**/*.mp4gibi satırlar tek başına yüzlerce megabayt kazandırır. - Dosyayı bir kez yazıp bir daha bakmamak. Proje büyüdükçe yeni klasörler eklenir. Ayda bir
du -sh ./*çalıştırıp bağlamda ne biriktiğine bakmak beş dakikalık bir alışkanlıktır.
Sıkça Sorulan Sorular#
.dockerignore dosyası nereye konur#
Derleme bağlamının kök dizinine, yani docker build komutuna verdiğin yolun içine konur. docker build . çalıştırıyorsan proje kökünde olmalıdır. Dockerfile'ın bulunduğu yer önemli değildir; belirleyici olan bağlam dizinidir. Compose kullanıyorsan servisin build.context alanında yazan dizini esas al.
.dockerignore ile .gitignore aynı şey mi#
Hayır. .gitignore hangi dosyaların sürüm kontrolüne girmeyeceğini, .dockerignore ise hangi dosyaların derleme bağlamına gönderilmeyeceğini belirler. İçerikleri büyük ölçüde örtüşse de kritik farklar vardır: .git klasörünün kendisi .dockerignore içinde dışlanmalıdır ve söz dizimi kuralları birebir aynı değildir.
.dockerignore derlemeyi ne kadar hızlandırır#
Kazanç doğrudan dışladığın veri miktarına bağlıdır. 400 MB'lık bir bağlamı 10 MB'a indirmek, yerel derlemede birkaç saniye, uzak bir derleme sunucusunda ya da CI koşucusunda çoğu zaman onlarca saniye kazandırır. Asıl kazanç ise dolaylıdır: node_modules ve .git bağlamdan çıkınca katman önbelleği çok daha sık isabet eder ve tekrarlanan derlemeler dramatik biçimde kısalır.
Dockerfile'ı .dockerignore içine yazabilir miyim#
Yazabilirsin ve genelde yazılır. Derleme motoru Dockerfile'ı ayrı bir yoldan okuduğu için bu dosyayı dışlamak derlemeyi bozmaz; sadece COPY . . ile imajın içine kopyalanmasını engeller. Aynısı .dockerignore, docker-compose.yml ve CI yapılandırma dosyaları için de geçerlidir.
node_modules klasörünü dışlarsam uygulamam çalışır mı#
Evet, çünkü bağımlılıkları imajın içinde yeniden kurarsın. Dockerfile'da önce package.json ve package-lock.json dosyalarını kopyalayıp npm ci çalıştırır, sonra kaynak kodu kopyalarsın. Bu yöntem hem doğru platformda derlenmiş bağımlılıklar verir hem de kod her değiştiğinde bağımlılıkların yeniden kurulmasını engeller.
Dışladığım bir dosyayı derleme sırasında yine de kullanabilir miyim#
Bağlam dışındaki bir dosyaya COPY ile erişemezsin. Derleme sırasında gereken değerleri --build-arg ile parametre olarak geçirebilir, gizli bilgiler içinse BuildKit'in gizli bağlama mekanizmasını kullanabilirsin; bu yöntemde dosya yalnızca ilgili RUN adımı sırasında görünür ve hiçbir katmana yazılmaz. Böylece hem sır imaja girmez hem de derleme çalışır.
Kapanış#
.dockerignore, tek bir metin dosyasıyla üç ayrı problemi birden çözen ender araçlardan biri: derleme süresi, önbellek isabeti ve sır sızıntısı. Aklında kalması gereken dört alışkanlık şunlar: her yeni projede daha ilk gün bir .dockerignore oluştur, .git ve bağımlılık klasörlerini mutlaka dışla, ! istisnalarını geniş kuralların altına yaz ve ayda bir bağlam boyutunu ölçüp neyin biriktiğine bak. Sırların imaja girmediğini varsaymak yerine, imajı bir kez açıp gözünle doğrula.
Konteyner altyapını kurarken bu tür ayrıntılarla tek başına boğuşmak istemiyorsan Clou.TR tarafında hazır bir zemin var. Kendi derleme ve dağıtım hattını kurmak için tam root erişimli VDS ve bulut sunucu paketlerimizi inceleyebilir, kurulum ve bakımı bize bırakmak istersen sunucu yönetimi hizmetimize göz atabilir, kod ve veri kopyalarını güvence altına almak için yedekleme çözümümüzü değerlendirebilirsin.