Перейти к содержанию

Terraform: лимиты контейнеров и стратегия обновления

Граф «Контура» уже организован и его состояние имеет понятную границу. Добавим две эксплуатационные настройки контейнера: лимит памяти и политику перезапуска. Затем разберём обновление образа. Учебная цель — связать параметры ресурса с реальным поведением и возможной остановкой, не объявляя пару Docker-контейнеров готовой системой высокой доступности.

В модуле сайта лимит памяти станет общей политикой. Все экземпляры получают одинаковое значение 128 в единицах Docker-провайдера, то есть мегабайтах. Это небольшое учебное ограничение для Nginx со статической страницей, а не измеренный оптимальный размер. В процессе написания нагрузка не создавалась и потребление не измерялось. Для приложения с обработкой изображений или большого JavaScript-сервера подходящий лимит определяют по отдельному профилю работы.

Ограничение и отказ

Параметр memory ограничивает доступные контейнеру ресурсы; он не заставляет программу потреблять меньше памяти по смыслу задачи. Если процесс пытается выйти за пределы и среда применяет ограничение, возможен отказ или завершение процесса. Увеличение числа контейнеров при той же общей памяти хоста также не гарантирует улучшение работы. Контейнерные лимиты рассматривают вместе с возможностями daemon и остальными его нагрузками.

Полный файл modules/site/main.tf для этого состояния:

terraform {
  required_providers {
    docker = { source = "kreuzwerker/docker", version = "= 3.6.2" }
  }
}
variable "name" { type = string }
variable "image_id" { type = string }
variable "network_id" { type = string }
variable "port" { type = number }
variable "html" { type = string }
resource "docker_container" "web" {
  name  = var.name
  image = var.image_id
  memory = 128
  restart = "unless-stopped"
  networks_advanced { name = var.network_id }
  ports {
    internal = 80
    external = var.port
    ip       = "127.0.0.1"
  }
  upload {
    file    = "/usr/share/nginx/html/index.html"
    content = var.html
  }
}
output "container_id" { value = docker_container.web.id }
output "url" { value = "http://127.0.0.1:${var.port}" }

Политика restart = "unless-stopped" задаёт поведение Docker при выходе процесса и перезапуске среды с учётом ручной остановки. Это не то же самое, что постоянный цикл Terraform-проверок. Terraform работает во время своих операций; Docker применяет политику к уже созданному контейнеру. Эти механизмы относятся к разным уровням управления. Если контейнер удалён полностью, restart policy не создаст его из ничего; для восстановления декларативного ресурса нужен отдельный процесс управления.

Учебная политика оставлена одинаковой для home и docs, чтобы объяснить общую границу модуля. Если один сайт должен быть временным, можно сделать вход restart_policy с допустимыми значениями. Но это расширяет публичный контракт. Прежде чем добавлять переменную, полезно решить, какие варианты действительно нужны и кто обязан их выбирать. Универсальный набор из десятков параметров может скрыть исходную цель локального модуля.

Тег и неизменяемое содержимое образа

В images.tf пока используется nginx:1.28.0-alpine. Это конкретный учебный тег, но имя не равнозначно криптографическому digest. При подготовке настоящего выпуска выбирают совместимый с платформой образ, проверяют его источник и фиксируют нужное содержимое. Передавать в статью выдуманный sha256 хуже, чем честно оставить тег: несуществующий хеш создаст иллюзию воспроизводимости. Поэтому архив не содержит такого фиктивного значения.

Новый digest или новый image ID может потребовать замену контейнера. Наши два сайта слушают фиксированные внешние порты и не стоят за отдельным балансировщиком. Нельзя одновременно запустить второй контейнер на той же паре адреса и порта без дополнительной схемы переключения. Следовательно, этот пример не обеспечивает обновление без паузы. Если план показывает удаление и создание, читатель должен учитывать промежуток недоступности.

Попытка добавить create_before_destroy не отменяет уникальность имён и портов Docker. Такая настройка меняет предпочтение жизненного цикла, но не создаёт свободный сокет и не переименовывает автоматически контейнер. Для настоящего плавного обновления понадобятся разные внутренние экземпляры, устойчивый вход, проверка готовности и управляемое переключение. В курсе мы называем эту архитектурную границу, а не выдаём один флаг за законченный механизм выпуска.

