Веб-сервер на ВМ: метаданные, user-data и группы безопасности

Рейтинг: 55.2% · 12 голосов
Подробный курс по Terraform и OpenTofu на примерах Yandex Cloud: ресурсы и провайдеры, состояние и бэкенды, модули, циклы и условия HCL, секреты и Lockbox, тестирование, CI/CD и командная работа. С актуализацией на 2026 (Terraform 1.3-1.10, OpenTofu).
Ответить
Аватара пользователя
Vlad_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Веб-сервер на ВМ: метаданные, user-data и группы безопасности

Сообщение Vlad_DevOps »

Оглавление курса (47)
  1. Что такое инфраструктура как код и зачем она нужна
  2. Категории инструментов IaC: чем отличаются Ansible, Packer, Kubernetes и Terraform
  3. Чем Terraform отличается от Ansible, Pulumi и CloudFormation
  4. Как работает Terraform под капотом и кто такой OpenTofu
  5. Установка Terraform и OpenTofu, подготовка Yandex Cloud
  6. Первый ресурс: разворачиваем виртуальную машину в Yandex Cloud
  7. Веб-сервер на ВМ: метаданные, user-data и группы безопасности (вы здесь)
  8. Переменные ввода и выходные значения в Terraform
  9. Кластер ВМ: группа экземпляров Yandex Compute Instance Group
  10. Балансировщик нагрузки: Application Load Balancer в Yandex Cloud
  11. Состояние Terraform: что такое tfstate и чем опасен локальный файл
  12. Удалённое хранилище состояния: бэкенд на Yandex Object Storage
  13. Изоляция состояния: рабочие области против раскладки по папкам
  14. Источники данных и terraform_remote_state: связываем компоненты
  15. Модули Terraform: переиспользуем инфраструктуру
  16. Входные, локальные и выходные переменные модуля
  17. Версионирование модулей и подводные камни
  18. Циклы в Terraform: параметр count
  19. Циклы в Terraform: for_each по множествам и картам
  20. Выражения for и строковые директивы
  21. Условная логика: count-трюк, for_each и директива if
  22. Встроенные функции, типы и выражения HCL
  23. Развёртывание без простоя: create_before_destroy
  24. Подводные камни Terraform и рефакторинг с блоком moved
  25. Управление секретами: основы и типы
  26. Инструменты управления секретами: Yandex Lockbox, Vault, SOPS
  27. Аутентификация провайдера и секреты: сервисные аккаунты и OIDC
  28. Секреты в ресурсах и состоянии, ephemeral-значения
  29. Провайдеры Terraform: установка, версии, required_providers
  30. Несколько копий одного провайдера: alias и мультизона
  31. Несколько провайдеров и аккаунтов: configuration_aliases
  32. Terraform, Docker и Kubernetes: Managed Kubernetes в Yandex Cloud
  33. Код Terraform промышленного уровня: почему это долго
  34. Мелкие компонуемые модули вместо монолита
  35. Тестируемые модули и проверки: validation, precondition, postcondition
  36. Версионирование, публикация модулей и Terragrunt
  37. Ручное тестирование Terraform и очистка ресурсов
  38. Автоматические тесты на Terratest: модульные тесты
  39. Интеграционные и сквозные тесты, пирамида тестирования
  40. Нативный terraform test и статический анализ
  41. Внедрение Terraform в команде: процессы и культура
  42. Конвейер развёртывания прикладного кода
  43. Конвейер инфраструктурного кода и золотое правило Terraform
  44. Стиль, ревью и CI/CD-инструменты: Atlantis, TACOS, policy as code
  45. Что нового в Terraform 1.3-1.10: моды, импорт, провайдер-функции, Stacks
  46. OpenTofu в 2026: чем живёт форк и как мигрировать
  47. Сертификация HashiCorp Terraform Associate и карьера
До этого момента мы поднимали голую виртуалку и радовались тому, что она хотя бы создаётся. Но голая ВМ - это как новый ноутбук без единой программы: вроде есть, а толку ноль. В этом уроке мы превратим её в живой веб-сервер, который сам по себе, без ручного ssh и копипасты команд, поднимет nginx и отдаст страничку в браузер. И сделаем это полностью через terraform - инфраструктура как код, как и положено.

Боль, которую мы лечим, простая. Ты создал инстанс, потом руками зашёл по ssh, поставил пакеты, что-то настроил, забыл записать. Через месяц нужна вторая такая же машина - и ты не помнишь и половины. А если машин десять? Подход "iac" в том и состоит, чтобы вся настройка лежала в .tf-файлах и воспроизводилась одной командой terraform apply. Сегодня мы вшиваем установку веб-сервера прямо в описание ВМ через cloud-init.

Что такое метаданные и user-data

У каждой виртуалки в облаке есть служба метаданных - это такой внутренний эндпоинт, к которому ОС обращается при загрузке. Через него облако передаёт машине информацию: ssh-ключи, имя хоста и, что нам сейчас важно, скрипт первичной настройки. В Yandex Cloud метаданные задаются в блоке (точнее, в аргументе-карте) metadata у ресурса yandex_compute_instance.

Ключ ssh-keys ты, скорее всего, уже видел в прошлых уроках - он кладёт твой публичный ключ внутрь машины. А вот ключ user-data - это и есть точка входа для cloud-init. Cloud-init - стандартный механизм в большинстве облачных образов Linux (Ubuntu, Debian, CentOS). Он читает user-data при первой загрузке и выполняет то, что там написано: ставит пакеты, пишет файлы, запускает команды. По сути это твой первый акт автоматизации внутри ВМ.

Формат user-data - это YAML, который начинается со строки #cloud-config. Звучит страшно, но на практике это пара блоков: что поставить и что запустить. Давай посмотрим минимальный конфиг, который ставит nginx и кладёт простую html-страницу:

Код: Выделить всё

#cloud-config
package_update: true
packages:
  - nginx
write_files:
  - path: /var/www/html/index.html
    content: |
      <h1>Привет из Terraform!</h1>
      <p>nginx подняли через cloud-init на Yandex Cloud</p>
runcmd:
  - systemctl enable nginx
  - systemctl restart nginx
Этот текст мы и передадим машине через метаданные. Удобный приём - вынести его в отдельный файл cloud-init.yaml рядом с конфигом и подтянуть функцией file().

Изображение

Собираем ВМ с user-data

Теперь сам ресурс. Обрати внимание на блок network_interface: чтобы машина была доступна из интернета, ей нужен внешний IP - это аргумент nat = true. Без него ВМ живёт только во внутренней сети, и никакой curl снаружи до неё не достучится.

Код: Выделить всё

resource "yandex_compute_instance" "web" {
  name        = "web-server"
  platform_id = "standard-v3"
  zone        = "ru-central1-a"

  resources {
    cores  = 2
    memory = 2
  }

  boot_disk {
    initialize_params {
      image_id = "fd80bm0rh4rkepi5ksdi" # Ubuntu 22.04 LTS
      size     = 10
    }
  }

  network_interface {
    subnet_id          = yandex_vpc_subnet.this.id
    nat                = true
    security_group_ids = [yandex_vpc_security_group.web.id]
  }

  metadata = {
    user-data = file("${path.module}/cloud-init.yaml")
    ssh-keys  = "ubuntu:${file("~/.ssh/id_ed25519.pub")}"
  }
}
Разберём по косточкам. user-data внутри metadata - это и есть наш cloud-init. file() читает файл с диска и подставляет его содержимое как строку. path.module - встроенная переменная Terraform, которая указывает на каталог текущего модуля, чтобы путь не ломался при запуске из другой директории. security_group_ids в network_interface - список идентификаторов групп безопасности, которые мы привяжем к сетевому интерфейсу. Их ID мы возьмём из ресурса, который опишем ниже.

Группа безопасности: открываем нужные порты

Внешний IP сам по себе ничего не открывает. По умолчанию трафик к машине режется, и если не настроить правила, твой nginx будет работать, но снаружи останется невидимым. За это отвечает ресурс yandex_vpc_security_group - облачный аналог файрвола перед интерфейсом ВМ.

Правила бывают двух направлений: ingress (входящий трафик к машине) и egress (исходящий от машины). Нам нужно впустить два порта: 22 для ssh и 80 для http. И обязательно разрешить весь исходящий трафик egress - иначе cloud-init не сможет скачать пакет nginx из репозиториев, и установка молча провалится. Это, кстати, одна из самых частых граблей у новичков.

Код: Выделить всё

resource "yandex_vpc_security_group" "web" {
  name        = "web-sg"
  description = "SSH and HTTP for web server"
  network_id  = yandex_vpc_network.this.id

  ingress {
    protocol       = "TCP"
    description    = "SSH"
    v4_cidr_blocks = ["0.0.0.0/0"]
    port           = 22
  }

  ingress {
    protocol       = "TCP"
    description    = "HTTP"
    v4_cidr_blocks = ["0.0.0.0/0"]
    port           = 80
  }

  egress {
    protocol       = "ANY"
    description    = "Allow all outbound"
    v4_cidr_blocks = ["0.0.0.0/0"]
    from_port      = 0
    to_port        = 65535
  }
}
Поля здесь ровно те, что лежат в документации провайдера. protocol принимает значения ANY, TCP, UDP, ICMP, IPV6_ICMP. v4_cidr_blocks - список подсетей, откуда (для ingress) или куда (для egress) разрешён трафик; 0.0.0.0/0 означает "отовсюду". Для одного порта пишем port, для диапазона - пару from_port и to_port. Открывать ssh на весь мир в проде - так себе идея, лучше сузить до своего IP, но для учебного стенда сойдёт.

Если тебе ближе держать правила отдельными ресурсами, в Yandex Cloud есть yandex_vpc_security_group_rule с аргументами security_group_binding и direction. Но мешать оба подхода в одной группе нельзя - провайдер ругнётся на конфликт. Для старта проще описывать ingress и egress прямо внутри группы, как выше.

Сеть, проверка и запуск

Чтобы всё это завелось, нужны ещё сеть и подсеть - база, на которую опираются и группа безопасности, и интерфейс ВМ:

Код: Выделить всё

resource "yandex_vpc_network" "this" {
  name = "web-net"
}

resource "yandex_vpc_subnet" "this" {
  name           = "web-subnet"
  zone           = "ru-central1-a"
  network_id     = yandex_vpc_network.this.id
  v4_cidr_blocks = ["10.10.0.0/24"]
}
Запускаем привычную пару команд. Сначала terraform plan - смотрим, что Terraform собирается создать: сеть, подсеть, группу безопасности и саму ВМ. Затем terraform apply - и через минуту-другую инфраструктура готова. Внешний IP машины Terraform знает после применения, его можно вывести через output по полю network_interface.0.nat_ip_address.

Проверяем, что веб-сервер живой:

Код: Выделить всё

curl http://<внешний_IP_машины>
Если в ответ прилетел наш html - поздравляю, ты только что развернул веб-сервер целиком из кода, ни разу не зайдя руками внутрь машины. Если ответа нет - дай cloud-init время. Установка nginx происходит уже после того, как terraform apply отрапортовал об успехе: Terraform создаёт ВМ, а дальше cloud-init работает внутри неё автономно. Первая загрузка с обновлением пакетов может занять минуту-две.

Типичные грабли
  • Забыли nat = true в интерфейсе - машина без внешнего IP, curl не дотянется, хотя внутри всё работает.
  • Не открыли egress - cloud-init не может скачать nginx, страница не появляется, а в логах внутри ВМ ошибки apt. Egress на ANY и 0.0.0.0/0 лечит.
  • Перепутали порт в ingress - открыли 8080 вместо 80, а nginx слушает 80. Соответствие портов проверяй внимательно.
  • Поспешили с curl - дали машине полсекунды и решили, что ничего не работает. Cloud-init не мгновенный, подожди.
  • Невалидный YAML в user-data - лишний отступ, и cloud-init молча проглатывает конфиг. Проверяй отступы, YAML их не прощает.
Почему хардкодить нельзя

Сейчас у нас всё прибито гвоздями: имя web-server, зона ru-central1-a, образ строкой, CIDR прямо в коде. Для одного учебного стенда это нормально. Но как только захочется поднять второй такой сервер, или развернуть копию в другой зоне, или отдать конфиг коллеге - начнётся боль. Менять придётся в десяти местах, и где-нибудь обязательно забудешь.

Именно поэтому в следующих уроках мы вынесем все эти значения в переменные. Имя, зона, образ, размер диска, разрешённые CIDR - всё это станет настраиваемыми входами. Один и тот же код сможет породить dev-стенд и прод, отличающиеся лишь файлом с переменными. Это не каприз, а суть подхода terraform: описание инфраструктуры должно быть переиспользуемым, а не одноразовым. Кстати, всё сказанное справедливо и для opentofu - открытого форка Terraform, синтаксис HCL у них общий.

Мини-лаба

Повтори руками, по шагам:
  • Создай файл cloud-init.yaml с установкой nginx и своей html-страницей.
  • Опиши сеть, подсеть, группу безопасности с ingress 22 и 80 и egress на всё.
  • Опиши yandex_compute_instance с nat = true, привязкой security_group_ids и metadata.user-data через file().
  • Прогони terraform plan, изучи, что будет создано, затем terraform apply.
  • Дождись cloud-init и проверь curl по внешнему IP. Добейся, чтобы вернулась твоя страница.
  • Бонус: убери egress и посмотри, как сломается установка. Потом верни обратно.
Контрольные вопросы
  • За что отвечает ключ user-data в metadata и какой механизм внутри ВМ его обрабатывает?
  • Зачем нужен аргумент nat = true и что будет без него?
  • Почему важно разрешить egress, если мы хотим всего лишь отдавать http-страницу?
  • Чем привязка через security_group_ids в network_interface отличается от описания правил внутри самой группы?
Итог

Что забрать с собой: metadata.user-data - это вход для cloud-init, через который ВМ сама себя настраивает при первой загрузке. yandex_vpc_security_group с правилами ingress и egress открывает нужные порты, и без egress установка пакетов не пройдёт. nat = true даёт внешний IP, без которого снаружи не достучаться. Группа цепляется к машине через security_group_ids в network_interface. И главный вывод на будущее: хардкод хорош ровно до второго сервера - дальше нужны переменные и модули terraform, к которым мы и перейдём.
👍2 ❤️1 🔥 😄 🤔2
Аватара пользователя
dockeraddict
Сообщения: 1
Зарегистрирован: 12 май 2026, 01:48

Re: Веб-сервер на ВМ: метаданные, user-data и группы безопасности

Сообщение dockeraddict »

Спасибо, наконец дошло зачем этот egress нужен. Сидел полчаса не мог понять почему nginx не ставится, а оказывается машина просто в интернет выйти не могла за пакетом. Вернул egress на ANY и все поднялось.
👍 ❤️ 🔥1 😄 🤔
Аватара пользователя
proxmoxandy
Сообщения: 1
Зарегистрирован: 21 май 2026, 03:55

Re: Веб-сервер на ВМ: метаданные, user-data и группы безопасности

Сообщение proxmoxandy »

А можно ssh не на 0.0.0.0/0 а сразу на свой айпи прописать в ingress? Или это уже в следующих уроках через переменные будет? Хочется чтоб порт 22 не на весь мир торчал.
👍 ❤️1 🔥 😄 🤔1
Ответить
← Предыдущая глава
Первый ресурс: разворачиваем виртуальную машину в Yandex Cloud
Следующая глава →
Переменные ввода и выходные значения в Terraform

Все главы курса «Terraform: инфраструктура как код на Yandex Cloud»

Поделиться темой: ✈ Telegram VK
Похожие запросы: как сделать бэкап docker volume и восстановить данныеdocker volume и bind mount в чем разница и где хранятся данные

Вернуться в «Terraform: инфраструктура как код на Yandex Cloud»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя