Bir imajı elle build edip elle sunucuya taşımak, tek kişilik küçük projelerde işe yarasa da ekiple çalışırken hızla sürdürülemez hale gelir. CI/CD (Continuous Integration / Continuous Deployment), kod her push edildiğinde imajı otomatik build eden, test eden ve gerekirse otomatik dağıtan bir boru hattı (pipeline) kurmanızı sağlar. Bu yazıda GitHub Actions üzerinden uçtan uca çalışan gerçekçi bir örnek kuruyoruz.

Neden CI/CD?

  • Tutarlılık: İmaj her zaman aynı, temiz ortamda build edilir — “bende çalışıyordu” sorunu build aşamasında da ortadan kalkar.
  • Hız: Kod push edildiği anda test ve build otomatik başlar, elle müdahale gerekmez.
  • Güvenlik: Zafiyet taraması gibi kontroller pipeline’a eklenerek, sorunlu bir imajın production’a ulaşması en baştan engellenir.

Basit bir GitHub Actions pipeline’ı

.github/workflows/docker-build.yml dosyasında tanımlanan bu akış; her main dalına push’ta imajı build eder, test eder ve registry’e gönderir:

name: Docker Build ve Push

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Kodu çek
        uses: actions/checkout@v4

      - name: Docker Buildx kur
        uses: docker/setup-buildx-action@v3

      - name: Docker Hub'a giriş yap
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: İmajı build et ve gönder
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            kullanici-adi/benim-api:latest
            kullanici-adi/benim-api:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

cache-from/cache-to: type=gha satırları, Docker katman önbelleğini GitHub Actions’ın kendi önbellek deposunda tutar — değişmeyen katmanlar (örneğin bağımlılık kurulumu) her build’de sıfırdan çalışmaz, bu da pipeline’ı ciddi ölçüde hızlandırır.

Build’den önce zafiyet taraması ekleyin

İmaj push edilmeden önce, bilinen güvenlik açıklarını yakalamak için Trivy gibi bir tarayıcıyı pipeline’a eklemek yaygın bir pratiktir (bkz. Container Image Güvenliği yazımız):

      - name: İmajı yerel olarak build et (henüz push etme)
        uses: docker/build-push-action@v5
        with:
          context: .
          push: false
          load: true
          tags: benim-api:test

      - name: Trivy ile zafiyet taraması
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: benim-api:test
          severity: HIGH,CRITICAL
          exit-code: 1   # kritik açık bulunursa pipeline'ı durdur
✓

Sırayı doğru kurun: önce build + test + tarama, sonra push. Böylece taramadan geçemeyen bir imaj hiçbir zaman registry’e ulaşmaz — “önce dağıt, sonra kontrol et” değil, “önce kontrol et, sonra dağıt” mantığı.

Otomatik dağıtım (CD): sunucuya deploy

İmaj registry’e ulaştıktan sonra, production sunucusunda yeni sürümü çekip yeniden başlatan bir adım eklenebilir. Basit bir kurulumda bu, SSH üzerinden sunucuda birkaç komut çalıştırmak kadar basit olabilir:

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Sunucuda yeni imajı çek ve yeniden başlat
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SUNUCU_IP }}
          username: ${{ secrets.SUNUCU_KULLANICI }}
          key: ${{ secrets.SUNUCU_SSH_ANAHTARI }}
          script: |
            docker pull kullanici-adi/benim-api:latest
            docker compose up -d --no-deps --build web

Kubernetes veya Docker Swarm kullanan daha büyük kurulumlarda bu adım genellikle kubectl set image ... veya docker service update --image ... komutuyla değiştirilir — mantık aynıdır: yeni imajı işaret et, orkestratör kalanını (rolling update dahil) halletsin.

Pipeline’ı özetleyen akış

  1. Kod main dalına push edilir.
  2. Pipeline imajı build eder.
  3. Trivy ile zafiyet taraması yapılır; kritik açık varsa pipeline durur.
  4. Tarama geçerse imaj registry’e push edilir.
  5. Sunucuda (veya orkestratörde) yeni imaj çekilip devreye alınır.

İmajınız artık otomatik olarak build edilip güvenli şekilde production’a ulaşıyor. Bir sonraki adım, bu production ortamındaki container’ların sağlıklı çalışıp çalışmadığını sürekli izlemek — bunu bir sonraki yazıda ele alıyoruz.