← Blog
·10 blog.minutes

Docker ve Kubernetes: Modern Gelistiriciler Icin Pratik Bir Rehber

Konteynerlestirme, Dockerfile en iyi uygulamalari, Kubernetes temelleri ve bir orkestratore gercekten ne zaman ihtiyaciniz olduguna dair kapsamli bir rehber.

Her gelistirici eninde sonunda ayni duvara carpar. Makinenizde kod yazarsiniz, mukemmel calisir, staging e gonderirsiniz ve eksik bir sistem bagimliligi veya farkli bir kutuphane surumuyle ilgili gizemli bir hatayla patlar. Klasik "benim makinemde calisiyor" sorunu, onlarca yildir yazilim gelistirmeyi rahatsiz etmistir ve Docker bunu yalnizca cozmekle kalmadi — cozumu o kadar basit hale getirdi ki artik kullanmamak icin hicbir mazeret yok.

Ancak Docker yalnizca paketleme sorununu cozer. Uygulamanizi konteynerlestirdikten sonra, onu uretimde calistirmaniz gerekir — potansiyel olarak birden cok sunucuda, yuk dengeleme, sifir kesintili dagitim, saglik kontrolleri ve otomatik kurtarma ile. Iste bu noktada Kubernetes devreye girer. Ve cogu gelistiricinin karmasiklik icinde kayboldugu yer de burasidir, cunku Kubernetes, icsellestirilmesi zaman alan tamamen yeni bir soyutlama kelime dagarcigi sunar.

Bu rehber, gurultuyu keser. Konteynerlerin gercekte ne oldugunu, verimli ve guvenli Dockerfile larin nasil yazilacagini, gercek uygulamalari dagitmak icin bilmeniz gereken Kubernetes kavramlarini, yerel gelistirme icin Docker Compose ve Kubernetes arasindaki odunlesimleri ve — en onemlisi — her araca ne zaman basvurmaniz ve ne zaman yalniz birakmaniz gerektigini kapsar.

Konteynerler gercekte nedir

Bir konteyner, hafif bir sanal makine degildir. Bu en yaygin yanilgidir ve yanlis zihinsel modellere yol acar. Bir sanal makine, bir hipervizor uzerinde, kendi cekirdegi, kendi bellek ayirmasi ve kendi aygit suruculeri ile tam bir konuk isletim sistemi calistirir. Bir konteyner, ana bilgisayar cekirdegini paylasir ve izole edilmis bir kullanici alani sureci olarak calisir. Izolasyon, Linux cekirdek ozellikleri tarafindan saglanir — surec izolasyonu icin ad alanlari, kaynak sinirlari icin cgroup lar ve verimli goruntu katmanlari icin overlay dosya sistemleri.

Bu ayrim onemlidir cunku gozlemleyeceginiz davranisi aciklar. Konteynerler, baslatilacak cekirdek olmadigi icin milisaniyeler icinde baslar. Yedek cekirdek ve gereksiz sistem surecleri olmadigi icin daha az bellek kullanirlar. Ancak ayni zamanda, Linux uzerinde calisan bir konteynerin ana bilgisayardan farkli bir cekirdek surumu calistiramayacagi ve bir Windows konteynerinin bir Windows ana bilgisayari (veya eski surumlerde bir Hyper-V Linux VM si) gerektirdigi anlamina gelir. macOS ta Docker Desktop, tam da bu nedenle Linux konteynerlerini hafif bir VM icinde calistirir.

Bir imaj, salt okunur sablondur — bir dosya sisteminin arti meta verilerin anlik goruntusu. Bir konteyner, ustunde yazilabilir bir katman bulunan bu imajin calisan bir ornegidir. Bir imaji bir kez olusturabilir ve ondan duzinelerce konteyner calistirabilirsiniz. Bu, Docker dunyasindaki temel islem birimidir ve bunu net bir sekilde anlamak diger her seyi kolaylastirir.

Dockerfile en iyi uygulamalari

Bir Dockerfile, bir imaj olusturmak icin bir tariftir. Her talimat yeni bir katman olusturur ve katmanlar onbellege alinir. Bu, talimatlarin sirasinin derleme hizini, imaj boyutunu ve guvenligi dogrudan etkiledigi anlamina gelir. Iste gercek projelerde en onemli olan ilkeler.

Katmanlari degisim sikligina gore siralayin

Docker, olusturulduktan sonra her katmani onbellege alir. Bir katman son derlemeden bu yana degismediyse, Docker onbellege alinmis surumu yeniden kullanir. Bu, nadiren degisen talimatlari uste ve sik sik degisen talimatlari alta koymaniz gerektigi anlamina gelir. Sistem bagimliliklari (apt-get, apk add) neredeyse hic degismez. Uygulama bagimliliklari (npm install, pip install), kilitleme dosyanizi guncellediginizde degisir. Uygulama kaynak kodu, her commit te degisir.

# Bad: source code before dependencies
FROM node:20-alpine
WORKDIR /app
COPY . .                 # busts the cache for everything below
RUN npm ci                # runs on every build, even if package.json did not change
EXPOSE 3000
CMD ["node", "dist/index.js"]

# Good: stable-first layer ordering
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci                # cached unless package.json changes
COPY . .                  # only the source changes bust this layer
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/index.js"]

Fark carpicidir. Kotu Dockerfile, her commit te tum bagimliliklari yeniden olusturur. Iyi olan, bagimliliklari yalnizca kilitleme dosyasi degistiginde yeniden olusturur; bu, her commit yerine tipik olarak pull request basina bir kezdir. 500 bagimliligi olan bir Node.js projesinde bu, derleme basina iki dakika tasarruf saglayabilir.

Cok asamali derlemeler

Cok asamali derlemeler, uygulamanizi olusturmak ve minimum bir calisma zamani imaji uretmek icin tek bir Dockerfile kullanmaniza olanak tanir. Derleme asamasi, derleyicileri, gelistirme bagimliliklarini ve derleme araclarini icerir. Calisma zamani asamasi, yalnizca derlenmis ciktiyi kopyalar. Bu, uretim imajlarini kucuk tutar ve saldiri yuzeyini azaltir.

# Build stage
FROM node:20-alpine AS builder
WORKDIR /build
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

# Runtime stage — starts from a fresh, minimal base
FROM node:20-alpine AS runner
WORKDIR /app

# Only what is needed to run
COPY --from=builder /build/dist ./dist
COPY --from=builder /build/package.json ./
COPY --from=builder /build/node_modules ./node_modules

EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]

Calisma zamani asamasi, TypeScript derleyicisini, kaynak dosyalarini veya herhangi bir gelistirme bagimliligini icermez. Tipik bir uygulama icin bu, imaji 800 MB den 200 MB in altina dusurur. COPY --from=builder sozdizimi anahtar icgorudur — dosyalari onceki bir asamadan, o asamadaki katmanlari ileri tasimadan ceker.

Kok olmayan kullanici olarak calistirin

Konteynerler varsayilan olarak root olarak calisir. Bu bir guvenlik riskidir: bir saldirgan uygulamanizi istismar ederse, konteyner icinde root erisimine sahip olur. Duzeltme, Dockerfile inizda root olmayan bir kullaniciya gecen tek bir satirdir. Cogu temel imaj, bu amacla bir node veya nobody kullanicisiyla birlikte gelir.

Guvenligin otesinde, cok asamali derlemeler ve dogru katman siralamasi, CI/CD hatti hizini da artirir. Bir imaj derlemesinde kazanilan her dakika, gelistiricilerinizin bir dagitim icin beklemedigi bir dakikadir. Gunde bes kez dagitim yapan on gelistiricili bir ekipte, derleme basina iki dakika tasarruf etmek, yilda altmis saatten fazla gelistirici zamani kurtarir.

Kubernetes temelleri

Kubernetes, bir konteyner orkestratorudur. Bir makine kumesini (dugumler) alir, konteynerleri bunlara programlar, calisir durumda tutar, ag olusturmayi yoneter ve sisteminizin istenen durumunu tanimlamak icin bildirimsel bir API saglar. Kubernetes e ne istediginizi soylersiniz — API sunucunuzun uc kopyasi, 8080 portu acik, kademeli guncelleme stratejisi — ve o bunu gerceklestirir.

Ogrenme egrisi gercektir cunku Kubernetes katmanli bir soyutlama seti sunar. En cok etkilesime gireceginiz ucu Pod lar, Deployment lar ve Service lerdir.

Pod lar

Pod, Kubernetes teki en kucuk dagitilabilir birimdir. Bir ag ad alani ve depolama birimlerini paylasan bir veya daha fazla konteyneri temsil eder. Pratikte, cogu Pod tek bir konteyner calistirir. Sidecar desenleri (ana konteyner arti bir gunluk kaydi veya proxy konteyneri) cok konteynerli Pod lar kullanir, ancak gunluk uygulama dagitimi icin Pod basina bir konteyner kullanacaksiniz.

Pod lari nadiren dogrudan olusturursunuz. Pod lar gecicidir — herhangi bir zamanda sonlandirilabilir ve yeniden programlanabilirler. Bir Pod u manuel olarak olusturursaniz ve uzerinde calistigi dugum basarisiz olursa, Pod sonsuza kadar kaybolur. Iste burada Deployment lar devreye girer.

Deployment lar

Bir Deployment, bir dizi ozdes Pod u (bir ReplicaSet) yoneter. Kademeli guncellemeleri, olceklendirmeyi, kendi kendini iyilestirmeyi ve geri almalari halleder. Bu, durum bilgisi olmayan uygulamalari dagitmak icin kullanacaginiz kaynaktir.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  labels:
    app: api-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
        - name: api
          image: myregistry/api-server:v1.2.3
          ports:
            - containerPort: 3000
          resources:
            requests:
              cpu: 250m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi
          livenessProbe:
            httpGet:
              path: /healthz
              port: 3000
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000

Bu Deployment, API sunucusunun uc kopyasini bildirir. Kubernetes, uc Pod un her zaman calisir durumda olmasini saglar. Bir Pod cokerse, Kubernetes bir yenisini olusturur. Kademeli bir guncelleme sirasinda (imaj etiketini degistirme), Kubernetes Pod lari tek tek degistirerek sifir kesinti saglar. Canlilik sondasi (liveness probe), Kubernetes e bir Pod un ne zaman saglikli oldugunu soyler; hazir olma sondasi (readiness probe), bir Pod un ne zaman trafik almaya hazir oldugunu soyler.

Service ler

Pod larin dinamik IP adresleri vardir. Bir Pod her yeniden olusturuldugunda yeni bir IP alir. Bir Service, seciciyle (selector) eslesen Pod lar arasinda trafigi yuk dengeleyen sabit bir ag uc noktasi saglar. Sisteminizin diger bolumlerinin uygulamanizi nasil buldugu ve onunla nasil konustugu budur.

apiVersion: v1
kind: Service
metadata:
  name: api-server
spec:
  selector:
    app: api-server
  ports:
    - port: 80
      targetPort: 3000
  type: ClusterIP

Bu Service, sabit bir kume-ici IP uzerindeki 80 portunu, app: api-server etiketine sahip Pod lardaki 3000 portuna esler. Kume icindeki diger hizmetler, ona api-server DNS adiyla ulasabilir. Harici trafik icin Service in ustunde bir LoadBalancer veya Ingress kaynagi kullanirsiniz.

Kubernetes, dagitim yaptiginiz bir platform degil, dagitiminizi tanimladiginiz bir platformdur. Emir kipi ile bildirimsel arasindaki fark, yapabileceginiz en onemli zihinsel degisimdir.

Yerel gelistirme: Docker Compose vs Kubernetes

Ekiplerin yaptigi en buyuk hata, uretimde kullandiklari icin yerel gelistirme icin Kubernetes e ihtiyac duyduklarini varsaymaktir. Docker Compose ve Kubernetes farkli amaclara hizmet eder ve yerel calisma icin yanlis olani secmek gereksiz surtusme yaratir.

