GitHub Actions Nedir: CI/CD Temelleri ve Kullanımı

Yazılım geliştirme süreçlerinde en can sıkıcı şeylerden biri, her değişikliği elle test edip elle sunucuya atmaktır. Bir ara ben de bu döngüdeyim: kodu yaz, FTP’ye bağlan, dosyaları sürükle, sunucuya gir, servisi yeniden başlat… Hem zaman kaybı, hem de insan hatasına açık kapı. İşte tam da bu noktada CI/CD kavramı ve GitHub Actions devreye giriyor. Bu yazıda GitHub Actions’ı sıfırdan anlayacak, gerçek dünya senaryolarıyla nasıl kullanacağınızı öğreneceksiniz.

CI/CD Nedir, Neden Önemlidir

CI/CD, Continuous Integration (Sürekli Entegrasyon) ve Continuous Deployment/Delivery (Sürekli Dağıtım) kavramlarının birleşiminden oluşur.

Continuous Integration şu anlama gelir: Ekibinizdeki geliştiriciler kod yazdıkça, bu kodlar otomatik olarak ana dal ile birleştirilir ve her birleştirmede testler çalıştırılır. “Bende çalışıyordu” sorunu böylece ortadan kalkar.

Continuous Deployment/Delivery ise şunu ifade eder: Testleri geçen kod otomatik olarak staging veya production ortamına aktarılır. Siz kahve içerken sistem kendi kendine deploy eder.

Bu iki kavramın sağladığı faydalar oldukça somuttur:

  • Hataları erken yakalar, production’a ulaşmadan önce görürsünüz
  • Manuel işlemler azaldığı için insan hatası riski düşer
  • Ekip üyeleri birbirinin kodunu sürekli entegre ettiğinden büyük merge çatışmaları yaşanmaz
  • Yeni özellikler kullanıcılara daha hızlı ulaşır
  • Gece 2’de sunucuya bağlanıp güncelleme yapma dönemi sona erer

GitHub Actions Nedir

GitHub Actions, GitHub’ın kendi bünyesinde sunduğu bir CI/CD platformudur. Deponuzda belirli olaylar (push, pull request, zamanlama vb.) gerçekleştiğinde otomatik olarak iş akışları başlatır. 2018’de beta olarak çıktı, 2019’da genel kullanıma açıldı ve şu an piyasadaki en popüler CI/CD araçlarından biri haline geldi.

GitHub Actions’ın öne çıkan özellikleri şunlardır:

  • Ücretsiz kota: Public repolar için tamamen ücretsiz, private repolar için aylık 2000 dakika ücretsiz kullanım hakkı var
  • Kolay entegrasyon: Zaten GitHub kullanıyorsanız ekstra bir servis kurmaya gerek yok
  • Marketplace: Binlerce hazır action var, sıfırdan yazmak zorunda kalmıyorsunuz
  • Matrix build: Aynı kodu farklı ortamlarda (Python 3.9, 3.10, 3.11 gibi) paralel test edebilirsiniz
  • Self-hosted runner: Kendi sunucunuzda çalıştırabilirsiniz

Temel Kavramlar

GitHub Actions’ı anlamak için birkaç temel kavramı kafanıza oturtmanız gerekiyor.

Workflow (İş Akışı): Otomatikleştirmek istediğiniz sürecin tamamı. YAML formatında tanımlanır ve .github/workflows/ dizininde saklanır.

Event (Olay): Workflow’u tetikleyen şeydir. Bir branch’e push yapmak, pull request açmak, bir issue oluşturmak ya da belirli bir saatte zamanlama gibi durumlar birer event’tir.

Job (İş): Workflow içindeki adım gruplarıdır. Birden fazla job tanımlayabilirsiniz, bunlar paralel ya da sıralı çalışabilir.

Step (Adım): Bir job içindeki tek tek komutlardır. Her step ya bir shell komutu ya da hazır bir action çalıştırır.

Runner: Job’ların çalıştığı sanal makinedir. GitHub’ın kendi runner’ları Ubuntu, Windows ve macOS destekler.

Action: Tekrar kullanılabilir görev birimidir. Marketplace’ten hazır action’lar kullanabilir ya da kendi action’ınızı yazabilirsiniz.

İlk Workflow Dosyanızı Oluşturun

Hadi işe koyulalım. Basit bir Python projesi için ilk CI pipeline’ınızı oluşturalım. Deponuzda .github/workflows/ dizini yoksa oluşturun ve içine ci.yml adında bir dosya koyun.

mkdir -p .github/workflows
touch .github/workflows/ci.yml

İşte temel bir workflow dosyası:

# .github/workflows/ci.yml
name: Python CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Kodu çek
        uses: actions/checkout@v4

      - name: Python kur
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Bağımlılıkları yükle
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      - name: Testleri çalıştır
        run: |
          python -m pytest tests/ -v

      - name: Kod kalitesini kontrol et
        run: |
          pip install flake8
          flake8 . --count --max-line-length=127

Bu workflow ne yapıyor? main veya develop branch’ine push yapıldığında ya da main‘e pull request açıldığında tetikleniyor. Ubuntu üzerinde Python 3.11 kuruyor, bağımlılıkları yüklüyor, testleri çalıştırıyor ve kod kalitesini kontrol ediyor. Böyle basit bir dosya ile çok ciddi bir güvence elde ediyorsunuz.

Gerçek Dünya Senaryosu: Node.js Uygulaması Deploy

Diyelim ki bir Node.js web uygulamanız var ve her push’ta hem test etmek hem de DigitalOcean’daki sunucunuza otomatik deploy yapmak istiyorsunuz. İşte bunun için gerçekçi bir workflow:

# .github/workflows/deploy.yml
name: Test ve Deploy

on:
  push:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Node.js kur
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Paketleri yükle
        run: npm ci

      - name: Unit testleri çalıştır
        run: npm test

      - name: Build al
        run: npm run build

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: SSH ile sunucuya bağlan ve deploy et
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/myapp
            git pull origin main
            npm ci --production
            pm2 restart myapp

Burada dikkat etmeniz gereken birkaç nokta var. needs: test satırı, deploy job’ının ancak test job’ı başarıyla tamamlandıktan sonra çalışmasını sağlıyor. if: github.ref == 'refs/heads/main' koşulu ise deploy’un sadece main branch’inden tetiklenmesini garantiliyor. Secrets (gizli değişkenler) konusuna birazdan geleceğiz.

Secrets Yönetimi

Şifreler, API anahtarları ve SSH private key’leri gibi hassas bilgileri asla doğrudan YAML dosyasına yazmayın. GitHub’ın Secrets özelliği tam bu iş için var.

Secrets eklemek için şu adımları izleyin:

  • GitHub deponuza gidin
  • Settings sekmesine tıklayın
  • Sol menüden “Secrets and variables” > “Actions” seçin
  • “New repository secret” butonuna tıklayın
  • İsim ve değer girerek kaydedin

Workflow dosyasında ise şu sözdizimini kullanıyorsunuz:

# Secrets kullanım örneği
steps:
  - name: Docker Hub'a giriş yap
    run: |
      echo "${{ secrets.DOCKER_PASSWORD }}" | docker login 
        -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin

  - name: Ortam değişkenlerini ayarla
    env:
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
      API_KEY: ${{ secrets.API_KEY }}
    run: |
      echo "Veritabanına bağlanılıyor..."
      node scripts/migrate.js

Secrets log’larda otomatik olarak maskelenir. Yani echo ${{ secrets.MY_SECRET }} yazsanız bile çıktıda * görürsünüz. Bu güzel bir güvenlik önlemi.

Matrix Build ile Çoklu Ortam Testi

Bir kütüphane geliştiriyorsanız ya da uygulamanızın birden fazla Python/Node sürümüyle çalışmasını istiyorsanız matrix build hayat kurtarır. Tek bir workflow tanımı ile onlarca kombinasyonu paralel test edebilirsiniz:

# .github/workflows/matrix.yml
name: Çoklu Ortam Testi

on: [push, pull_request]

jobs:
  test:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ['3.9', '3.10', '3.11', '3.12']
        exclude:
          - os: windows-latest
            python-version: '3.9'

    steps:
      - uses: actions/checkout@v4

      - name: Python ${{ matrix.python-version }} kur
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: Testleri çalıştır
        run: |
          pip install pytest
          pytest tests/ -v --tb=short

Bu workflow, exclude kısmı hariç toplamda 11 farklı kombinasyonu paralel olarak çalıştırır. Eğer her birini elle test etseydiniz saatler harcardınız. GitHub Actions bunu dakikalar içinde halleder.

Artifact Yönetimi ve Önbellekleme

Her workflow çalışmasında bağımlılıkları sıfırdan indirmek zaman kaybıdır. Önbellekleme ile bu süreyi ciddi ölçüde kısaltabilirsiniz:

# .github/workflows/cache-example.yml
name: Önbellekli Build

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: npm önbelleğini ayarla
        uses: actions/cache@v3
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Paketleri yükle
        run: npm ci

      - name: Build al
        run: npm run build

      - name: Build çıktısını artifact olarak sakla
        uses: actions/upload-artifact@v3
        with:
          name: build-output
          path: dist/
          retention-days: 7

  deploy:
    needs: build
    runs-on: ubuntu-latest

    steps:
      - name: Build artifact'ını indir
        uses: actions/download-artifact@v3
        with:
          name: build-output
          path: dist/

      - name: Sunucuya yükle
        run: |
          rsync -avz dist/ user@server:/var/www/html/

hashFiles fonksiyonu, package-lock.json dosyasının hash’ini önbellek anahtarı olarak kullanır. Bağımlılıklar değişmediği sürece önbellekten yükleme yapılır, değişirse yeni bir önbellek oluşturulur. Bu küçük optimizasyon, workflow sürenizi yüzde elliye kadar düşürebilir.

Docker ile CI/CD Pipeline

Modern uygulamaların büyük çoğunluğu containerized olarak çalışıyor. Docker image build edip registry’ye push etmek ve ardından deploy etmek için şu workflow’u kullanabilirsiniz:

# .github/workflows/docker-deploy.yml
name: Docker Build ve Deploy

on:
  push:
    branches: [ main ]
    tags: [ 'v*.*.*' ]

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    steps:
      - 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.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Meta bilgileri çıkar
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: myusername/myapp
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - name: Image'ı build et ve push et
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest

    steps:
      - name: Uzak sunucuda container'ı güncelle
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            docker pull myusername/myapp:main
            docker stop myapp || true
            docker rm myapp || true
            docker run -d 
              --name myapp 
              --restart unless-stopped 
              -p 3000:3000 
              -e DATABASE_URL=$DATABASE_URL 
              myusername/myapp:main

Tag push’larında (v1.2.3 gibi) otomatik olarak semantic versioning ile etiketleme yapılıyor. Bu sayede image geçmişiniz düzenli kalır ve gerektiğinde eski bir versiyona dönmek kolaylaşır.

Workflow Tetikleyicileri ve Koşullar

GitHub Actions’ın gücünün önemli bir kısmı esnek tetikleyici sistemidir. İhtiyacınıza göre şekillendirin:

# .github/workflows/advanced-triggers.yml
name: Gelişmiş Tetikleyiciler

on:
  # Zamanlama ile çalıştır (her gece saat 02:00 UTC)
  schedule:
    - cron: '0 2 * * *'

  # Manuel tetikleme (input parametreli)
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy ortamı'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production
      debug_mode:
        description: 'Debug modu aktif et'
        type: boolean
        default: false

  # Başka bir workflow tamamlandığında
  workflow_run:
    workflows: ["Test Suite"]
    types:
      - completed

jobs:
  conditional-deploy:
    runs-on: ubuntu-latest
    # Sadece başarılı workflow'dan sonra çalış
    if: ${{ github.event.workflow_run.conclusion == 'success' }}

    environment: ${{ inputs.environment || 'staging' }}

    steps:
      - name: Ortam bilgisini göster
        run: |
          echo "Deploy ortamı: ${{ inputs.environment }}"
          echo "Debug modu: ${{ inputs.debug_mode }}"
          echo "Tetikleyen: ${{ github.event_name }}"

Özellikle workflow_dispatch çok kullanışlı. GitHub arayüzünden “Run workflow” butonuna tıklayarak manuel olarak ve parametrelerle çalıştırabiliyorsunuz. Gece yarısı acil bir deploy yapmanız gerektiğinde terminale bile gerek kalmıyor.

Self-Hosted Runner Kurulumu

GitHub’ın sunduğu runner’lar çoğu iş için yeterlidir ancak bazı durumlarda kendi runner’ınızı kurmak mantıklıdır:

  • Private network kaynaklarına erişmeniz gerekiyorsa
  • Özel donanım gerektiren işler varsa
  • Ücretsiz dakika kotasını aşıyorsanız
  • Daha hızlı bir makine istiyorsanız

