Вернуться к главной странице, списку всех тем
7. Автоматическое создание, настройка и обновление множества ресурсов в облаке
В предыдущем уроке мы создавали виртуальные машины, базы и хранилища кликами в облачной консоли или CLI-командами. Это работает, пока у тебя один-два сервера. Но что, если завтра нужно поднять 50 серверов, по 10 баз данных, 20 балансировщиков, и точно так же повторить всё это в трёх окружениях — dev, staging, prod? Кликать руками — это сотни часов работы и гарантированные ошибки.
Представь, что у тебя есть рецепт пирога, записанный на бумаге. Ты можешь приготовить по нему пирог дома, можешь дать рецепт другу — он приготовит точно такой же. А можно загрузить рецепт в робота-кондитера — и он будет печь идентичные пироги в любом количестве. Точно так же работает Infrastructure as Code (IaC) — инфраструктура как код: ты описываешь нужную инфраструктуру в текстовых файлах, а инструменты автоматически создают её в облаке.
Двумя самыми популярными инструментами IaC являются:
- Terraform (и его открытый форк OpenTofu) — создаёт ресурсы в облаке: ВМ, сети, базы, кластеры Kubernetes.
- Ansible — настраивает уже существующие машины: ставит программы, кладёт конфиги, перезапускает сервисы.
Они дополняют друг друга. Сначала Terraform создаёт «коробку» (саму ВМ), потом Ansible заходит внутрь по SSH и устанавливает там nginx, базу, обновляет пакеты.
Что такое Infrastructure as Code
IaC — это подход, при котором всю инфраструктуру (серверы, сети, базы, права доступа) описывают в текстовых файлах, хранят в Git, и применяют через автоматизированные инструменты. Главные принципы:
- Декларативность — ты описываешь, что должно быть («3 ВМ, 1 балансировщик, 1 БД»), а не как это сделать пошагово. Инструмент сам разберётся.
- Идемпотентность — повторное применение одного и того же кода ничего не ломает. Если ВМ уже есть — она не пересоздаётся.
- Версионирование — вся инфраструктура в Git, видна полная история: кто, когда и почему её менял.
- Воспроизводимость — одним и тем же кодом можно развернуть dev, staging, prod, и они будут идентичны.
- Code review — изменения инфраструктуры проходят через Pull Request, как обычный код. Это резко снижает количество ошибок.
Terraform — создание ресурсов в облаке
Terraform — инструмент от компании HashiCorp, который умеет работать с сотнями облачных провайдеров через специальные модули — providers: yandex-cloud, aws, azurerm, kubernetes, postgresql, github и т. д.
⚠️ Важный нюанс 2024–2026. В августе 2023 года HashiCorp поменяла лицензию Terraform с открытой Mozilla Public License на закрытую Business Source License (BSL), что вызвало недовольство сообщества. В результате появился открытый форк — OpenTofu, поддерживаемый Linux Foundation. Синтаксис и команды идентичны (
tofu plan,tofu applyвместоterraform plan,terraform apply), большинство модулей совместимы. В российских компаниях и open-source проектах сейчас активно мигрируют на OpenTofu. Дальше в этом уроке мы пишем «Terraform», но всё то же самое относится и к OpenTofu.
Основные понятия Terraform
- Provider — модуль для работы с конкретным облаком (например,
yandexилиaws). Подключается в коде, после чего Terraform умеет создавать ресурсы этого облака. - Resource — описание одного ресурса в облаке: ВМ, диска, сети, балансировщика.
- Data Source — способ «прочитать» уже существующий ресурс (например, готовый образ ОС), не создавая его.
- Variable — переменная, чтобы один и тот же код можно было применить с разными значениями (например,
vm_count = 3для dev,vm_count = 20для prod). - Output — значение, которое Terraform «отдаёт наружу» после применения (например, IP-адрес созданной ВМ).
- State (состояние) — файл
terraform.tfstate, в котором Terraform запоминает, какие ресурсы он уже создал. Это критически важный файл, без него Terraform «забывает» обо всех созданных ресурсах. Хранить его рекомендуется не локально, а в remote backend: S3-совместимом хранилище, Yandex Object Storage, GitLab Managed Terraform State. - Module — переиспользуемый набор ресурсов. Например, модуль «standard-web-service» создаёт сразу ВМ + балансировщик + DNS-запись.
- Plan и Apply — рабочий цикл:
terraform planпоказывает, что будет сделано (только показывает!),terraform apply— реально применяет изменения.
Жизненный цикл работы с Terraform
1. terraform init — скачать провайдеры, инициализировать
2. terraform fmt — отформатировать код в стандартном виде
3. terraform validate — проверить синтаксис
4. terraform plan — посмотреть, ЧТО будет создано/удалено/изменено
5. terraform apply — реально применить изменения
6. terraform destroy — удалить ВСЁ, что создал Terraform (для очистки)
Пример конфигурации Terraform для Yandex Cloud
# Указываем, какие провайдеры используем
terraform {
required_version = ">= 1.5"
required_providers {
yandex = {
source = "yandex-cloud/yandex"
version = "~> 0.130"
}
}
# Храним state не локально, а в облачном хранилище
backend "s3" {
endpoints = { s3 = "https://storage.yandexcloud.net" }
bucket = "my-terraform-state"
region = "ru-central1"
key = "prod/terraform.tfstate"
skip_region_validation = true
skip_credentials_validation = true
skip_requesting_account_id = true
skip_s3_checksum = true
}
}
# Настройка провайдера
provider "yandex" {
zone = "ru-central1-a"
}
# Переменные
variable "vm_count" {
description = "Сколько одинаковых ВМ создавать"
type = number
default = 1
}
# Поиск свежего образа Ubuntu 24.04 — data source, не создаёт ничего
data "yandex_compute_image" "ubuntu" {
family = "ubuntu-2404-lts"
}
# Создаём собственную сеть
resource "yandex_vpc_network" "main" {
name = "main-network"
}
resource "yandex_vpc_subnet" "main" {
name = "main-subnet"
network_id = yandex_vpc_network.main.id
zone = "ru-central1-a"
v4_cidr_blocks = ["10.0.1.0/24"]
}
# Создаём count копий ВМ
resource "yandex_compute_instance" "web" {
count = var.vm_count
name = "web-${count.index}"
resources {
cores = 2
memory = 2
core_fraction = 20
}
boot_disk {
initialize_params {
image_id = data.yandex_compute_image.ubuntu.id
size = 20
}
}
network_interface {
subnet_id = yandex_vpc_subnet.main.id
nat = true
}
metadata = {
ssh-keys = "ubuntu:${file("~/.ssh/id_ed25519.pub")}"
}
}
# Выводим публичные IP всех созданных машин
output "public_ips" {
value = yandex_compute_instance.web[*].network_interface.0.nat_ip_address
}
После запуска terraform apply Terraform создаст в Yandex Cloud сеть, подсеть и одну ВМ. Изменив vm_count = 5 и снова запустив apply — добавит ещё 4 машины (старая останется, Terraform поймёт, что она уже существует).
Ansible — настройка машин по SSH
Когда машины созданы, нужно их настроить: установить программы, положить конфиги, открыть порты. Этим занимается Ansible.
Главные особенности:
- Agentless — на управляемой машине не нужно ничего устанавливать заранее, кроме SSH-сервера и Python. Ansible сам подключается, выполняет команды и отключается.
- Идемпотентность — Ansible проверяет текущее состояние, и если оно уже соответствует желаемому — ничего не делает. Можно запускать playbook хоть 100 раз — результат одинаковый.
- Декларативность через модули — ты не пишешь
apt install nginx, ты пишешь «модульansible.builtin.aptдолжен обеспечить, чтобы пакетnginxбыл установлен». Ansible сам понимает, что нужно сделать. - YAML-синтаксис — описание читается даже не-программистами.
Основные понятия Ansible
- Inventory — файл со списком серверов, на которых работаем. Может быть статическим (просто YAML или INI с IP-адресами) или динамическим (Ansible сам ходит в облако и получает актуальный список ВМ).
- Playbook — YAML-файл с инструкциями: что и в каком порядке делать на каких серверах.
- Task — одна задача (например, «установить nginx»).
- Module — программа, которая выполняет конкретное действие (
aptдля пакетов,copyдля файлов,serviceдля systemd-сервисов,lineinfileдля редактирования файлов). - Role — переиспользуемый набор задач, файлов, переменных. Например, роль
nginxсодержит всё, что нужно для установки и базовой настройки nginx. - Handler — задача, которая запускается только если её «уведомили» (например, перезапуск nginx после изменения конфига).
- Variables — переменные, как в Terraform, чтобы один playbook работал для разных окружений.
- Galaxy — публичный репозиторий готовых ролей: https://galaxy.ansible.com
ℹ️ В 2026 году актуальная версия — ansible-core 2.18+ (под капотом) и Ansible 11+ (community package, объединяющий core + сотни коллекций модулей). Стабильно работает на Python 3.11+.
Пример простого playbook
# install-web.yml
- name: Установка и настройка nginx
hosts: web_servers
become: true # выполнять команды через sudo
vars:
nginx_port: 80
welcome_message: "Сервер развёрнут через Ansible"
tasks:
- name: Обновить кэш apt и установить nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Развернуть индексную страницу из шаблона
ansible.builtin.template:
src: index.html.j2
dest: /var/www/html/index.html
owner: www-data
group: www-data
mode: "0644"
notify: restart nginx # если файл изменился — перезапустить nginx
- name: Разрешить порт в ufw
community.general.ufw:
rule: allow
port: ""
proto: tcp
- name: Убедиться, что nginx запущен и в автозагрузке
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: restart nginx
ansible.builtin.service:
name: nginx
state: restarted
Файл шаблона templates/index.html.j2 (Jinja2):
<!DOCTYPE html>
<html>
<head><title>Hello from Ansible</title></head>
<body>
<h1></h1>
<p>Host: </p>
<p>IP: </p>
</body>
</html>
Запуск: ansible-playbook -i inventory.ini install-web.yml
Структура Ansible-роли
roles/
└── nginx/
├── defaults/main.yml # самые базовые переменные (можно перекрыть)
├── vars/main.yml # переменные роли (приоритет выше)
├── tasks/main.yml # сами задачи
├── handlers/main.yml # обработчики (перезапуск сервисов)
├── templates/ # Jinja2-шаблоны
├── files/ # файлы для копирования как есть
└── meta/main.yml # метаданные (зависимости, автор)
Terraform vs Ansible — когда что использовать
| Задача | Чем сделать |
|---|---|
| Создать ВМ в облаке | Terraform |
| Создать VPC, подсеть, балансировщик | Terraform |
| Создать Managed PostgreSQL | Terraform |
| Установить nginx на существующую ВМ | Ansible |
| Положить конфиг и перезапустить сервис | Ansible |
| Обновить версию ОС на 100 серверах | Ansible |
| Создать Kubernetes-кластер в облаке | Terraform |
| Установить Helm-чарт в Kubernetes | Helm (или Terraform с helm-провайдером) |
| Создать пользователей и роли в облаке (IAM) | Terraform |
| Подкрутить параметры ядра Linux на сервере | Ansible |
Главное правило: Terraform — про создание и удаление ресурсов в облаке. Ansible — про состояние программ и конфигов внутри уже существующих машин.
Альтернативы и тренды 2026 года
- OpenTofu — открытый форк Terraform под Linux Foundation. Полностью совместим с Terraform, но без угрозы изменения лицензии.
- Pulumi — IaC на «настоящих» языках программирования (TypeScript, Python, Go, C#). Удобнее для разработчиков, но Terraform/OpenTofu по-прежнему стандарт в DevOps.
- Crossplane — управление облачной инфраструктурой через Kubernetes-манифесты. Создаёшь YAML с типом
Database, Crossplane создаёт реальную базу в Yandex Cloud или AWS. - Ansible Automation Platform (бывший Ansible Tower / AWX) — корпоративная UI-надстройка для запуска playbooks, расписаний, отчётности, RBAC.
- Atlantis и env0 — инструменты для GitOps-подхода к Terraform: pull request → автоматический plan в комментарии → ручное подтверждение apply.
Теоретические вопросы
-
Что такое Infrastructure as Code и в чём его преимущества? Ответ: Подход, при котором вся инфраструктура описана в текстовых файлах, версионируется в Git и применяется автоматизированно. Преимущества: воспроизводимость, ревью изменений, версионирование, скорость разворачивания, отказ от ручных кликов, идентичные dev/staging/prod.
-
В чём разница между декларативным и императивным подходом? Ответ: Декларативный — описываешь желаемый результат (Terraform: «должно быть 3 ВМ»). Императивный — описываешь шаги для его достижения (bash: «создай ВМ, потом ещё одну»). Декларативный подход проще, безопаснее и легче поддаётся повторному применению.
-
Что такое идемпотентность и почему она критична для IaC? Ответ: Свойство операции: повторное выполнение даёт тот же результат, что и одно выполнение. Если запустить
terraform applyилиansible-playbookдважды подряд, ничего не сломается и не создастся дважды. -
Что такое Terraform state и почему его нельзя терять? Ответ: Файл
terraform.tfstate— это «память» Terraform о том, какие ресурсы он создал и как они выглядят. Без state Terraform не знает, что управлять, и при следующем apply попытается создать всё заново или поломает существующее. Хранится в Object Storage с включённым versioning и блокировками. -
Что такое remote backend и блокировка state? Ответ: Remote backend — хранение state не на ноутбуке инженера, а в общем хранилище (S3, Yandex Object Storage). Блокировка (locking) — механизм, при котором, пока один инженер запускает apply, другие не могут запустить параллельно — иначе state поломается.
-
Чем
terraform planотличается отterraform apply? Ответ: Plan показывает diff — что будет создано, изменено или удалено, но ничего не делает. Apply реально применяет изменения. Правило: всегда смотри plan перед apply, особенно на проде. -
Что такое модуль в Terraform? Ответ: Переиспользуемый набор ресурсов с входными и выходными параметрами. Например, модуль «standard-vm» создаёт ВМ + диск + IP + DNS-запись. В разных проектах модуль вызывается с разными параметрами.
-
Что такое provider в Terraform? Ответ: Подключаемый модуль для работы с конкретным API:
yandex,aws,kubernetes,helm,postgresql. Каждый provider добавляет свои ресурсы. В Terraform можно использовать несколько провайдеров одновременно. -
Можно ли запустить Terraform параллельно для одного проекта на двух машинах? Ответ: Нет, если только не настроена блокировка state. Параллельный запуск без локов приведёт к рассинхронизации state и может «потерять» ресурсы из учёта.
-
Что такое Ansible playbook? Ответ: YAML-файл с описанием задач, которые Ansible выполнит на указанных в inventory машинах. Playbook состоит из play (групп задач для разных хостов) и tasks (отдельных операций).
-
Что такое inventory и какие типы бывают? Ответ: Список управляемых хостов. Статический — обычный INI/YAML с IP/именами. Динамический — скрипт или плагин, который при каждом запуске ходит в облако (Yandex Cloud, AWS) и получает актуальный список ВМ. В крупных инфраструктурах всегда используют динамический inventory.
-
Что такое handler в Ansible и зачем он нужен? Ответ: Задача, которая выполняется только если её уведомили (
notify). Классический пример: после изменения конфига nginx нужно его перезапустить. Без handler перезапуск выполнялся бы каждый раз, даже если конфиг не менялся. -
Что такое идемпотентный модуль и приведи пример НЕидемпотентного использования. Ответ: Модуль, который проверяет состояние перед действием.
ansible.builtin.apt: name=nginx state=presentидемпотентен — если nginx стоит, ничего не делает. Неидемпотентно:command: apt install nginxилиshell: echo "x" >> /etc/file— будет добавлять строку в файл при каждом запуске. Для shell/command используютcreates:илиremoves:для идемпотентности. -
Чем Ansible Role отличается от обычного playbook? Ответ: Role — стандартизированная структура папок (tasks/, files/, templates/, vars/, handlers/, defaults/, meta/), которую можно переиспользовать в разных проектах.
-
Чем Terraform отличается от Ansible и когда что использовать? Ответ: Terraform — для создания ресурсов в облаке (ВМ, сети, БД). Ansible — для настройки программ и конфигов на уже существующих машинах. Terraform работает через API облака, Ansible — по SSH.
-
Можно ли заменить Ansible на cloud-init / user_data? Ответ: Для простой первоначальной настройки (установить 1–2 пакета, положить ключи) — да, cloud-init вполне работает и проще. Для сложной настройки, регулярных обновлений конфигов, многосерверных операций — нет, Ansible незаменим. Часто их комбинируют.
-
Что такое Ansible Vault и зачем он нужен? Ответ: Встроенный механизм шифрования секретов в YAML-файлах. Пароли, ключи, токены хранятся в зашифрованном виде в Git, расшифровываются при запуске playbook паролем или ключом. Не путать с HashiCorp Vault (он будет в уроке 9).
-
Что такое OpenTofu и почему он появился? Ответ: Открытый форк Terraform под управлением Linux Foundation. Появился после смены лицензии Terraform на BSL в августе 2023. По синтаксису и поведению полностью совместим с Terraform.
-
Как проверить, что Terraform-код корректен, без реального применения? Ответ:
terraform fmt(формат),terraform validate(синтаксис и ссылки),terraform plan(что произойдёт), плюс инструментыtflint,tfsec,checkov,trivyдля статического анализа на безопасность. -
Что такое drift и как его обнаружить? Ответ: Drift — это когда реальное состояние инфраструктуры разошлось с тем, что описано в Terraform-коде (кто-то изменил ресурс руками через консоль). Обнаруживается через
terraform plan— он покажет разницу. На проде стоит регулярно запускатьplanпо расписанию (через CI или Atlantis) и оповещать при drift.
Практическая часть
Задание 1. Установка инструментов
Шаги:
- Установи Terraform или OpenTofu. В России лучше OpenTofu (нет лицензионных ограничений):
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh \ -o install-opentofu.sh chmod +x install-opentofu.sh ./install-opentofu.sh --install-method standalone tofu --version - Установи Ansible:
python3 -m pip install --user ansible --break-system-packages ansible --version # Должно быть ansible-core 2.18+ - Проверь, что у тебя настроен
ycCLI и SSH-ключ из урока 6.
Задание 2. Первая инфраструктура через Terraform
Цель: Создать ВМ в Yandex Cloud полностью декларативно.
Шаги:
- Создай папку и базовые файлы:
mkdir terraform-lesson && cd terraform-lesson touch main.tf .gitignore - Содержимое
.gitignore(state-файлы не должны попадать в Git!):.terraform/ *.tfstate *.tfstate.backup *.tfvars crash.log -
Заполни
main.tfпримером кода из теоретической части (тот, что выше). - Инициализация и применение:
tofu init # или terraform init tofu fmt tofu validate tofu plan # внимательно прочитай вывод tofu apply # подтверди yes -
Посмотри
terraform.tfstate— это и есть «память» Terraform. -
Сделай изменение (например, поменяй имя ВМ) и снова
plan→apply. - Удали всё:
tofu destroy
Задание 3. State в Object Storage
Цель: Перенести state в remote backend.
Шаги:
-
Создай bucket для state через
yc storage bucket create. - Создай сервисный аккаунт со static access key:
yc iam service-account create --name tf-state yc iam access-key create --service-account-name tf-state -
Добавь блок
backend "s3"вmain.tf(как в примере выше). - Передай ключи через переменные окружения:
export AWS_ACCESS_KEY_ID="<твой access key>" export AWS_SECRET_ACCESS_KEY="<твой secret>" tofu init -migrate-state - Проверь в Object Storage, что файл state появился.
Задание 4. Первый Ansible playbook
Цель: Настроить ВМ, созданную Terraform, через Ansible.
Шаги:
- Создай inventory.ini:
[web] <публичный_IP_твоей_ВМ> ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_ed25519 - Проверь связь:
ansible -i inventory.ini web -m ping # должно вернуть pong - Создай playbook
web.yml: ```yaml- name: Базовая настройка веб-сервера
hosts: web
become: true
tasks:
-
name: Обновить apt cache ansible.builtin.apt: update_cache: true cache_valid_time: 3600
-
name: Установить пакеты ansible.builtin.apt: name: - nginx - htop - curl - jq state: present
-
name: Развернуть индексную страницу ansible.builtin.copy: dest: /var/www/html/index.html content: | <html><body> <h1>Привет от Ansible!</h1> <p>Хостнейм: </p> <p>Дата: </p> </body></html> owner: www-data group: www-data mode: “0644”
-
name: Запустить и включить nginx ansible.builtin.service: name: nginx state: started enabled: true ```
-
- name: Базовая настройка веб-сервера
hosts: web
become: true
tasks:
- Запусти:
ansible-playbook -i inventory.ini web.yml -
Проверь в браузере:
http://<IP_ВМ>— должна открыться твоя страница. -
Запусти playbook ещё раз. Обрати внимание, что Ansible выдаёт
okвместоchanged— это работа идемпотентности. - Измени текст и запусти ещё раз. На этот раз будет
changed=1— Ansible увидел разницу.
Задание 5. Свой Ansible role
Цель: Превратить плоский playbook в роль.
Шаги:
- Сгенерируй структуру роли:
ansible-galaxy init roles/nginx -
Перенеси задачи из
web.ymlвroles/nginx/tasks/main.yml, шаблон страницы — вroles/nginx/templates/index.html.j2. -
Используй модуль
ansible.builtin.templateвместоcopy, чтобы поддерживать Jinja2-переменные. - В
roles/nginx/defaults/main.ymlположи дефолтные переменные:nginx_welcome_title: "Привет от роли" - Обнови основной playbook:
```yaml
- hosts: web
become: true
roles:
- nginx ```
- hosts: web
become: true
roles:
Задание 6. Связка Terraform + Ansible
Цель: Получить полный pipeline «создать ВМ → настроить ВМ».
Шаги:
-
После
tofu applyTerraform выведет публичный IP вoutput. - Создай скрипт
apply-all.sh:#!/usr/bin/env bash set -euo pipefail tofu apply -auto-approve IP=$(tofu output -raw vm_public_ip) echo "[*] Жду 30 секунд, пока ВМ полностью загрузится..." sleep 30 # Динамический inventory echo "[web]" > inventory.ini echo "$IP ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_ed25519 ansible_ssh_common_args='-o StrictHostKeyChecking=no'" >> inventory.ini ansible-playbook -i inventory.ini web.yml -
Запускай
bash apply-all.sh— и у тебя будет полностью готовый веб-сервер за пару минут, без единого клика мышью. - Удали всё:
tofu destroy
Задание 7. Чек-лист зрелого использования IaC
Проверь себя, можешь ли ты ответить «да» на эти пункты:
- Весь Terraform-код лежит в Git
- State хранится не локально, а в Object Storage с включённым versioning
- Используется блокировка state при
apply - Перед
applyвсегда смотритсяplan - Изменения в проде идут через Pull Request с code review
- CI проверяет код:
terraform fmt -check,terraform validate,tflint,tfsec - Секретные данные (пароли, ключи) не лежат в Git в открытом виде
- Ansible-роли версионируются и переиспользуются между проектами
- Для секретов в Ansible используется
ansible-vault - Есть тесты Ansible-ролей через Molecule
Если на все пункты «да» — у тебя зрелая IaC-практика.