Сводный пост по мотивам двух статей:
- Streamlining Terraform PR Automation with Atlantis on ECS Fargate — Husain Yusuf, апрель 2025.
- Terraform Automation Using Atlantis — Heshan Dharmasena, февраль 2025.
Все скриншоты Atlantis UI и примеры PR-обсуждений см. в оригиналах — здесь только выжимка и код-примеры для быстрого старта.
Проблема, которую решает Atlantis
Знакомые боли команды с Terraform:
- каждый инженер запускает
terraform applyсо своей машины и своей версией CLI; - нет видимости, что именно катится в инфру и кем;
- ревью и apply — ручные, легко забыть после аппрува;
- state-lock конфликты, когда двое одновременно правят один env.
Всё это лечится централизацией через Atlantis — open-source-инструментом на Go, который сажает terraform plan / terraform apply прямо в pull request.
Что такое Atlantis
- Open source, self-hosted, написан на Go — runatlantis.io .
- Интегрируется с VCS через webhook: GitHub, GitLab, Bitbucket, Gitea, Azure DevOps.
- На PR запускает
terraform planи комментирует результат прямо в диалоге ревью. - После аппрува по команде
atlantis applyв комментарии — раскатывает изменения. - Не привносит свой отдельный UI — вся операционка идёт через привычный GitHub/GitLab PR-флоу.
- Управление конфигурацией репозитория — через файл
atlantis.yamlв корне проекта.
Workflow: plan и apply
sequenceDiagram
autonumber
participant Dev as Разработчик
participant Git as VCS (GitHub / Gitea / ...)
participant Atl as Atlantis
participant Cloud as Провайдер
Dev->>Git: Открывает PR с изменением Terraform
Git->>Atl: Webhook (pull_request)
Atl->>Cloud: terraform plan
Cloud-->>Atl: Результат plan
Atl->>Git: Комментарий с планом в PR
Dev->>Git: Ревью + аппрув
Dev->>Git: Комментарий: atlantis apply
Git->>Atl: Webhook (comment)
Atl->>Cloud: terraform apply
Cloud-->>Atl: Результат apply
Atl->>Git: Комментарий с результатом apply
Git->>Git: PR мержится (auto/manual)
Ключевой момент: state автоматически лочится на уровне проекта. Пока один PR не докатился до apply-или-отмены, никакой другой PR по этому же проекту не сможет запустить plan.
Ключевые фичи
- Автоматизация plan/apply — на каждое изменение PR.
- VCS-агностика — единый механизм webhook для всех Git-хостингов.
- State locking — исключает race между PR по одному проекту.
- RBAC — можно ограничить, кто имеет право запускать
apply. - Кастомные workflow — разные шаги для разных папок в одном репозитории (описываются в
atlantis.yaml). - Аудит — все действия остаются в истории PR и коммитов.
- Только read-доступ к репо — Atlantis не пишет в исходники, только читает их и комментирует PR.
Способ 1: AWS ECS Fargate
Подход из статьи Husain Yusuf . Все компоненты (ALB, ECS Service, IAM-роли, secrets) поднимаются одним Terraform-модулем.
Почему Fargate:
- Serverless — не надо возиться с EC2.
- Auto-scaling по нагрузке.
- Изоляция — Atlantis живёт в своём контейнере.
- Оплата по факту использования.
Что понадобится
- AWS-аккаунт, VPC с public + private subnets.
- GitHub App:
App ID,Installation ID,Private Key. - Webhook secret.
- (желательно) домен в Route53 для HTTPS.
Ключевой Terraform-модуль
Здесь используется официальный модуль terraform-aws-modules/atlantis/aws
. Минимально важный фрагмент:
resource "aws_cloudwatch_log_group" "atlantis" {
name = "/ecs/atlantis"
retention_in_days = 7
}
module "atlantis" {
source = "terraform-aws-modules/atlantis/aws"
version = "4.4.0"
vpc_id = var.vpc_id
service_subnets = var.private_subnets_id
name = "atlantis"
atlantis = {
environment = [
{ name = "ATLANTIS_REPO_ALLOWLIST", value = join(",", var.atlantis_repo_allowlist) },
{ name = "ATLANTIS_GH_APP_ID", value = var.github_app_id },
{ name = "ATLANTIS_GH_APP_INSTALLATION_ID", value = var.github_app_installation_id },
{ name = "ATLANTIS_ATLANTIS_URL", value = "https://${var.route53_record_name}" },
{ name = "ATLANTIS_LOG_LEVEL", value = "debug" },
]
secrets = [
{ name = "ATLANTIS_GH_WEBHOOK_SECRET", valueFrom = aws_secretsmanager_secret_version.github_webhook_secret.arn },
{ name = "ATLANTIS_GH_APP_KEY", valueFrom = aws_secretsmanager_secret_version.github_app_private_key.arn },
]
}
service = {
enable_execute_command = true
task_exec_iam_role_name = "atlantis-task-execution-role"
tasks_iam_role_name = "atlantis-tasks-role"
tasks_iam_role_policies = var.tasks_iam_role_policies
}
alb_subnets = var.public_subnets_id
certificate_domain_name = var.certificate_domain_name
route53_record_name = var.route53_record_name
route53_zone_id = var.route53_zone_id
create_alb = var.create_alb
}Секреты
GitHub App private key и webhook secret кладём в AWS Secrets Manager — Atlantis-контейнер подхватит их через secrets-блок в task definition:
resource "aws_secretsmanager_secret" "github_app_private_key" {
name = "github_app_private_key"
}
resource "aws_secretsmanager_secret_version" "github_app_private_key" {
secret_id = aws_secretsmanager_secret.github_app_private_key.id
secret_string = var.github_app_private_key
}
resource "aws_secretsmanager_secret" "github_webhook_secret" {
name = "github_webhook_secret"
}
resource "aws_secretsmanager_secret_version" "github_webhook_secret" {
secret_id = aws_secretsmanager_secret.github_webhook_secret.id
secret_string = var.github_webhook_secret
}Webhook в GitHub
Можно завести из Terraform (у автора для этого есть модуль-обёртка ./tf-modules/github-repository-webhook), либо вручную в настройках репозитория. Endpoint — <atlantis_url>/events.
Раскатка
terraform init
terraform plan
terraform applyПосле — проверяем, что ALB DNS отвечает, и открываем тестовый PR.
Способ 2: Kubernetes через Helm
Подход из статьи Heshan Dharmasena . Гораздо проще — если Kubernetes уже есть.
Установка
helm repo add runatlantis https://runatlantis.github.io/helm-charts
helm inspect values runatlantis/atlantis > values.yamlМинимальный values.yaml
Пример для локального тестирования на self-hosted Gitea:
# Разрешённые репозитории
orgAllowlist: "gitea.localhost/*"
# Аутентификация в Gitea
gitea:
user: atlantis-bot
token: <token из Gitea>
secret: <webhook secret>
baseUrl: "http://localhost:3001"
atlantisUrl: "http://localhost:4141"
service:
type: NodePort
port: 4141
nodePort: 4141
ingress:
enabled: false
# Настройки поведения репозиториев
repoConfig: |
---
repos:
- id: /.*/
allow_custom_workflows: true
allowed_overrides: [workflow]
apply_requirements: [approved]
workflows:
default:
plan:
steps: [init, plan]
apply:
steps: [apply]
resources:
requests:
memory: 1G
cpu: 100m
limits:
memory: 1G
cpu: 200m
volumeClaim:
enabled: true
storageClassName: standard
size: 1GiОбратите внимание на apply_requirements: [approved] — apply запустится только после аппрува PR. И на volumeClaim — Atlantis хранит на PVC информацию о lock’ах и рабочие каталоги.
Применяем и port-forward
helm upgrade --install atlantis runatlantis/atlantis -f values.yaml
kubectl port-forward pod/atlantis-0 4141:4141Открываем http://localhost:4141 — простой frontend со списком активных lock’ов.
atlantis.yaml в репозитории
Файл в корне репо, описывает проекты и workflow:
version: 3
automerge: true
projects:
- name: project_1
terraform_version: terraform1.10.5
dir: project_1/
workflow: project_1
workflows:
project_1:
plan:
steps:
- run: terraform1.10.5 init
- plan:
extra_args: [-var-file=env/dev.tfvars]
apply:
steps:
- applyТакой файл позволяет держать несколько terraform-проектов в одном репозитории с разными версиями Terraform и разными наборами tfvars.
Тестирование
Универсальный сценарий (одинаково работает и для ECS Fargate, и для Kubernetes-деплоя):
- Создайте ветку и внесите изменение в Terraform (например, добавьте tag на существующий ресурс).
- Откройте PR.
- Atlantis автоматически поймает webhook и опубликует комментарий с
terraform plan. - Ревьюер аппрувит PR.
- Комментарий
atlantis apply— Atlantis запускает apply и публикует результат. - Если в
atlantis.yamlстоитautomerge: true— PR смержится сам.
Если что-то пошло не так — можно отменить блокировку через atlantis unlock в комментарии, либо через web-UI Atlantis.
Безопасность и next steps
- Не давать Atlantis прав больше, чем нужно. IAM-политика на
tasks_iam_role_policies(ECS) или ServiceAccount (K8s) должны совпадать с реальной потребностью Terraform-модулей. apply_requirements: [approved]— обязательный минимум для чувствительных env.- Отдельный ServiceAccount / IRSA / instance profile на env — не давать одному Atlantis доступ и в dev, и в prod без изоляции.
- Webhook-секреты в SSM / Secrets Manager / Sealed Secrets — не в git.
- HTTPS + Basic Auth или SSO для веб-эндпоинта Atlantis.
Для multi-account AWS-схем следующая логичная тема — role assumption через terraform.tfvars + provider-блоки, но это уже отдельный пост.
Итог
Atlantis — простой и эффективный способ уйти от локального terraform apply к прозрачному GitOps-подходу без необходимости уходить в SaaS вроде Terraform Cloud или Spacelift. Развернуть можно и в AWS ECS Fargate одним модулем из registry, и в Kubernetes одним helm install. Настройка — 30-60 минут, а ROI по прозрачности и скорости ревью инфры измеряется в неделях.