Runner kurmak için şu adımları izleyin:

# GitHub > Settings > Actions > Runners > New self-hosted runner

# Runner'ı indir
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.311.0.tar.gz -L 
  https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz
tar xzf ./actions-runner-linux-x64-2.311.0.tar.gz

# Yapılandır (token GitHub arayüzünden alınır)
./config.sh --url https://github.com/KULLANICI/REPO 
  --token BURAYA_TOKEN_GELECEK

# Servis olarak kur ve başlat
sudo ./svc.sh install
sudo ./svc.sh start

# Durum kontrolü
sudo ./svc.sh status

Workflow dosyasında self-hosted runner kullanmak için runs-on satırını değiştirmeniz yeterli:

jobs:
  build:
    runs-on: self-hosted
    # ya da daha spesifik etiket ile:
    # runs-on: [self-hosted, linux, x64]

Hata Ayıklama ve İzleme

Workflow’larınızda bir şeyler ters gittiğinde ne yaparsınız? GitHub Actions birkaç güzel araç sunuyor:

# .github/workflows/debug.yml
name: Debug Pipeline

on: [push]

jobs:
  debug-job:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Ortam değişkenlerini listele
        run: env | sort

      - name: GitHub context bilgisi
        env:
          GITHUB_CONTEXT: ${{ toJson(github) }}
        run: echo "$GITHUB_CONTEXT"

      - name: Hata durumunda bile çalış
        if: failure()
        run: |
          echo "Bir önceki adım başarısız oldu!"
          echo "Branch: ${{ github.ref }}"
          echo "Commit: ${{ github.sha }}"
          # Slack bildirimi gönder
          curl -X POST ${{ secrets.SLACK_WEBHOOK }} 
            -H 'Content-type: application/json' 
            --data '{"text":"Deploy başarısız! Branch: ${{ github.ref }}"}'

      - name: Her durumda çalış
        if: always()
        run: echo "Bu adım her zaman çalışır"

if: failure() ile hata durumunda Slack veya e-posta bildirimi gönderebilirsiniz. if: always() ile log toplama veya temizleme işlemlerini her zaman çalıştırabilirsiniz.

Yaygın Hatalar ve Çözümleri

Yeni başlayanların en sık yaptığı hatalar şunlardır:

YAML girintileme hataları: YAML’da girinti hayati önem taşır. Tab yerine boşluk kullanın ve tutarlı olun. Visual Studio Code için YAML extension’ı kurmanızı öneririm.

Secrets’ı yanlış referanslama: ${{ secret.MY_KEY }} değil, ${{ secrets.MY_KEY }} doğru kullanım.

Job bağımlılıklarını unutmak: needs tanımlamadan deploy job’ı test job’ından önce çalışabilir.

Runner’da sudo gerektiren komutlar: GitHub’ın runner’larında sudo çalışır ancak self-hosted runner’larda kullanıcı yetkilerine dikkat edin.

Büyük artifact’lar: 500 MB’ı aşan artifact’lar için GitHub’ın artifact depolama limitlerini göz önünde bulundurun, harici storage kullanmayı düşünün.

Sonuç

GitHub Actions, yazılım geliştirme süreçlerinizi kökten dönüştürebilecek güçlü bir araçtır. Bu yazıda ele aldığımız konular bir başlangıç noktasıdır: temel CI pipeline’dan Docker deployment’a, matrix build’den self-hosted runner’a kadar oldukça geniş bir yelpaze gördünüz.

Benim tavsiyem şu: Karmaşık şeylerle başlamayın. Önce projenize basit bir test workflow’u ekleyin. Çalıştığını görünce bir adım daha atın, staging deploy’u ekleyin. Sonra production’ı otomatize edin. Her adımda güven kazanırsınız ve sistemi daha iyi anlarsınız.

CI/CD’nin en büyük katkısı teknik olmayan bir şeydir aslında: Zihinsel rahatlık. “Deploy ettim, bir şey bozuldu mu acaba?” kaygısıyla değil, “Testler geçti, otomatik deploy oldu, her şey yolunda” güveniyle çalışmak başka bir his. GitHub Actions ile bu noktaya ulaşmak artık hiç bu kadar kolay olmamıştı.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir