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?

Workflow: Bir veya birden fazla job içeren en üst seviye yapı. .github/workflows dizininde bulunur.

Job: Bir veya birden fazla adım (step) içeren bir işlem. Aynı veya farklı makinelerde (runner) çalıştırılabilir.

Step: Belirli bir görevi gerçekleştiren bir komut veya aksiyon.

Action: Yeniden kullanılabilir adımlardan oluşan küçük işlevler. GitHub Marketplace'te bulunabilir veya kendi aksiyonlarınızı yazabilirsiniz.

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 "yourmail@example.com"

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!