"Bende çalışıyor" cümlesini her ekip projesinde en az bir kez duyarsın. Senin bilgisayarında Java 21 var, arkadaşında 17. Sen PostgreSQL 16 kullanıyorsun, o hiç kurmamış. Uygulama sende açılıyor, onda açılmıyor. Docker bu sorunu çözüyor: uygulamayı, çalışması için gereken her şeyle birlikte bir paket hâline getiriyor ve o paket her yerde aynı şekilde çalışıyor.
Önce iki kavram: imaj ve konteyner
- İmaj (image): Uygulamanın, çalışma ortamının ve bağımlılıklarının donmuş bir kopyası. Bir tarif gibi düşünebilirsin.
Dockerfileadındaki bir dosyadan üretiliyor. - Konteyner (container): O imajdan başlatılmış, çalışan bir süreç. Aynı imajdan istediğin kadar konteyner başlatabilirsin.
Sanal makineye benziyor ama ondan çok daha hafif: konteyner ayrı bir işletim sistemi açmıyor, bilgisayarının çekirdeğini paylaşıyor. Bu yüzden saniyeler içinde açılıyor.
Kurulum
Windows ve macOS'ta Docker Desktop kurmak en kolay yol. Linux'ta Docker Engine'i dağıtımının paket yöneticisiyle kurabilirsin. Kurulumdan sonra terminalde şunu çalıştır:
docker run hello-worldEkranda bir karşılama mesajı görüyorsan Docker hazır.
İlk Dockerfile
Örnek olarak küçük bir Node.js API'si düşünelim. Proje klasörünün kökünde Dockerfile adında bir dosya oluştur:
FROM node:22-alpine
WORKDIR /app
# Önce yalnız bağımlılık dosyaları: kod değişince bu katman yeniden kurulmasın.
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]Satır satır:
FROM: Hangi hazır imajın üstüne kuracağını söylüyor. Burada içinde Node.js 22 olan küçük bir Linux imajı.WORKDIR: Konteynerin içinde çalışılacak klasör.COPYveRUN npm ci: Önce bağımlılık listesini kopyalayıp bağımlılıkları kuruyor, sonra kodun geri kalanını kopyalıyor. Bu sıra önemli. Docker her satırı bir katman olarak önbelleğe alıyor; kodun değişse bile bağımlılıklar değişmediyse kurulum yeniden yapılmıyor ve imaj saniyeler içinde yeniden üretiliyor.EXPOSE: Uygulamanın dinlediği portu belgeliyor.CMD: Konteyner açılınca çalışacak komut.
Kökte bir de .dockerignore dosyası aç ve imaja girmemesi gerekenleri yaz. Bu hem imajı küçültür hem de şifrelerin yanlışlıkla imaja girmesini engeller:
node_modules
.git
.envİmajı üret ve çalıştır
docker build -t benim-api .
docker run --rm -p 3000:3000 benim-api-p 3000:3000 bilgisayarının 3000 numaralı portunu konteynerin 3000 numaralı portuna bağlıyor. Tarayıcıda http://localhost:3000 adresini açtığında uygulamanı görmelisin. --rm ise konteyner durunca onu otomatik siliyor.
Veritabanı da lazımsa: Docker Compose
Gerçek projelerde uygulama tek başına çalışmaz; bir veritabanı da gerekir. Her birini ayrı docker run komutlarıyla başlatmak yerine Docker Compose ile hepsini tek bir dosyada tanımlarsın. Kökte compose.yaml oluştur:
services:
api:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:gizli@db:5432/app
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: gizli
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:Sonra tek komut:
docker compose up --buildDikkat edilecek iki nokta:
- API veritabanına
localhostile değil, servisin adıyla (db) bağlanıyor. Compose'daki servisler aynı ağda, birbirlerini adlarıyla buluyorlar. volumesolmadan veritabanındaki her şey konteyner silinince giderdi. Adlandırılmış bir volume, veriyi konteynerden ayrı saklıyor.
Ekipteki herkes artık projeyi aynı komutla, aynı sürümlerle açabiliyor. README'ne de bu komutu yazman yeterli.
Sık takılınan yerler
- "Port is already allocated": Bilgisayarında aynı portu kullanan başka bir şey çalışıyor. Ya onu kapat ya da sol taraftaki portu değiştir:
"3001:3000". - Uygulama konteynerde açılıyor ama tarayıcıdan erişilemiyor: Uygulaman yalnızca
127.0.0.1üzerinde dinliyor olabilir. Konteyner içinde0.0.0.0adresinde dinlemesi gerekiyor. - Kodu değiştirdim ama değişiklik görünmüyor: İmajı yeniden üretmen gerekiyor:
docker compose up --build. - Disk doluyor: Eski imajlar ve durmuş konteynerler birikiyor.
docker system dfne kadar yer kapladığını,docker system prunekullanılmayanları temizlemeyi gösteriyor. Silmeden önce ne sileceğini oku. - Şifreler imaja girdi: Şifreleri Dockerfile'a yazma,
.envdosyasını.dockerignore'a ekle ve değerleri çalışma anında ortam değişkeniyle ver.
Bu hafta dene
- Kendi projen için bir
Dockerfileve.dockerignoreyaz. - Veritabanı kullanıyorsa bir
compose.yamlekle. - Depoyu boş bir klasöre klonla ve yalnızca
docker compose upile ayağa kalktığını doğrula. - README'ye bu komutu ekle. Artık projeni çalıştırmak için kimsenin senin bilgisayarındaki kurulumu taklit etmesi gerekmiyor.
Docker ile takıldığın bir yer olursa yalnız değilsin. re:make her pazar 15.00'te buluşuyor; bilgisayarını getir, birlikte çözelim. Üye olmadan da gelebilirsin. Yeri ve saati burada.
Bir sonraki not düştüğünde haberin olsun.