Политика обновления вместо случайного скачивания

Docker-ресурс образа не обязан автоматически получать новое содержимое тега на каждом расчёте. Поведение чтения и триггеров зависит от возможностей выбранного провайдера. Если обновление нужно, его оформляют как явное изменение входного образа или согласованную схему отслеживания digest. Иначе два компьютера могут использовать одинаковую строку имени, но разное локальное содержимое. Читаемая запись версии должна соответствовать фактическим байтам будущего запуска.

В UPDATES.md сохранён краткий порядок решения: выбрать источник и платформу, получить реальный digest, изменить исходники, посмотреть замены и отдельно подтвердить поведение приложения. Мы не автоматизируем скачивание нового образа при каждом запуске рабочего сайта. Для лаборатории это удерживает обновление в пределах явного учебного шага. Для командной эксплуатации политика потребует графика, ответственного и процедуры реакции на уязвимости.

Откат тоже состоит из разных частей. Вернуть прежнюю строку образа в Git означает вернуть намерение, но не уже работающий процесс. Нужно рассчитать и согласовать обратное изменение инфраструктуры. Кроме того, приложение могло изменить внешние данные, с которыми старая версия несовместима. В статическом Nginx-примере таких миграций данных нет, поэтому обратное переключение проще по модели, однако оно всё равно не было выполнено и измерено.

Наблюдение после самостоятельного запуска

Читатель, решивший отдельно запустить лабораторию, может посмотреть настройки памяти и restart policy через Docker-инвентарь. Затем проверяют сам ответ HTTP по обоим outputs. Это разные наблюдения: один показывает конфигурацию контейнера, другой — путь к странице. Не стоит делать вывод о корректной работе сайта только из факта, что policy установлена. Процесс способен перезапускаться бесконечно из-за ошибки конфигурации и ни разу не обслужить полезный запрос.

Рассмотрим ещё один ошибочный вывод: после установки 128 мегабайт страница стала быстрее. Без сравнимых измерений такой причинной связи нет. Лимит обычно задаёт границу потребления, а не оптимизацию. Наш урок учит формулировать и читать ресурсные ограничения. Если цель состоит в скорости загрузки, её отдельно связывают с размером контента, кешированием, сетью и поведением клиента. Это помогает не смешивать инфраструктурную дисциплину с доказательствами производительности.

«Контур» теперь имеет явную эксплуатационную политику и честно названную границу обновления. В завершающем уроке соберём эти решения в регламент передачи проекта: что хранится в репозитории, что резервируется отдельно, кто читает планы и каким образом заканчивается жизнь только учебных ресурсов.

Лимиты как часть интерфейса

Если в будущей версии модуля появляется переменная памяти, документируйте единицу измерения в самом контракте. Число 128 без единицы выглядит переносимым, но разные API используют мегабайты, мебибайты или байты. Потребитель может выбрать значение, отличающееся на порядки. Значение по умолчанию должно быть объяснено областью применения, а не случайно скопировано из прежнего контейнера.

Политика перезапуска также не является мониторингом результата. Успешно работающий процесс может возвращать ошибку каждому запросу, а Docker будет считать его запущенным. Если цель — обнаружение отказа страницы, надо определить конкретный наблюдаемый критерий и источник сигнала. Наш модуль пока задаёт жизненный цикл процесса. Разделение этих обещаний позволит добавить наблюдение следующим самостоятельным шагом без ложного вывода о готовой отказоустойчивости.

Оглавление серии, общая подборка и полный архив исходников. Для этого урока выберите lesson-11.

Первичные источники: Версии Terraform, Учебник Terraform и Docker, Схема Docker container 3.6.2, Схема Docker image 3.6.2, Адреса и moved, Локальный backend, Import, Refresh-only plan.

Редакционный статус: локальный черновик. Учебные команды, приложение и проверки не запускались; описанные результаты ожидаемые. Профиль версий закреплён, разрешённый lockfile не создавался.