Docker Compose, yerel gelistirme icin tasarlanmistir. Tek bir makinede calisir, konteynerleri saniyeler icinde baslatir ve ihtiyaciniz olan seye dogrudan karsilik gelen basit bir YAML formatina sahiptir: bir web sunucusu, bir veritabani, bir Redis ornegi ve belki bir kuyruk calisani. Hizmetleri tanimlarsiniz ve docker compose up her seyi cevrimici hale getirir, loglar terminalinize akar, portlar localhost a eslenir ve sicak yeniden yukleme kutudan cikar cikmaz calisir.

version: "3.8"
services:
  api:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Bu Compose dosyasi, size sicak yeniden yukleme, kalici depolamali yerel bir veritabani ve hizmetler arasinda uygun ag olusturma ile calisan bir gelistirme ortami verir. Yaklasik otuz satir YAML alir ve on saniyeden kisa surede baslar.

Minikube, Kind ve k3s, Kubernetes i yerel olarak calistirabilir, ancak onemli olcude ek yuk eklerler. Daha fazla bellek gerektirir, baslamalari daha uzun surer ve tek bir ozellik uzerinde yineleme yaparken ihtiyaciniz olmayan karmasiklik (ingress denetleyicileri, hizmet aglari, depolama siniflari) eklerler. Kubernetes i yerel olarak calistirmak, Kubernetes e ozgu davranislari — pod cikarma politikalari, yatay pod otomatik olceklendirme veya ozel kaynak tanimlari gibi — test etmek icin kullanislidir, ancak gunluk gelistirmede Compose un yerini tutmaz.

  • Yerel gelistirme icin Docker Compose kullanin. Hizlidir, basittir ve calistirdiginiz konteynerlerle dogrudan eslesir.
  • Uretim altyapiniz ConfigMap ler, Secret lar veya ozel denetleyiciler gibi Kubernetes ozelliklerini kullandiginda entegrasyon testi icin Kubernetes (Minikube veya Kind araciligiyla) kullanin.
  • Uzak bir gelistirme kumesini yalnizca GPU erisimi, ozel donanim veya uretimi tam olarak yansitan paylasimli bir staging ortami gerektiginde kullanin.
  • Sirf iki ortaminiz var diye yerel olarak iki Kubernetes kumesi calistirmayin. Compose, bunu tek bir --profile bayragiyla halleder.
  • Ekibiniz, uygulama kodu yazmaktan cok Kubernetes yapilandirmalarinda hata ayiklamaya zaman harciyorsa, farlarinizin otesine gecmissinizdir. Compose a geri donun ve karmasikligi yalnizca ona sahip olmamanin acisi, onu surdurmenin acisini astiginda ekleyin.

Yaygin tuzaklar ve bunlardan nasil kacinilir

Kavramlari anladiktan sonra bile, belirli hatalar ekipler arasinda tekrarlanir. Iste iki gunluk hata ayiklama oturumlarini atlamak icin ezberlemeye deger olanlar.

Imaj etiketi karmasasi en yaygin uretim sorunudur. Bir Kubernetes Deployment inda imaj etiketi olarak latest kullanmak, herhangi bir dugumde hangi surumun calistigini soyleyemeyeceginiz anlamina gelir. Kubernetes, bir imaji yalnizca dugumde yoksa ceker, bu nedenle bir dugumdeki latest, diger dugumdeki latest ten farkli bir surum olabilir. Her zaman anlamsal surum etiketleri veya commit SHA lari kullanin. Daha da iyisi, tam nitelikli bir imaj ozeti (digest) kullanin — degismez oldugu garanti edilen tek sey budur.

Kaynak istekleri (requests) ve limitleri siklikla atlanir veya rastgele ayarlanir. Istek belirlemezseniz, Kubernetes Pod larinizi akillica programlayamaz ve dugumler asiri yuklenir. Limit belirlemezseniz, bir Pod daki bellek sizintisi ayni dugumdeki diger Pod lari cokertebilir. Ikisini de ayarlayin ve oneri modundaki Vertical Pod Autoscaler gibi araclari gercek kullanim bazinda ince ayar yapmak icin kullanin.

ConfigMap ler ve Secret lar, ortam degiskenleri veya dosyalar olarak baglanir. Ortam degiskenleri kullanislidir, ancak herhangi bir degisiklik Pod un yeniden baslatilmasini gerektirir. Dosya tabanli baglamalar, yeniden baslatmadan guncellenebilir (Pod, dosyaya erisildiginde yeni icerigi okur), ancak bircok uygulama baslangicta yapilandirmayi onbellege alir. Uygulamanizin hangi deseni kullandigini bilin ve yapilandirma yaklasiminizi buna gore tasarlayin.

Kubernetes te kalici birimler (persistent volumes) sihirli degildir. Bir PersistentVolumeClaim depolama talep eder, ancak temel depolama sinifi bulut saglayiciniz icin yapilandirilmis olmalidir. Varsayilan depolama siniflari, yerel SSD lerden farkli performans ozelliklerine sahip aga-bagli depolama kullanabilir. Veritabani performansiniz onemliyse, uretime gecmeden once depolama sinifinizi karsilastirmali olarak test edin.

Kubernetes te loglama ve hata ayiklama, tek bir sunucudan daha zordur. Pod lar gecicidir, bu nedenle bir Pod silindiginde loglar kaybolur. Canli izleme icin kubectl logs --tail=50 -f pod-name kullanin, ancak uretimde hata ayiklama icin merkezi bir log cozumune (Loki, Elasticsearch veya bir bulut loglama servisi) ihtiyaciniz vardir. Benzer sekilde, calisan bir konteyneri incelemek icin kubectl exec -it pod-name -- sh ile bir Pod a exec yapin, ancak calisan bir konteyner icinde yaptiginiz herhangi bir degisikligin yeniden baslatmada kaybolacagini unutmayin.

Kubernetes e gercekten ihtiyaciniz var mi?

Bu, kimsenin sormak istemedigi sorudur cunku Kubernetes bir muhendislik ozgecmisinde iyi gorunur ve operasyonel olgunluk sinyali verir. Ancak Kubernetes, belirli bir soruna cozumdur: birden cok konteynerli hizmeti, otomatik kurtarma, olceklendirme ve kademeli dagitimlarla birden cok makinede calistirmak. Tek bir sunucuda calisan bir veya iki hizmetiniz varsa, Kubernetes gereksizdir.

Iste basit bir karar cercevesi. Saniyede on binden az istek sunan tek bir uygulama dagitiyorsaniz, uretimde Docker Compose ile tek bir sunucu (evet, Compose bircok is yuku icin uretimde gayet iyi calisir) size iyi hizmet edecektir. Caddy veya Nginx gibi bir ters proxy ekleyin, otomatik yedeklemeler kurun ve tek bir gelistiricinin tamamini anlayip surdurebilecegi bir uretim sisteminiz olur.

Kubernetes e, bagimsiz olarak dagitilmasi gereken birden cok hizmetiniz oldugunda, hizmet-basi olceklendirmeye ihtiyac duydugunuzda (API nizin on kopyaya ihtiyaci var ancak calisaninizin yalnizca ikiye), rutin bir operasyon olarak sifir-kesintili dagitimlara ihtiyac duydugunuzda veya ekibinizde birincil sorumlulugu altyapi olan en az bir kisi oldugunda gecin. Bu kosullar karsilanmadan once, Kubernetes in operasyonel maliyeti — hem kume yonetimi hem de gelistirici bilissel yuku acisindan — net bir negatiftir.

Bircok ekip, orta yoldan faydalanir. Yerel gelistirme icin Docker Compose ve uretim icin AWS App Runner, Google Cloud Run veya Fly.io gibi yonetilmis bir konteyner platformu kullanin. Bu platformlar, bir Kubernetes kontrol duzlemini yonetmenizi gerektirmeden konteyner dagitimi, otomatik HTTPS ve olceklendirme saglar. Kubernetes ogrenme egrisi olmadan konteynerlestirmenin faydalarinin cogunu elde edersiniz.

En iyi altyapi stratejisi, ekibinizin ozellik gonderimini saglayandir. Docker ve Kubernetes araclardir, kimlik degildir. Yardimci olduklarinda kullanin, olmadiklarinda atlayin.