Build Context ve .dockerignore
Önceki derste Dockerfile talimatlarını öğrendik — FROM, RUN, COPY, CMD ve diğerleri. Şimdi çok önemli ama sıklıkla gözden kaçan bir konuya geleceğiz: build context. Bu kavramı doğru anlamazsan build'lerin yavaşlar, image'ların gereksiz yere şişer ve hatta gizli bilgilerin (şifreler, API anahtarları) image'a sızabilir.
Taşındığını düşün. Nakliyeci geldi ve "ne götürelim?" diye soruyor. Sen de evdeki her şeyi kamyona yüklüyorsun — çöp poşetleri, eski gazeteler, kırık tabure, geçen yılın vergi beyannameleri dahil. Sonra yeni evde yarısını çöpe atıyorsun. Hem zaman kaybettin, hem kamyon parası fazla çıktı, hem de hassas belgelerini nakliyeciye göstermiş oldun.
.dockerignore olmadan Docker build tam olarak bunu yapıyor. Build context olarak dizindeki her şeyi Docker daemon'a gönderiyor. Bu derste build context'in nasıl çalıştığını, .dockerignore ile nasıl optimize edileceğini ve bu konudaki en iyi pratikleri öğreneceğiz.
Build Context Nedir?
docker build komutunu çalıştırdığında, belirttiğin dizindeki tüm dosyalar Docker daemon'a tar arşivi olarak gönderilir. Bu dizine "build context" denir:
docker build -t myapp .
# ^
# Bu nokta (.) = build context = mevcut dizinPeki neden doğrudan dosya sistemininden okumuyor da daemon'a gönderiyor? Çünkü Docker'ın mimarisi client-server yapısında. Docker CLI (client) ve Docker Daemon (server) ayrı prosesler. Hatta farklı makinelerde bile olabilirler. CLI, daemon'a "bu dosyaları al ve image build et" diyor.
Build başladığında gördüğün ilk satır:
Sending build context to Docker daemon 245.7MB245MB? Bir web uygulaması için bu çok fazla! Muhtemelen node_modules, .git ve diğer gereksiz dosyalar dahil. Hadi bunu inceleyelim.
Build Context Boyutunu Ölçmek
Mevcut dizindeki hangi dosya/dizinlerin ne kadar yer kapladığını görelim:
du -sh */ .* 2>/dev/null | sort -rh | head -10
# 180M node_modules/
# 45M .git/
# 12M coverage/
# 5M dist/
# 2M src/
# 1M public/
# 500K .next/
# 200K docs/Gördün mü? 245MB'ın 180MB'ı node_modules (ki container'da zaten yeniden yüklenecek), 45MB'ı .git (ki container'da hiç işe yaramaz). Gerçekte sadece src/, public/, package.json gibi dosyalar lazım — toplamı belki 5MB.
Build Context Kaynakları
En yaygın kullanım yerel dizin olsa da, build context farklı kaynaklardan da gelebilir:
# Mevcut dizin (en yaygın)
docker build .
# Farklı dizin
docker build /path/to/project
# Git repository'den doğrudan
docker build https://github.com/user/repo.git
docker build https://github.com/user/repo.git#branch
# Stdin'den Dockerfile (context yok)
echo 'FROM alpine
RUN echo "hello"' | docker build -t minimal -
# COPY/ADD çalışmaz çünkü context yok.dockerignore Dosyası — Build Context Filtresi
.dockerignore, build context'ten hariç tutulacak dosyaları belirtiyor. Proje kök dizinine yerleştirirsin ve sözdizimi .gitignore'a çok benzer.
Temel Sözdizimi
# Yorum satırları
# Belirli dosya
README.md
LICENSE
# Belirli dizin
node_modules
.git
coverage
# Wildcard
*.log
*.md
*.swp
# Recursive wildcard
**/*.test.js
**/*.spec.js
**/test/
# Negation (istisna — hariç tutmadan çıkar)
*.md
!README.md
# Tüm .md dosyaları hariç tut, AMA README.md'yi dahil etKapsamlı Node.js .dockerignore
# .dockerignore — Node.js Projesi
# Dependencies (container'da yeniden yüklenecek)
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnp
.pnp.js
.yarn/cache
# Testing
coverage
.nyc_output
**/*.test.js
**/*.spec.js
**/__tests__
**/__mocks__
jest.config.*
cypress/
# Build tools & IDE
.git
.gitignore
.vscode
.idea
*.sublime-*
.editorconfig
.eslintrc*
.prettierrc*
tsconfig.json
# Docker (kendi dosyaları — recursive kopya önleme)
Dockerfile*
docker-compose*
.dockerignore
# Documentation
*.md
docs/
!README.md
# Environment (GİZLİ BİLGİLER!)
.env
.env.*
!.env.example
# OS files
.DS_Store
Thumbs.db
*.swp
*.swo
*~
# Misc
tmp/
temp/
logs/
*.logKapsamlı Python .dockerignore
# .dockerignore — Python Projesi
# Python
__pycache__
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
.venv/
*.egg-info/
dist/
build/
# Testing
.tox/
.coverage
htmlcov/
.pytest_cache/
tests/
**/*_test.py
**/test_*.py
# IDE & Tools
.git
.gitignore
.vscode
.idea
.mypy_cache/
.ruff_cache/
# Docker
Dockerfile*
docker-compose*
.dockerignore
# Docs & Misc
*.md
docs/
.env
.env.*
*.log
tmp/
.DS_Store.dockerignore'un Etkisini Görmek
Şimdi farkı somut olarak görelim:
# ÖNCE — .dockerignore yok
docker build -t myapp .
# Sending build context to Docker daemon 245.7MB
# Build time: 45 seconds
# SONRA — .dockerignore eklendi
docker build -t myapp .
# Sending build context to Docker daemon 4.2MB
# Build time: 12 seconds%98 küçülme! Build context 245MB'dan 4MB'a düştü. Build süresi neredeyse 4 kat hızlandı. Ve daha önemlisi, gereksiz dosyalar image'a girmedi.
Build context boyutunu test etmek istersen, build yapmadan sadece boyutu görebilirsin:
# Geçici bir Dockerfile ile sadece context boyutunu gör
echo 'FROM scratch' > /tmp/Dockerfile.test
docker build -f /tmp/Dockerfile.test .
# Sending build context to Docker daemon 4.2MB
# Build başarısız olur (scratch'tan bir şey yapamaz) ama boyutu görürsün
rm /tmp/Dockerfile.testCOPY Sıralaması ve Cache Optimizasyonu
Build context'i küçültmek önemli ama bir o kadar da önemli olan şey COPY sıralaması. Docker her COPY talimatında dosyaların hash'ini kontrol eder. Hash değiştiyse o katman ve sonraki tüm katmanlar yeniden build edilir.
Sorun: Her Değişiklikte Tüm Cache Kırılıyor
# ❌ YANLIŞ SIRA
COPY . /app/ # Herhangi BİR dosya değişince bu katman kırılır
RUN npm install # Ve bu da TEKRAR çalışır (5-10 dakika!)server.js'te bir satır değiştirdin. COPY . /app/ hash'i değişti. Dolayısıyla npm install de tekrar çalışıyor — 5 dakika bekliyorsun. Sadece bir satır için!
Çözüm: Bağımlılıkları Koddan Önce Kopyala
# ✅ DOĞRU SIRA
COPY package.json package-lock.json /app/ # Sadece package dosyaları
RUN npm install # Bağımlılıkları yükle
COPY . /app/ # Sonra kodu kopyalaŞimdi server.js değiştiğinde ne oluyor? package.json değişmediği için ilk COPY cache'ten gelir. npm install de cache'ten gelir. Sadece COPY . /app/ yeniden çalışır — milisaniyeler.
Bunu gözlemleyelim:
# İlk build — her şey sıfırdan
docker build -t myapp:v1 .
# Step 3/6 : COPY package.json package-lock.json ./
# ---> abc123 (cache MISS)
# Step 4/6 : RUN npm install
# ---> def456 (cache MISS — 30 saniye bekliyorsun)
# Step 5/6 : COPY . .
# ---> ghi789 (cache MISS)
# server.js'te bir değişiklik yap ve tekrar build et
docker build -t myapp:v2 .
# Step 3/6 : COPY package.json package-lock.json ./
# ---> Using cache abc123 ← Cache HIT!
# Step 4/6 : RUN npm install
# ---> Using cache def456 ← Cache HIT! npm install ATLANDI!
# Step 5/6 : COPY . .
# ---> xyz999 (cache MISS — sadece bu çalışıyor)30 saniyelik npm install atlandı — build 2 saniyede bitti! Bu optimizasyon, özellikle CI/CD pipeline'larında, günde onlarca build yapıldığında muazzam zaman tasarrufu sağlar.
Cache kuralı: Bir katman değiştiğinde, ondan sonraki tüm katmanlar da yeniden çalıştırılır. Bu yüzden seyrek değişenleri (bağımlılıklar) üste, sık değişenleri (kod) alta koy.
İleri Teknikler
Whitelist Yaklaşımı — En Güvenli Strateji
Varsayılan olarak her şeyi hariç tut, sadece gerekenleri dahil et:
# .dockerignore — Whitelist yaklaşımı
*
!src/
!package.json
!package-lock.json
!tsconfig.json
!public/Bu yaklaşım ile yeni eklenen dosyalar (mesela bir .env.production) otomatik olarak hariç tutulur. Yanlışlıkla gizli bilgilerin image'a girmesi neredeyse imkansız hale gelir.
Build Context Dışından COPY Yapılamaz
Bunu bilmek önemli: Dockerfile sadece build context içindeki dosyalara erişebilir.
# ❌ Bu çalışmaz — /etc/hosts build context'te değil
COPY /etc/hosts /app/
# ✅ Build context'i üst dizin yapabilirsin
# docker build -f project/Dockerfile .Monorepo'da Build Context
Büyük projelerde birden fazla servis aynı repo'da olabilir:
monorepo/
├── packages/
│ ├── frontend/
│ │ └── Dockerfile
│ ├── backend/
│ │ └── Dockerfile
│ └── shared/
├── package.json
└── .dockerignore# Root'tan build et, farklı Dockerfile kullan
docker build -f packages/backend/Dockerfile -t backend:v1 .
docker build -f packages/frontend/Dockerfile -t frontend:v1 .Gizli Dosya Sızıntısı — Güvenlik Uyarısı
.dockerignore'un en önemli rollerinden biri güvenlik. Eğer .env dosyanız build context'te ise ve COPY . /app/ yapıyorsanız, gizli bilgileriniz image'a girer:
# ⚠️ TEHLİKE!
docker run --rm myapp cat /app/.env
# DB_PASSWORD=supersecret
# API_KEY=sk-live-abc123
# 😱 Image'ı push ettiysen, herkes görebilir!Çözüm:
# .dockerignore'a ekle
.env
.env.*
!.env.exampleVe image'ı yeniden build et (--no-cache ile eski katmanları temizle):
docker build --no-cache -t myapp .Yaygın Hatalar ve Çözümleri
Build Context Çok Büyük
docker build -t myapp .
# Sending build context to Docker daemon 2.1GBNeyin büyük olduğunu bul:
du -sh */ .* 2>/dev/null | sort -rh | head -10Ve .dockerignore'a ekle. Genellikle suçlu: node_modules, .git, data/ dizinleri.
COPY Dosya Bulamıyor
COPY failed: file not found in build context or excluded by .dockerignoreÜç olası neden: dosya gerçekten yok, dosya .dockerignore'da, veya build context yanlış dizini gösteriyor. Debug için geçici olarak .dockerignore'ı devre dışı bırak:
mv .dockerignore .dockerignore.bak
docker build -t myapp .
mv .dockerignore.bak .dockerignoreBu Derste Ne Öğrendik?
Build context,
docker build .komutundaki dizinin tamamı. Docker daemon'a tar olarak gönderilir — büyük olursa build yavaşlar..dockerignore ile gereksiz dosyaları hariç tut. Build hızı ve image boyutu dramatik düşer (%98 küçülme mümkün).
node_modules, .git, coverage, IDE dosyaları, .env her zaman hariç tutulmalı.
Whitelist yaklaşımı (
*+!) en güvenli strateji — yeni dosyalar otomatik hariç tutulur.COPY sıralaması cache'i doğrudan etkiler. Seyrek değişen dosyaları (bağımlılıklar) önce, sık değişenleri (kod) sonra kopyala.
.dockerignore olmadan gizli dosyalar (.env, key dosyaları) image'a sızabilir — bu ciddi bir güvenlik riski.
Bir sonraki derste ilk Dockerfile'ımızı sıfırdan yazacak, build edecek ve çalıştıracağız!
AI Asistan
Sorularını yanıtlamaya hazır