Сводный пост по мотивам двух статей:

Все скриншоты Atlantis UI и примеры PR-обсуждений см. в оригиналах — здесь только выжимка и код-примеры для быстрого старта.

Проблема, которую решает Atlantis

Знакомые боли команды с Terraform:

Всё это лечится централизацией через Atlantis — open-source-инструментом на Go, который сажает terraform plan / terraform apply прямо в pull request.

Что такое Atlantis

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.

Ключевые фичи

Способ 1: AWS ECS Fargate

Подход из статьи Husain Yusuf . Все компоненты (ALB, ECS Service, IAM-роли, secrets) поднимаются одним Terraform-модулем.

Почему Fargate:

Что понадобится

Ключевой Terraform-модуль

Здесь используется официальный модуль terraform-aws-modules/atlantis/aws . Минимально важный фрагмент:

HCL
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:

HCL
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.

Раскатка

BASH
terraform init
terraform plan
terraform apply
Нажмите, чтобы развернуть и увидеть больше

После — проверяем, что ALB DNS отвечает, и открываем тестовый PR.

Способ 2: Kubernetes через Helm

Подход из статьи Heshan Dharmasena . Гораздо проще — если Kubernetes уже есть.

Установка

BASH
helm repo add runatlantis https://runatlantis.github.io/helm-charts
helm inspect values runatlantis/atlantis > values.yaml
Нажмите, чтобы развернуть и увидеть больше

Минимальный values.yaml

Пример для локального тестирования на self-hosted Gitea:

YAML
# Разрешённые репозитории
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

BASH
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:

YAML
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-деплоя):

  1. Создайте ветку и внесите изменение в Terraform (например, добавьте tag на существующий ресурс).
  2. Откройте PR.
  3. Atlantis автоматически поймает webhook и опубликует комментарий с terraform plan.
  4. Ревьюер аппрувит PR.
  5. Комментарий atlantis apply — Atlantis запускает apply и публикует результат.
  6. Если в atlantis.yaml стоит automerge: true — PR смержится сам.

Если что-то пошло не так — можно отменить блокировку через atlantis unlock в комментарии, либо через web-UI Atlantis.

Безопасность и next steps

Для 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 по прозрачности и скорости ревью инфры измеряется в неделях.

Ссылки

Авторские права

Автор: Vasiliy Fakunin

Ссылка: https://notes.melancholic.tech/posts/atlantis-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-terraform-pr-%D0%BA%D0%B0%D0%BA-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82-%D0%B8-%D0%BA%D0%B0%D0%BA-%D0%B7%D0%B0%D0%B4%D0%B5%D0%BF%D0%BB%D0%BE%D0%B8%D1%82%D1%8C/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша