Atlantis ile Terraform Pull Request Otomasyonu Kurulumu
Laptopından terraform apply atan ekip, bir süre sonra iki problemle karşılaşır. Biri kimin neyi ne zaman uyguladığına dair kayıt tutulmaması, diğeri iki kişinin aynı state üzerinde aynı anda değişiklik yapması. Recruit ekibinin mühendisleri de tam bu yüzden Atlantis'e geçti: aynı ortama aynı anda apply atan kişiler birbirinin kaynağını siliyordu. Atlantis, Terraform işlemlerini pull request yorumlarına taşıyan, kendi sunucunuzda koşan açık kaynak bir araç. PR açıldığında terraform plan çalışıyor, çıktı PR'a yorum olarak düşüyor, onaydan sonra atlantis apply yazınca değişiklik uygulanıyor. Başka hiçbir yere gitmenize gerek kalmıyor.
Neden GitHub Actions yetmiyor
Actions ile de plan ve apply otomatikleştirilebilir, teknik olarak mümkün. Fark uygulama anında ortaya çıkıyor. Merge tetiklemeli pipeline'larda apply patlarsa düzeltme PR'ı açmanız gerekir ve bu arada main branch deploy edilemez durumda kalır. Atlantis ise merge öncesi apply modelini temel alır; branch üzerinde tekrar tekrar plan ve apply deneyebilirsiniz, main her zaman uygulanan konfigürasyonla senkron kalır. Zenn'de yazan bir mühendisin değindiği gibi apply her zaman başarılı olacak diye bir kural yok; kaynak isimlerindeki karakter kısıtları, uzunluk limitleri yüzünden ilk denemede patlamalar sıradan. Tek PR üzerinde deneye deneye ilerlemek, yeni bir düzeltme PR'ı açmaktan daha az yorucu.
İkinci fark kilit mekanizması. Terraform'un kendi state lock'u, iki komutun aynı anda çalışmasını engeller. Atlantis'in kilidi daha üstte durur: bir PR plan yaptığı anda o dizin ve workspace kilitlenir, aynı dizine dokunan başka bir PR plan yapamaz ve kilidi tutan PR'a yönlendirilir. Kilit PR merge edilene, kapatılana ya da atlantis unlock yorumu yapılana kadar tutulur. Kilitleme tüm repoyu değil sadece ilgili dizin ve workspace'i kapsar. Bu, parallel çalışan ekiplerde birinin değişikliğinin diğerininkini götürmesini engeller.
Üçüncüsü yetki meselesi. CI servisine AWS credential vermek zorunda kalırsınız ve genelde geniş yetkili bir IAM anahtarı verirsiniz. Atlantis'i AWS içinde, örneğin ECS Fargate üzerine kurarsanız IAM rolü ile kimliklendirme yapılır, anahtar AWS dışına çıkmaz.
Kurulumun iskeleti
Atlantis tek bir Go binary'si. Webhook dinler, PR olayı gelince repoyu klonlar, Terraform komutlarını çalıştırır, sonucu PR'a yorumlar. Port 4141 üzerinde bir HTTP servisi olarak ayağa kalkar. Docker ile denemek için:
docker run -d \
--name atlantis \
-p 4141:4141 \
-e ATLANTIS_GH_USER="atlantis-bot" \
-e ATLANTIS_GH_TOKEN="ghp_token" \
-e ATLANTIS_GH_WEBHOOK_SECRET="webhook-secret" \
-e ATLANTIS_REPO_ALLOWLIST="github.com/org/*" \
ghcr.io/runatlantis/atlantis:latest server Lokal deneme için resmi dokümantasyon ngrok öneriyor. ngrok http 4141 ile genel bir adres alınır, GitHub tarafında webhook Payload URL olarak bu adresin sonuna /events eklenmiş hali girilir, Content type application/json seçilir. Webhook olaylarından Issue comments, Pull requests, Pushes ve Pull request reviews işaretlenmeli. Sunucu tarafında ise:
atlantis server \
--atlantis-url="$URL" \
--gh-user="$USERNAME" \
--gh-token="$TOKEN" \
--gh-webhook-secret="$SECRET" \
--repo-allowlist="$REPO_ALLOWLIST" --repo-allowlist kritik bir bayrak. Atlantis hangi repolara cevap vereceğini bilmezse, webhook secret bilen herkes sizin sunucunuza istek atıp istediği repoda Terraform çalıştırabilir. github.com/myorg/* gibi desenler kullanılabilir, virgülle birden fazla repo girilebilir, hariç tutmak için !github.com/myorg/untrusted-repo sözdizimi var. Ortam değişkeni kullanacaksanız bayrak adındaki tireler alt çizgiye dönüşür ve başına ATLANTIS_ eklenir: --gh-user → ATLANTIS_GH_USER. Öncelik sırası bayrak, ortam değişkeni, config dosyası şeklinde.
Kimliklendirme: PAT mi GitHub App mi
İki yol var. Kişisel erişim anahtarı kurulumu basittir, atlantis-bot gibi bir makine kullanıcısı açıp token üretirsiniz. Üretim için önerilen GitHub App tarafı: rate limit durumları daha rahat, izinler daha ince taneli. App oluştururken webhook URL'sini Atlantis adresinin /events yoluna verirsiniz, private key indirip şu bayraklarla başlatırsınız:
atlantis server \
--gh-app-id=12345 \
--gh-app-key-file=/path/to/private-key.pem \
--gh-app-slug=atlantis-terraform \
--gh-webhook-secret=secret \
--repo-allowlist="github.com/myorg/*" GitLab, Bitbucket, Azure DevOps ve Gitea da destekleniyor, sadece bayrak adları değişir: --gitlab-token, --bitbucket-token, --azuredevops-token gibi.
atlantis.yaml ile davranışı şekillendirmek
Repoyu Atlantis yönetimine almak için reponun köküne atlantis.yaml koymak yeterli. En küçük haliyle:
version: 3
projects:
- dir: project1
autoplan:
when_modified: ["*.tf*"] Bu, project1 altındaki .tf dosyaları değiştiğinde otomatik plan tetikler. Monorepoda birden fazla Terraform dizini varsa her birine ayrı proje tanımı girilir. Ortak modülleriniz varsa when_modified listesine modül yollarını ekleyin:
version: 3
projects:
- name: dev
dir: environments/dev
autoplan:
when_modified: ["*.tf", "*.tfvars", "../../modules/**/*.tf"]
enabled: true
apply_requirements: [approved, mergeable]
- name: production
dir: environments/production
autoplan:
when_modified: ["*.tf", "*.tfvars", "../../modules/**/*.tf"]
enabled: true
apply_requirements: [approved, mergeable] apply_requirements listesi uygulama kapısını belirler. approved, PR onaylanmadan apply çalışmaz demek. mergeable, status check'lerin geçmiş olmasını şart koşar. undiverged ise branch'in main ile güncel olmasını zorunlu kılar; eski bir planı apply etmenin önüne geçer. Bu üçünü birlikte kullanmak çoğu ekip için makul bir başlangıç.
Autoplan davranışını sunucu tarafında da ayarlayabilirsiniz. --autoplan-file-list bayrağı hangi dosya desenlerinin plan tetikleyeceğini kontrol eder, varsayılanı **/*.tf,**/*.tfvars ve benzeri tüm Terraform dosyaları. Modül değişikliklerinin tetiklemesini istiyorsanız --autoplan-modules bayrağını açmanız gerekir, varsayılan kapalıdır. Dikkat: Qiita'daki bir yazarın yaşadığı gibi modül dizininde her provider güncellemesinde tüm working directory'lerde plan koşması ve hepsinin kilitlenmesi can sıkıcı olabilir. Recruit ekibi bunu modüllerde required_providers sürümü sabitlememekle çözmüş.
Workspace ve tfvars otomasyonu
Atlantis workspace'e özel tfvars dosyalarını kendiliğinden algılar. Proje dizininde env/staging.tfvars varsa atlantis plan -w staging yorumu bu dosyayı otomatik -var-file ile ekler. Ekstra konfigürasyon gerekmez. Plan çıktıları diskte saklanır; apply, planı yeniden üretmek yerine kayıtlı plan dosyasını oynatır. Bu yüzden apply sırasında vereceğiniz plan değiştiren bayraklar yok sayılır.
Komutlar
Günlük kullanımdaki komut seti kompakt:
atlantis planplanı tetikler.-d dizinile belirli dizin,-p projeile atlantis.yaml'daki isimli proje,-w workspaceile workspace seçilir.atlantis applykayıtlı planı uygular. Hedef belirtilmezse Atlantis kök dizin için üretilmiş planı uygulamayı dener;-d,-p,-wbayraklarıyla belirli planı seçebilirsiniz.atlantis unlockkilidi bırakır.atlantis importveatlantis state rmmevcut kaynakları state'e almak için kullanılır; import sonrası yeniden plan gerekir.
Terraform'a parametre geçmek için -- sonrası kullanılır: atlantis plan -- -target=aws_instance.example -var 'foo=bar'.
Custom workflow ile policy katmanı
Varsayılan adımlar yetmediğinde workflows bölümüyle kendi zincirinizi kurarsınız. Plan adımları arasına tflint, checkov, conftest sokmak yaygın. Conftest senaryosunda plan JSON'a dökülür, Rego ile yazılmış politikalar bunun üzerinde koşar; mesela S3 bucket isminde alt çizgi yasaklayan bir kural. Recruit'in konfigürasyonunda her ortam için ayrı IAM rolü env adımıyla enjekte edilmiş:
workflows:
dev:
plan:
steps:
- env:
name: AWS_ROLE_ARN
value: "arn:aws:iam::123456789012:role/atlantis-plan-role-dev"
- init
- plan
policy_check:
steps:
- show
- run: conftest test -p ../../../conftest-policies/aws $SHOWFILE Repoda tanımlı custom workflow'ların çalışabilmesi için sunucu tarafındaki repos.yaml içinde allow_custom_workflows: true ve allowed_overrides: [workflow] ayarlanmalı. Bu yetkiyi sınırlamak istiyorsanız sunucu konfigürasyonunda kapatıp repo tarafında geçersiz kılınabilir alanları daraltırsınız.
Tek replika zorunluluğu ve veri
Atlantis yatay ölçeklenmez. Kilitler, plan dosyaları ve checkout edilen repolar --data-dir altında tutulur; Helm chart StatefulSet ile tek replika olarak dağıtır ve bir PVC ister. Pod yeniden başladığında bu hacim kaybolursa uçan planlar gider. Kubernetes'e kurulum için helm repo add runatlantis https://runatlantis.github.io/helm-charts ile başlayıp GitHub bilgilerini ve orgAllowlist değerlerini set etmeniz yeterli. AWS tarafında topluluk modülü terraform-aws-modules/atlantis işi bitirir: ECS Fargate servisi, ALB, güvenlik grupları, log grupları hepsini kurar, secret'ları Secrets Manager'dan enjekte eder.
Güvenlik tarafında düşünülmesi gerekenler
--allow-fork-prs bayrağı varsayılan olarak kapalıdır ve iyi ki öyle. Fork'tan gelen bir PR, Atlantis'e kötü niyetli bir Terraform konfigürasyonu üzerinden istediği kodu çalıştırma şansı verir; çünkü plan aşamasında bile keyfi kod çalıştırılabilir. Webhook tarafında trafik GitHub'ın IP aralıklarına daraltılabilir. GUI tarafında ise uzun süre hiç kimliklendirme yoktu; Atlantis'e sonradan kendi içinde Basic Auth desteği eklendi, /healthz endpoint'i sağlık kontrolü için auth dışında tutulur. Terraform Cloud ya da benzeri bir SaaS istemiyorsanız, PR yorumları üzerinden yürüyen bu model ekip ölçeğinde ciddi yük alıyor. Kilit, onay kapısı, kayıtlı plan, hepsi tek binary içinde.