Biri Github Actions mı dedi?

GitHub Actions, GitHub üzerinde yer alan, kullanımı kolay bir CI/CD (Continuous Integration/Continuous Deployment) aracıdır. Kullanıcıların kodlarını otomatik olarak test etmesine, derlemesine ve dağıtmasına olanak tanır. İş akışlarını (workflow) tanımlayarak, kod değişikliklerine bağlı olarak belirli işlemlerin otomatik olarak gerçekleştirilmesini sağlayabilmek için kullanılır. Bu yazıda kendi projelerinizi Github Actions kullanarak nasıl dağıtabileceğinizi anlatmaya çalışacağım ama önce genel bilgileri vereyim.

Ne İçin Kullanılır?

Sürekli Entegrasyon (CI): Kod değişikliklerini otomatik olarak test etme ve derleme.
Sürekli Dağıtım (CD): Uygulamaları belirli ortamlara otomatik olarak dağıtma.
Otomasyon: Kod deposu (repository) üzerindeki belirli olaylara bağlı olarak otomatik görevler çalıştırma.
Bildirimler: Belirli olaylar gerçekleştiğinde (örneğin, pull request açıldığında) bildirimler gönderme.
Kod Kalitesi Kontrolleri: Kodun kalitesini otomatik olarak analiz etme ve raporlama.

Nasıl Çalışır?

