Операційна автоматизація з Ansible на AWS інфраструктурі керованій Terraform

Операційна автоматизація з Ansible на AWS інфраструктурі керованій Terraform

Виклик операційної автоматизації

Infrastructure as Code з Terraform вирішує проблему provisioning інфраструктури—створення VPC, баз даних, контейнерних кластерів—але production системи вимагають поточних операційних завдань, які виходять за межі декларативної моделі Terraform. Seeding бази даних, конфігурація додатків, операції на рівні контейнерів та динамічне управління середовищами вимагають імперативної автоматизації, яка реагує на runtime умови замість декларування бажаного стану.

Операційні завдання, які Terraform не може ефективно виконувати:

  • Операції з базою даних: Виконання міграцій, seeding даних, управління схемами для кожного середовища
  • Управління контейнерами: Виявлення запущених контейнерів, виконання команд, streaming логів
  • Отримання секретів: Завантаження credentials з Parameter Store під час виконання
  • Динамічне виявлення: Пошук ресурсів інфраструктури без hardcoded конфігурації
  • Робочі процеси для конкретних середовищ: Різні операції для розробки vs production

Виклик інтеграції: Як операційні інструменти виявляють та взаємодіють з динамічно provisioned інфраструктурою без підтримки статичної конфігурації, яка дрейфує від реальності?

Ключові результати:

  • Автоматизований database seeding для всіх середовищ (30 хвилин → 5 хвилин)
  • Нульова статична конфігурація через динамічне виявлення ECS хостів
  • Секрети ніколи не зберігаються в коді (100% отримання з SSM Parameter Store)
  • Environment-agnostic playbooks (єдиний код для всіх середовищ)
  • 95% операційна повторюваність через кодифіковані робочі процеси

Архітектура: інтеграція Terraform + Ansible

Terraform та Ansible виконують комплементарні ролі в управлінні інфраструктурою: Terraform provisioning immutable інфраструктури декларативно, Ansible виконує mutable операції імперативно. Патерн інтеграції використовує resource tagging та AWS APIs як контракт між інструментами.

RDSECSSSMTagsECS APISSM APIEC2 APIDiscoverySecretsDB SeedingContainer OpsCloud InfrastructureTerraformAWS APIsAnsible

Terraform provisioning інфраструктури:

  • VPC, підмережі, security groups, таблиці маршрутизації
  • RDS PostgreSQL з Multi-AZ конфігурацією
  • ECS кластери, task definitions, сервіси
  • ECR container registry з lifecycle policies
  • S3 buckets, CloudFront distributions
  • IAM ролі, security groups, load balancers
  • Заповнення SSM Parameter Store секретами
  • Консистентний resource tagging (app_name, environment)

Ansible виконує операції:

  • Налаштування схеми бази даних та seeding
  • Виявлення ECS контейнерів та виконання команд
  • Отримання параметрів SSM для runtime конфігурації
  • Міграції та deployments на рівні додатка
  • Мультисередовищні операційні робочі процеси
  • Завдання обслуговування та troubleshooting
  • Запити до ECS API для запущених tasks фільтрованих за тегами
  • Розв'язання ланцюжка task → container instance → EC2 instance
  • Побудова динамічного inventory без статичних файлів

Integration Pattern

Контракт:

  1. Terraform provisioning інфраструктури з консистентними тегами
  2. Terraform зберігає секрети в SSM Parameter Store за шаблоном іменування
  3. Ansible виявляє ресурси через AWS APIs використовуючи фільтри за тегами
  4. Ansible отримує секрети з SSM використовуючи сконструйовані шляхи параметрів
  5. Ansible виконує операції на виявлених ресурсах
  6. Немає hardcoded деталей інфраструктури в коді Ansible

Data Flow:

Parameter StoreAnsibleAWS InfrastructureTerraformParameter StoreAnsibleAWS InfrastructureTerraformProvision ECS cluster with tagsStore database credentialsQuery ECS API (filter by tags)Return running tasks + instancesDescribe EC2 instancesReturn instance IPsGet parameters (constructed path)Return decrypted secretsSSH/SSM to instancesExecute operations in containers

Переваги:

  • Зміни інфраструктури автоматично відображаються в Ansible
  • Немає статичних inventory файлів для підтримки
  • Секрети ніколи в коді або version control
  • Єдиний playbook працює для всіх середовищ
  • Конфігураційний дрейф неможливий (завжди запитує поточний стан)

Реалізація: Terraform Output → Ansible Input

Реалізація встановлює інтеграцію через Terraform resource tagging та Ansible playbooks динамічного виявлення.

Terraform конфігурація для Ansible

Налаштування SSM Parameter Store:

Terraform створює параметри за передбачуваною конвенцією іменування, яку Ansible може сконструювати:

# terraform/ssm.tf
resource "aws_ssm_parameter" "postgres_host" {
  name  = "/${var.app_name}/${var.env}/POSTGRES_HOST"
  type  = "String"
  value = data.terraform_remote_state.shared.outputs.rds_address
}

resource "aws_ssm_parameter" "postgres_password" {
  name  = "/${var.app_name}/${var.env}/POSTGRES_PASSWORD"
  type  = "SecureString"
  value = "${var.db_password}_${var.env}"
}

Шаблон іменування параметрів:

/${app_name}/${environment}/${parameter_name}

Приклади:

  • /terraform-letscommerce/dev/POSTGRES_HOST
  • /terraform-letscommerce/prod/POSTGRES_PASSWORD

Конфігурація ECS Service:

# terraform/ecs.tf
resource "aws_ecs_service" "app" {
  name            = "${var.app_name}-${var.env}-ecs-service"
  cluster         = "${var.app_name}-ecs-cluster"
  task_definition = aws_ecs_task_definition.app.arn
  desired_count   = var.task_count

  tags = {
    Application = var.app_name
    Environment = var.env
  }
}

Структура проекту Ansible

ansible/
├── site.yml                       # Головний orchestration playbook
├── get-ecs-hosts.yml             # Динамічне виявлення ECS хостів
├── get-ssm-db-params.yml         # Отримання параметрів SSM
├── get-docker-container.yml      # Виявлення контейнерів на хостах
├── exec-in-container.yml         # Загальне виконання команд
├── seed-db-sql.yml               # SQL ініціалізація бази даних
├── seed-db-sequelize.yml         # ORM-based міграції/seeding
└── connect-test.yml              # Перевірка connectivity

Головний Orchestration (site.yml):

---
# 1. Виявлення інфраструктури
- import_playbook: get-ecs-hosts.yml

# 2. Тестування connectivity
- import_playbook: connect-test.yml

# 3. Отримання конфігурації
- import_playbook: get-ssm-db-params.yml

# 4. Операції з контейнерами
- import_playbook: get-docker-container.yml
- import_playbook: exec-in-container.yml

# 5. Операції з базою даних
- import_playbook: seed-db-sql.yml
- import_playbook: seed-db-sequelize.yml

Патерн динамічного Inventory

Патерн виявлення ECS хостів:

1. Запит до ECS API для запущених tasks
   → Фільтрація за: cluster name + service name + environment tag
   → Повертає: List of task ARNs

2. Отримання ARN container instances з tasks
   → Вхід: Task ARNs
   → Повертає: Container instance ARNs

3. Розв'язання EC2 instance IDs
   → Вхід: Container instance ARNs
   → Повертає: EC2 instance IDs

4. Отримання EC2 instance IPs
   → Вхід: EC2 instance IDs
   → Повертає: Public/Private IP addresses

5. Додавання до динамічного inventory
   → Побудова in-memory inventory
   → Статичні файли не потрібні

Ключовий момент: Ланцюжок виявлення розв'язує: Service → Tasks → Container Instances → EC2 Instances → IPs

Патерн отримання параметрів SSM:

1. Конструювання шляху параметра зі змінних
   → Шаблон: /{app_name}/{environment}/{parameter}
   → Приклад: /terraform-letscommerce/dev/POSTGRES_HOST

2. Запит до SSM Parameter Store
   → Запит дешифрування для SecureString параметрів
   → Повертає: Значення параметрів

3. Побудова об'єкта конфігурації
   → Збирання всіх параметрів в структуровану конфігурацію
   → Доступна для всіх наступних playbooks

Переваги:

  • Той самий код отримує dev/staging/prod параметри (змінна середовища вибирає)
  • Секрети дешифруються під час виконання, ніколи не зберігаються в коді
  • Terraform оновлює параметри → Ansible бачить зміни негайно

Операційні робочі процеси

Production операції кодифіковані як повторювані Ansible playbooks, які виявляють інфраструктуру динамічно та виконують завдання специфічні для середовища.

Робочий процес 1: Database Seeding

Процес:

1. Підключення до виявлених ECS хостів
   → Використовує динамічний inventory з фази виявлення

2. Пошук цільового Docker контейнера
   → Збіг за шаблоном імені контейнера
   → Збереження container ID для операцій

3. Виявлення директорії додатка
   → Пошук загальних шляхів (/app, /usr/src/app, /opt/app)
   → Ідентифікація за наявністю package.json

4. Виконання міграцій бази даних
   → Виконання: docker exec {container} sequelize db:migrate
   → Виконується у всіх середовищах

5. Seeding бази даних (умовно)
   → Виконання: docker exec {container} sequelize db:seed:all
   → Тільки в development середовищі

Логіка для конкретних середовищ:

  • Development: Міграції + повний data seeding
  • Staging: Міграції + мінімальні тестові дані
  • Production: Тільки міграції (без seeding)

Робочий процес 2: операції з контейнерами

Патерн:

1. Виявлення контейнера
   → Запит до Docker daemon на ECS хостах
   → Фільтрація за шаблоном імені контейнера (ecs-*-server)
   → Збереження container ID для операцій

2. Виконання команди
   → Виконання: docker exec {container_id} {command}
   → Захоплення та повернення output
   → Логування результатів для аудиту

3. Загальні операції
   → Очищення application cache
   → Rebuild search indexes
   → Генерація звітів
   → Health checks
   → Debug production issues

Робочий процес 3: повне налаштування середовища

Процес виконання:

1. Infrastructure Discovery
   → Пошук ECS хостів з запущеними tasks для середовища
   → Побудова динамічного inventory

2. Перевірка Connectivity
   → Перевірка SSH доступу до виявлених хостів
   → Тестування мережевої connectivity

3. Отримання Secrets
   → Завантаження database credentials з SSM
   → Дешифрування secure параметрів

4. Ідентифікація контейнерів
   → Виявлення application контейнерів на хостах
   → Збереження container IDs

5. Операції з базою даних
   → Виконання міграцій (всі середовища)
   → Seed даних (тільки development)

6. Валідація
   → Підтвердження успішності всіх операцій
   → Генерація audit log

Порівняння часу:

  • Manual: 30-45 хвилин (схильний до помилок, не повторюваний)
  • Automated: 5 хвилин (консистентний, повторюваний, з аудитом)

Патерни динамічного виявлення

Динамічне виявлення усуває статичну конфігурацію шляхом запитів до AWS APIs для визначення поточного стану інфраструктури під час виконання.

Розв'язання ECS до EC2

Ланцюжок виявлення:

   aws ecs list-tasks   

   aws ecs describe-tasks   

   ECS Service Name   

   Task ARNs   

   Container Instance ARNs   

   aws ec2 describe-instances   

   ansible add_host   

   EC2 Instance IDs   

   EC2 IP Addresses   

   Ansible Inventory   

Flow: ECS Service → Tasks → Container Instances → (aws ecs describe-container-instances) → EC2 IDs → IPs → Ansible Inventory

Чому це важливо:

  • ECS tasks можуть переміщатися між instances
  • Instances можуть бути замінені auto-scaling
  • IP адреси змінюються при recreation instance
  • Статичний inventory стає застарілим негайно

Динамічне виявлення гарантує:

  • Завжди підключається до поточно запущених instances
  • Адаптується до scaling подій автоматично
  • Виживає заміни instances
  • Не потрібні ручні оновлення inventory

Виявлення контейнерів

Виклик: Кілька контейнерів запущені на кожному ECS instance. Який контейнер містить додаток?

Патерн виявлення:

- name: Find application container
  become: true
  shell: >
    docker ps
    --filter "label=com.amazonaws.ecs.task-definition-family={{ app_name }}-{{ env }}"
    --format "{{ '{{' }}.ID{{ '}}' }}"
  register: container_id

Критерії виявлення:

  • ECS task definition family labels
  • Шаблони імен контейнерів
  • Фільтр running state
  • Вибір першого збігу

Результат: Встановлена змінна target_container для всіх наступних операцій

Виявлення параметрів SSM

Конструювання шляху параметра:

# Змінні
app_name: terraform-letscommerce
env: dev
parameter: POSTGRES_HOST

# Сконструйований шлях
parameter_path: '/{{ app_name }}/{{ env }}/{{ parameter }}'
# Результат: /terraform-letscommerce/dev/POSTGRES_HOST

Переваги:

  • Немає hardcoded імен параметрів
  • Environment-specific значення автоматичні
  • Terraform та Ansible використовують однакову конвенцію іменування
  • Додавання нових параметрів не вимагає змін Ansible

Безпека:

  • SecureString параметри зашифровані у спокої
  • Дешифрування з прапором --with-decryption
  • IAM policies контролюють доступ per environment
  • Секрети ніколи не з'являються в коді чи логах

Результати та уроки

Ключові метрики

Операційна ефективність:

  • Час database seeding: 30 хвилин → 5 хвилин (83% скорочення)
  • Налаштування середовища: 2 години → 10 хвилин (повна операційна готовність)
  • Конфігураційний дрейф: 0% (динамічне виявлення запобігає застарілій конфігурації)
  • Операційна повторюваність: 95% (кодифіковані робочі процеси, консистентне виконання)
  • Ручне втручання: Зменшено з 10+ кроків до однієї команди

Операційний вплив:

  • Provisioning нового середовища: Інфраструктура (Terraform) + операції (Ansible) повністю автоматизовані
  • Disaster recovery: Повне відтворення середовища з коду
  • Onboarding команди: Операції документовані як виконуваний код
  • Debugging: Стандартизовані робочі процеси для інспекції контейнерів та troubleshooting

Що спрацювало

Патерн динамічного inventory: Нульова статична конфігурація, автоматична адаптація до змін інфраструктури

Tag-based виявлення: Terraform теги стають Ansible query фільтрами—простий, надійний контракт

Інтеграція параметрів SSM: Секрети ніколи в коді, автоматичне environment-specific отримання

Idempotent операції: Database seeding безпечний для повторного виконання, міграції відстежують стан

Патерн єдиного playbook: Одна кодова база для всіх середовищ, параметр середовища вибирає поведінку

Розділення Terraform + Ansible: Чіткі обов'язки запобігають перекриттю інструментів та плутанині

Підводних каменів уникати

Hardcoding деталей інфраструктури: IP, hostnames, container IDs в playbooks гарантують застарілу конфігурацію

Статичні inventory файли: Стають застарілими негайно коли ECS масштабується або instances заміняються

Неконсистентний tagging: Terraform ресурси без стандартних тегів ламають discovery запити

Відсутні IAM permissions: Ansible потребує ECS:Describe*, EC2:Describe*, SSM:GetParameter permissions

Non-idempotent операції: Database операції, які падають при повторному виконанні, запобігають автоматизації

Ігнорування обробки помилок: Production операції потребують комплексного виявлення збоїв та звітування

Висновок

Операційна автоматизація з Ansible доповнює Terraform provisioning інфраструктури, обробляючи імперативні завдання, які вимагають runtime state awareness. Патерн інтеграції—Terraform provisioning з тегами, Ansible виявляє динамічно—усуває статичну конфігурацію та запобігає дрейфу.

Шлях реалізації:

  1. Встановити Terraform стратегію tagging (app_name, environment на всіх ресурсах)
  2. Створити SSM параметри з передбачуваною конвенцією іменування
  3. Реалізувати playbook виявлення ECS хостів
  4. Побудувати отримання параметрів SSM для секретів
  5. Розробити playbooks операційних робочих процесів (база даних, контейнери)
  6. Тестувати в development, валідувати в staging, deploy в production

Коли це має сенс:

  • Управління операційними завданнями поза provisioning інфраструктури
  • Мультисередовищні AWS deployments, що вимагають консистентних операцій
  • Команди, які кодифікують операційні знання для повторюваності
  • Потреба в автоматизованому database seeding, міграціях, операціях з контейнерами
  • Організації, що усувають ручні операційні процедури

Ресурси: