Сеть, ссылки между ресурсами и выходные значения
Параметры позволяют настроить сайт, но его связи пока ограничены образом. Добавим в «Контур» отдельную Docker-сеть и выходные значения. Учебная цель состоит в чтении графа зависимостей: контейнер получает идентификатор образа и сети, а корневой модуль возвращает адрес для браузера. Это не требует явного описания очередности команд.
Сеть Docker группирует контейнеры и задаёт внутреннюю область соединений. Она отличается от опубликованного порта хоста. Браузер использует loopback-адрес на компьютере; контейнеры внутри именованной сети могут обращаться друг к другу по собственным правилам DNS и адресации. В лаборатории сейчас один сервер, поэтому сеть кажется избыточной. Она нужна как самостоятельный ресурс, который далее станет общим для нескольких сайтов.
Значение ссылки и значение имени
В network.tf объявлен docker_network.web с именем ${var.prefix}-network. Префикс тот же, что у контейнера, потому что он обозначает принадлежность окружению. Однако совпадение строк само по себе не создаёт связь. Контейнер должен явно подключиться к сети. Для этого в его блоке networks_advanced используем docker_network.web.id. Провайдер принимает имя или идентификатор сети; ссылка на управляемый ресурс выбирает идентификатор без ручного копирования.
Terraform видит выражение и понимает: значение сети потребуется прежде, чем контейнер сможет получить нужную настройку. Это вычислимая зависимость. Положение блоков в файлах значения не имеет. Можно расположить network.tf после main.tf в алфавитном списке, и граф останется тем же. Добавлять depends_on к каждой ссылке не нужно: оно применяется к особым зависимостям, которые невозможно выразить передачей значения.
Полный файл network.tf для этого состояния:
resource "docker_network" "web" {
name = "${var.prefix}-network"
}
Полный файл outputs.tf для этого состояния:
output "url" { value = "http://127.0.0.1:${var.port}" }
output "container_id" { value = docker_container.web.id }
Полный файл main.tf для этого состояния:
resource "docker_container" "web" {
name = "${var.prefix}-web"
image = docker_image.web.image_id
networks_advanced { name = docker_network.web.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 })
}
}
Частая ошибка — записать буквальную строку kontur-network вместо ссылки, одновременно сохранив ресурс сети. Человек видит одинаковые имена, но Terraform не обязан выводить зависимость из их совпадения. Если позже префикс изменится, строка также отстанет от конфигурации. Выражение с id делает и связь, и последующую настройку явными. Этот приём будет повторён в модуле сайта, где корень передаст сеть как вход.
Выход модуля для человека
Файл outputs.tf вводит url и container_id. Первый строится из выбранного внешнего порта. Второй получает фактическую идентичность контейнера от провайдера. Оба значения можно прочитать средствами Terraform после самостоятельного применения, но они имеют разные свойства. URL представляет обещанный маршрут подключения; идентификатор возникает только у настоящего созданного объекта. На стадии первого плана часть значений может ещё быть неизвестна.
URL не включает имя сети, потому что браузер работает вне её внутренней DNS-области. Нельзя подставить ${var.prefix}-network вместо 127.0.0.1 и ожидать доступности из браузера. Имя Docker-сети не является доменным именем сайта на хосте. Аналогично имя контейнера может разрешаться для соседнего контейнера, но не для любой программы операционной системы. Выходные значения помогают сделать эту границу понятной без изучения всего сетевого стека.
Не считайте output «проверкой доступности». Его вычисление может успешно вернуть http://127.0.0.1:8088, даже если сервер отвечает неподходящей страницей. Выход выражает данные, которыми конфигурация располагает, а не выполняет произвольную диагностику. Для будущего запуска отдельно сопоставляют адрес, ответ HTTP и ожидаемый HTML. В этой статье такие наблюдения описаны как ожидаемые, поскольку ни сеть, ни контейнер редакционно не создавались.
Общая сеть и независимые адреса
Представим будущие сайты home и docs. Они смогут использовать одну сеть и один образ Nginx, но на хосте каждому потребуется отдельная пара адреса и порта. Это два разных вида совместного использования: внутренний транспорт допускает несколько участников, а один опубликованный сокет нельзя отдать двум контейнерам одновременно. Поэтому входы следующего урока будут проверять уникальность внешних портов.
У такой сети остаются ограничения. Наличие именованной сети не создаёт firewall приложения, не включает шифрование и не ограничивает HTTP по пользователям. По умолчанию другие контейнеры, которым разрешено подключение, способны использовать внутренний адрес. Для более строгой инфраструктуры потребуются отдельные решения по изоляции и маршрутизации. Мы не будем объявлять лабораторную bridge-сеть полноценной корпоративной границей безопасности.
Теперь рассмотрим перенос конфигурации. Если изменить только префикс сети, настоящее имя ресурса может потребовать замены. Контейнер зависит от её идентификатора и поэтому тоже получит изменённую настройку. План покажет последствия через граф. Это полезнее ручного списка действий «сначала удалить контейнер, потом сеть»: такой список слишком рано фиксирует одну реализацию вместо декларативного намерения. Но человек всё равно обязан прочитать итоговую замену и возможную остановку.
Другая ошибка возникает при использовании собственного IP контейнера в output. Внутренний IP может измениться при пересоздании, а Docker Desktop на некоторых платформах помещает сеть в отдельную виртуальную машину. Хостовый браузер не обязан напрямую достигать такого адреса. Для нашего учебного пользовательского входа устойчивее использовать опубликованный loopback-порт. Внутренние адреса можно возвращать для специальных потребителей, если их среда и назначение названы явно.
«Контур» теперь представляет небольшой граф: образ и сеть являются зависимостями контейнера, а адрес страницы выражен отдельным выходом. Читатель должен суметь объяснить каждую стрелку этого графа и отличить вычисляемую связь от похожих строк. Следующий шаг усложнит количество экземпляров, сохранив ту же модель. Мы создадим два сайта через for_each и увидим, почему устойчивый ключ ресурса полезнее позиции в списке.
Зависимость от значения и зависимость от готовности
Ссылка на идентификатор сети означает, что её ресурс нужен для настройки контейнера. Она не означает, что удалённый HTTP-сервис внутри другого контейнера уже готов отвечать. Даже если Terraform создал процесс раньше, приложение способно продолжать инициализацию. Эти уровни часто смешивают при добавлении базы данных. Для готовности нужен отдельный контракт и подходящий механизм наблюдения, а не просто дополнительный depends_on.
В нашем статическом сервере зависимости ограничены образом и сетью. Поэтому граф легко проверить глазами: нет скрытого внешнего API и отдельной базы. При последующем расширении записывайте новую зависимость через тот механизм, который соответствует её природе. Значение передают выражением, политику порядка описывают отдельно, готовность приложения подтверждают наблюдением. Такой порядок сохраняет читаемость конфигурации даже тогда, когда сайтов становится больше.
Оглавление серии, общая подборка и полный архив исходников. Для этого урока выберите lesson-05.
Первичные источники: Версии Terraform, Учебник Terraform и Docker, Схема Docker container 3.6.2, Схема Docker image 3.6.2, Адреса и moved, Локальный backend, Import, Refresh-only plan.
Редакционный статус: локальный черновик. Учебные команды, приложение и проверки не запускались; описанные результаты ожидаемые. Профиль версий закреплён, разрешённый lockfile не создавался.