GitHub Actions, kullanıcıların iş akışlarını YAML (YAML Ain't Markup Language) dosyaları ile tanımladığı bir sistemdir. Bu iş akışları belirli olaylara (events) tepki verir ve belirli işlemleri (jobs) gerçekleştirir.

Temel Bileşenleri Nelerdir?
  1. Workflow: Bir veya birden fazla job içeren en üst seviye yapı. .github/workflows dizininde bulunur.
  2. Job: Bir veya birden fazla adım (step) içeren bir işlem. Aynı veya farklı makinelerde (runner) çalıştırılabilir.
  3. Step: Belirli bir görevi gerçekleştiren bir komut veya aksiyon.
  4. Action: Yeniden kullanılabilir adımlardan oluşan küçük işlevler. GitHub Marketplace'te bulunabilir veya kendi aksiyonlarınızı yazabilirsiniz.
  5. Runner: İş akışlarının çalıştırıldığı sanal makineler.

Nerelerde Kullanılır?

CI/CD Pipeline Kurulumu: Kodun otomatik olarak test edilmesi, derlenmesi ve dağıtılmasında kullanılır.
Otomatik Kontroller: Kod kalitesi, güvenlik taramaları, stil rehberine uygunluk gibi kontrollerin otomatik yapılmasında kullanılır.
Dağıtım: Uygulamaların belirli ortamlara (test, staging, production) otomatik olarak dağıtılması için kullanılır.
Bildirimler ve Entegrasyonlar: Slack, Discord, e-posta gibi araçlara bildirimler gönderme ve diğer hizmetlerle entegrasyon sağlamak amacıyla kullanılır.

Uzun lafın kısası GitHub Actions, GitHub deposu üzerinde otomasyon süreçlerini yönetmek için güçlü ve esnek bir araçtır. İhtiyaçlarınıza göre özelleştirilebilir ve genişletilebilir.

Deployment Yönetimi

Öncelikle burada Github Actions kullanarak bir PHP projesini bir kaç farklı senaryoda en basit şekilde nasıl dağıtabileceğinizi anlatmaya çalışacağım. Elbette adımlarda çalıştırılan işlemleri kendinize göre değiştirerek kendiniz için uygun bir dağıtım süreci tasarlayabilirsiniz. Hadi başlayalım.

Yapılandırma Dosyası : deploy.yml

Github Actions kullanarak deploment sürecinizi yönetmek için öncelikle bir deploy.yml dosyasına ihtiyacınız var.

Projenizin github reposunda ".github/workflows" dizinini oluşturun.

Bu dizin içinde "deploy.yml" isimli bir dosya oluşturun. Ve aşağıdaki içeriği ekleyin.

name: Deploy PHP Application

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
      
      - name: PHP Kurulumu
        uses: shivammathur/setup-php@v2
        with: 
          php-version: '8.0'
      
      - name: Composer paketlerinin kurulumu
        run: composer install --no-progress --no-suggest --prefer-dist

      - name: SSH Bağlantısı ve Son Kodun Alınması
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          HOST: ${{ secrets.SSH_HOST }}
          USER: ${{ secrets.SSH_USER }}
          REMOTE_PATH: ${{ secrets.REMOTE_PATH }}
        run: |
          echo "$SSH_PRIVATE_KEY" > private_key
          chmod 600 private_key
          ssh -i private_key -o StrictHostKeyChecking=no $USER@$HOST "cd $REMOTE_PATH && git pull origin main"

SSH Anahtarı ve Yetkilendirme

Sunucunuzda bir SSH anahtarı oluşturun. Bu işlem için aşağıdaki komutu yürütün;

ssh-keygen -t rsa -b 4096 -C "[email protected]"

Bu komut, sana id_rsa ve id_rsa.pub isimli iki dosya oluşturacaktır. Oluşturulan SSH anahtarının github tarafından kullanılması için ~/.ssh/authorized_keys dosyasına yazılması gerekiyor.

cat ~/.ssh/id_rsa.pub

Yukarıdaki komutun çıktısını kopyalayarak

nano ~/.ssh/authorized_keys

yapıştırın ve kapatın.

Github Secrets Ayarlamaları

Github reponuzu tarayıcıda açın ve "Settings" sekmesine gidin. Ardından "Secrets and variables" altındaki "Actions" menüsüne gidin ve aşağıdakileri ekleyin;

  • SSH_PRIVATE_KEY : Bu sunucunuzda oluşturduğunuz SSH anahtarınızdır. Bu anahtarı öğrenmek için aşağıdaki komutu yürütebilirsiniz.
cat ~/.ssh/id_rsa
  • SSH_HOST : Bu sunucunuzun IP adresidir.
  • SSH_USER : SSH bağlantısında kullanılacak kullanıcıdır.
  • REMOTE_PATH : Sunucunuzda projenizin bulunduğu dizindir.

Her şeyi doğru yaptıysanız "main" branchine yapacağınız bir push ya da birleştirme otomatik olarak sunucunuza kodun gideceği anlamına geliyor. :D

Farklı Ortamlar Farklılık Gerektirir

Yukarıda anlattıklarım temelde "main" branchinde her hangi bir birleştirme işlemi yapıldığında sunucunuza bağlanarak bu değişikliği sunucunuza çekmekten ibaretti. Ancak genellikle işler bu kadar basit olmayacaktır. :D

Canlı ve test ortamlarınızın ayrı olduğunu ve farklı branchleri dinlediğini düşünelim. Ne yapacaksınız? İşte örnek bir deploy.yml dosyası içeriği;

name: Deploy PHP Application

on:
  push:
    branches:
      - main
      - develop

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: SSH Bağlantısı ve Son Kodun Alınması
        if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
          
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            REMOTE_USER="canli_kullanici_adi"
            REMOTE_HOST="canlı_sunucu_adresi"
            REMOTE_PATH="/home/remote/project/path"
          elif [ "${{ github.ref }}" == "refs/heads/develop" ]; then
            REMOTE_USER="test_kullanici_adi"
            REMOTE_HOST="test_sunucu_adresi"
            REMOTE_PATH="/home/remote/project/path"
          fi
          
          ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $REMOTE_USER@$REMOTE_HOST "cd $REMOTE_PATH && git pull origin ${GITHUB_REF##*/}"

SSH_KNOWN_HOSTS : Bu aşağıdaki komutun çıktısıdır.

ssh-keyscan -H your_server_domain

Farklı Sunucular Farklı Ortamlar mı?

Canlı ve test ortamlarını ayırmış olmak da kalbur üstü bir proje için tam olarak geçerli bir senaryo değildir. Muhtemelen böyle bir projede canlı ve test ortamlarının sayısı birden fazla olacaktır. Öyleyse bizde döngüden destek alalım. :D

name: Deploy PHP Application

on:
  push:
    branches:
      - main
      - develop

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: SSH Bağlantısı ve Son Kodun Alınması
        if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
          
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            SERVERS=("canli_sunucu1" "canli_sunucu2" "canli_sunucu3")
            REMOTE_USER="canli_kullanici_adi"
            REMOTE_PATH="/home/remote/project/path"
          elif [ "${{ github.ref }}" == "refs/heads/develop" ]; then
            SERVERS=("test_sunucu1" "test_sunucu2")
            REMOTE_USER="test_kullanici_adi"
            REMOTE_PATH="/home/remote/project/path"
          fi
          
          for SERVER in "${SERVERS[@]}"
          do
          echo "Deploying to $SERVER"
          ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no $REMOTE_USER@$SERVER "cd $REMOTE_PATH && git pull origin ${GITHUB_REF##*/}"
          done

SSH_KNOWN_HOSTS : Bu aşağıdaki komutun çıktısıdır.

ssh-keyscan -H your_server1_domain your_server2_domain your_server3_domain ...

Firewall Kısıtlamaları Nasıl Çözülür?

İşler ciddileşmeye başladı. :D Sunucularınıza erişim için IP kısıtlaması gibi bir kısıtlama olabilir ki bu güvenlik için son derece mantıklıdır. Böyle bir durumda sunucularımıza erişebilecek bir sunucuya (bastion host) ihtiyacımız olacaktır.

Adım 1. SSH anahtarınızı bastion host olarak kullanacağımız sunucuda oluşturuyoruz.

Adım 2. Bastion Host'tan diğer sunuculara erişim sağlayın. "~/.ssh/config" dosyasını açın ve aşağıdaki yapılandırmayı kendinize uygun şekilde düzenleyerek yapıştırın ve kaydedin.

Host sunucu1
    HostName sunucu1_ip
    User kullanici_adi
    IdentityFile ~/.ssh/id_rsa

Host sunucu2
    HostName sunucu2_ip
    User kullanici_adi
    IdentityFile ~/.ssh/id_rsa

# Diğer sunucular için benzer yapılandırma...

Bu durumda deploy.yml dosyası da şöyle değişecektir.

name: Deploy PHP Application

on:
  push:
    branches:
      - main
      - develop

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: SSH Bağlantısı ve Son Kodun Alınması
        if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          BASTION_HOST: ${{ secrets.BASTION_HOST }}
          BASTION_USER: ${{ secrets.BASTION_USER }}
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          
          ssh-keyscan -H ${{ secrets.BASTION_HOST }} >> ~/.ssh/known_hosts
          
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            SERVERS=("canli_sunucu1" "canli_sunucu2" "canli_sunucu3")
            REMOTE_USER="canli_kullanici_adi"
            REMOTE_PATH="/home/remote/project/path"
          elif [ "${{ github.ref }}" == "refs/heads/develop" ]; then
            SERVERS=("test_sunucu1" "test_sunucu2")
            REMOTE_USER="test_kullanici_adi"
            REMOTE_PATH="/home/remote/project/path"
          fi
          
          for SERVER in "${SERVERS[@]}"
          do
          echo "Deploying to $SERVER"
          ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no -J ${{ secrets.BASTION_USER }}@${{ secrets.BASTION_HOST }} $REMOTE_USER@$SERVER "cd $REMOTE_PATH && git pull origin ${GITHUB_REF##*/}"
          done

Hepsi bu kadar demek istedim ancak henüz Github Actions bu kadarla bitecek bir şey değil! :D Bir sonraki yazımda Docker ve Kubernetes ile birlikte Github Actions nasıl kullanılabilir anlatmaya çalışacağım.

Teşekkür ederim!

Bu yazıyı paylaş

Yazar

Muhammet Şafak

Yazılım Mühendisi & Full-Stack Geliştirici. PHP, Laravel ve modern web teknolojileri üzerine yazıyor.

Hakkımda

Yorumlar 0

Henüz yorum yapılmamış.

İlk yorumu siz yapın!

Yorum Yaz

Yorumunuz moderasyon sonrası yayınlanacaktır.

E-posta adresiniz yayınlanmayacaktır.