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

Переменные, проверки и HTML-шаблон

План помогает читать изменения, но до сих пор настройки «Контура» находятся прямо в ресурсе. Теперь выделим входные параметры: префикс имени, внешний порт и заголовок страницы. Один набор инфраструктурных блоков сможет выражать разные локальные варианты. Одновременно добавим HTML-шаблон, чтобы сайт показывал свою принадлежность лаборатории, а не стандартную страницу Nginx.

Переменная Terraform — именованный вход корневого модуля. Она не является изменяемой ячейкой программы и не получает новое значение после создания ресурса. Выбирается одно значение для расчёта конфигурации. Из этого значения строятся выражения, например имя контейнера. Тип и validation описывают допустимую область входа, но не удостоверяют внешние факты: свободен ли порт, существует ли Docker daemon, разрешён ли запуск на выбранном хосте.

Ограничения на значения

В variables.tf задаются три входа. Для prefix разрешены маленькие латинские буквы, цифры и дефис; первый символ должен быть буквой. Ограничение длины удерживает имена в понятных пределах. Такой учебный контракт намеренно уже возможностей Docker. Он позволяет использовать префикс в именах сети и контейнеров без дополнительных правил преобразования и помогает читателю сразу увидеть принадлежность ресурсов.

Порт имеет тип number, но это ещё не целое значение. Поэтому проверка включает диапазон и сравнение с floor. Число 8088.5 нельзя использовать как TCP-порт, хотя оно соответствует общему числовому типу. Диапазон начинается с 1024, потому что лаборатория не нуждается в привилегированном адресе. Сама проверка не обещает доступность порта; она только отсеивает входы, которые нельзя осмысленно передать дальше.

Полный файл variables.tf для этого состояния:

variable "prefix" {
  type    = string
  default = "kontur"
  validation {
    condition     = can(regex("^[a-z][a-z0-9-]{1,24}$", var.prefix))
    error_message = "Use a lowercase prefix, 2–25 characters."
  }
}
variable "port" {
  type    = number
  default = 8088
  validation {
    condition     = var.port >= 1024 && var.port <= 65535 && floor(var.port) == var.port
    error_message = "Port must be an integer from 1024 to 65535."
  }
}
variable "title" {
  type    = string
  default = "Kontur local web"
  validation {
    condition     = can(regex("^[A-Za-z0-9 ._-]{1,80}$", var.title))
    error_message = "The lab title permits ASCII letters, numbers, spaces, dot, underscore and dash."
  }
}

Полный файл site/index.html.tftpl для этого состояния:

<!doctype html>
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width">
<title>${title}</title><main><h1>${title}</h1><p>Local Terraform laboratory.</p></main></html>

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

resource "docker_container" "web" {
  name  = "${var.prefix}-web"
  image = docker_image.web.image_id
  ports {
    internal = 80
    external = var.port
    ip       = "127.0.0.1"
  }
  upload {
    file    = "/usr/share/nginx/html/index.html"
    content = templatefile("${path.module}/site/index.html.tftpl", { title = var.title })
  }
}

Заголовок ограничен набором ASCII-символов, безопасных для прямой вставки в наш простой HTML. templatefile не выполняет HTML-экранирование автоматически. Если разрешить произвольную строку с угловыми скобками, читатель сможет получить разметку вместо текста. Для публичного редактора контента понадобится отдельная модель безопасного вывода; здесь узкий учебный алфавит удерживает пример понятным. Эта граница записана в validation и названа в документации, а не оставлена неявным предположением.

Передача данных в шаблон

Файл site/index.html.tftpl содержит полный короткий документ. В нём одна подстановка ${title}, используемая для заголовка вкладки и h1. Функция templatefile получает путь и объект переменных. Привязка к path.module делает расположение шаблона независимым от того, откуда пользователь вызвал процесс. Если бы путь вычислялся относительно случайной текущей директории, перенос рабочего каталога мог бы привести к ошибке чтения.

В ресурс контейнера добавлен блок upload: он записывает результат шаблона по пути /usr/share/nginx/html/index.html перед запуском. Мы не используем привязку директории хоста и не предполагаем, что контейнер видит дерево проекта. Это полезное различие для читателя, знакомого с Docker volume. В данной версии контейнер получает конкретные байты конфигурационного HTML; изменение шаблона затем является изменением намерения ресурса, а не незаметным редактированием живого файла.

Передавайте входы через файл, показанный как terraform.tfvars.example, после собственной настройки и явного указания -var-file. Суффикс .example выбран специально: Terraform не должен случайно подхватить демонстрационные параметры как реальные локальные настройки. Если переименовать файл в автоматическое имя, меняется способ загрузки. Для первых опытов явный путь в команде делает происходящее легче заметить. Настоящие локальные файлы с чувствительными значениями не попадут в Git.

Изменение одной настройки

Пусть у читателя занят порт 8088. Он может задать 8092, сохранив префикс и заголовок. Новый URL будет использовать 8092 на хосте, однако Nginx продолжит слушать внутренний 80. Этот пример показывает назначение отдельного входа: человек меняет причину, а выражения автоматически переносят значение в нужное место. Если одновременно вручную исправить ресурс и переменную, можно создать противоречивые источники истины.

Другой вариант меняет только title на Kontur documentation. Ожидаемое содержимое HTTP-страницы изменится, а её имя контейнера и порт останутся прежними по конфигурации. Но способ применения такого изменения зависит от поведения провайдера: блок загрузки может привести к замене ресурса. Поэтому «изменили только текст» не означает «процесс точно не будет остановлен». Реальный план остаётся обязательным источником сведений о предполагаемом действии.

Разберём ошибку шаблона. Если переименовать вход в page_title, а в объекте для templatefile оставить ключ title, сам файл продолжит ожидать старый ключ. Если же изменить ключ объекта, забыв подстановку в шаблоне, вычисление не найдёт нужную переменную. Эти имена относятся к небольшому контракту между HCL и шаблоном. Сохраняйте их согласованно; наличие одинакового названия в разных файлах здесь не случайная косметика.

Полезно также различать отсутствие переменной и пустое значение. Значение по умолчанию используется, когда вход не задан; пустая строка является отдельным переданным значением и проходит через validation. Для префикса она будет отвергнута. Такой результат лучше молчаливой попытки создать контейнер с непонятным именем. В больших проектах аналогичный принцип помогает остановить ошибочную конфигурацию раньше внешнего изменения.

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

Почему входной файл содержит пример

Файл с суффиксом .example можно безопасно читать до подготовки среды. Он описывает форму входов и помогает заметить опечатку: external_port не заменяет объявленную port. Если передать неизвестный или неверно названный вход, ожидаемого изменения не получится. Не пытайтесь исправлять это дублированием настроек в ресурсе; сначала сопоставьте имя объявления и имя переданного значения.

Заголовок страницы не предназначен для пользователя из интернета. Мы явно ограничили его учебным алфавитом. Если в будущем он приходит из CMS, правильное решение состоит в изменении контракта вывода и экранировании для конкретного HTML-контекста. Одно выражение Terraform не превращает произвольную строку в безопасную разметку. Так маленький шаблон становится поводом понять границу между параметром инфраструктуры и содержимым настоящего сайта.

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

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

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