Принятие существующего контейнера под управление
Иногда инфраструктура уже существует: контейнер создан вручную, а теперь его хотят описывать через Terraform. Для этого служит импорт. Он устанавливает связь между адресом ресурса и существующим идентификатором; не заменяет подготовку конфигурации и не доказывает, что следующий план безопасен. В «Контуре» мы разбираем импорт в отдельной папке adoption, чтобы не смешивать его с основными сайтами.
Наша учебная цель — подготовить описание одного локального контейнера, который раньше не входил в состояние Terraform. Сам контейнер здесь не создаётся и не импортируется. Читатель сначала выбирает принадлежащий ему лабораторный объект и собирает реальные сведения: имя, идентификатор образа, порт, сетевые настройки и прочие важные аргументы. Демонстрационный файл с заполнителями не является основанием для изменения настоящего объекта.
Конфигурация до импорта
adoption/main.tf содержит один ресурс docker_container.adopted. Имя и идентификатор образа поступают через переменные, внешний порт — через отдельный числовой вход. Для краткой лаборатории предполагается обычный контейнер с внутренним портом 80 и привязкой хостового порта к loopback. Если реальный выбранный контейнер устроен иначе, его конфигурацию надо расширить до соответствия. Нельзя взять этот короткий файл как описание любого Docker-контейнера.
Полный файл adoption/main.tf для этого состояния:
variable "container_name" { type = string }
variable "image_id" { type = string }
variable "external_port" { type = number }
resource "docker_container" "adopted" {
name = var.container_name
image = var.image_id
ports {
internal = 80
external = var.external_port
ip = "127.0.0.1"
}
}
Команды для отдельной самостоятельной работы читателя; при написании не выполнялись:
terraform import -var-file=terraform.tfvars docker_container.adopted ACTUAL_CONTAINER_ID
terraform plan -var-file=terraform.tfvars
В terraform.tfvars.example вместо image_id стоит явный заполнитель. Его заменяют настоящим Docker image ID, а не именем образа «на глаз». Та же точность нужна для идентификатора контейнера в команде импорта. Длинные идентификаторы выглядят неудобно, но их задача — обозначать конкретный объект. Выбор по похожему человеческому имени без проверки легко передаёт под управление чужой контейнер.
Папка adoption имеет собственные требования провайдера и своё отдельное локальное состояние. Если выполнять команды из корня «Контура», ресурс docker_container.adopted там не объявлен. Если выполнять из adoption, модули основных сайтов туда не входят. Это не вопрос расположения строки в файле, а вопрос выбранного корневого модуля. Сначала определите рабочую директорию, затем обсуждайте импортируемый адрес.
Связь, которая не создаёт контейнер
После самостоятельной подготовки можно выполнить terraform import docker_container.adopted ACTUAL_CONTAINER_ID. Последняя часть здесь является условным обозначением и должна быть заменена настоящим идентификатором. Команда предназначена для записи управления существующим объектом. Она не скачивает вместо него новый Nginx и не должна восприниматься как обход конфликта имени. Import связывает известный объект с известным адресом состояния.
Сразу после импорта нужен обычный план. Он сравнит объявленное намерение с тем, что провайдер прочитал о контейнере. Если в конфигурации забыта настройка сети или перепутан порт, план может предлагать изменение или замену. Сам успех импорта не означает, что эта замена желательна. До применения необходимо привести описание к реальному согласованному контракту или явно принять конкретное изменение как отдельную миграцию.
Рассмотрим пример: контейнер использует внешний 8090, а в файле по ошибке указано 8088. Импорт может успешно запомнить объект, затем план покажет разницу. Это не ошибка механизма импорта. Конфигурация действительно требует другой порт. Исправление зависит от намерения: сохранить существующий доступ — значит изменить вход, перенести доступ — значит подготовить последствия замены. Нельзя подавить любую разницу, просто назвав её шумом провайдера.
Один объект и один владелец
Особенно опасна ситуация, когда выбранный контейнер уже присутствует в другом state. Повторный импорт в adoption создаст второй центр управления. Две конфигурации смогут спорить о портах, образе и имени. Поэтому до импорта проверяют владение: откуда объект был создан, каким процессом обновляется и какое состояние уже связано с ним. Terraform не является глобальным реестром всех рабочих папок на компьютере.
Если объект надо передать из одного состояния в другое, это отдельная согласованная операция с копиями данных, прекращением прежнего управления и обзором нового плана. Наш урок не предлагает автоматического рецепта для неизвестных рабочих состояний. Для безопасной учебной ситуации выбирается контейнер, который точно создан вне Terraform и принадлежит отдельной лаборатории. Это ограничение уменьшает количество неявных участников операции.
Импорт не переносит бизнес-данные. Если контейнер содержит загруженные файлы или важную базу внутри своего записываемого слоя, эта проблема остаётся прежней. После импорта конфигурационная замена способна уничтожить слой. Сначала обеспечивают подходящее хранение и восстановление данных, затем обсуждают управление жизненным циклом. В нашей демонстрации контейнер отдаёт одноразовую статическую страницу, поэтому такой риск назван, но не маскируется сложной фиктивной процедурой резервирования.
Разбор расхождения после импорта
На практике часть аргументов может иметь значения по умолчанию, а часть — вычисляемые значения провайдера. Не следует копировать весь вывод состояния в конфигурацию. Вычисляемый идентификатор описывает результат, а не обязательно допустимый вход. Надо читать схему ресурса для выбранной версии и понимать, какие свойства задают намерение. Поэтому в плане курса закреплена конкретная версия Docker-провайдера, а ссылки ведут к её первичной документации.
Представим, что имя совпадает и порт совпадает, но реальный контейнер использует другой image ID. Импорт всё равно может установить связь; последующий план покажет желание перейти на объявленный образ. Проверяйте не только видимые человеку поля. Идентичность байтов образа, способ запуска и сетевые параметры определяют поведение сервера. Учебный HTML не является достаточным доказательством совпадения инфраструктурных конфигураций.
Результат урока — отдельный подготовленный модуль принятия ресурса и понятная последовательность: определить объект, описать его, связать адрес, рассмотреть разницу. Никаких действий над контейнером в процессе написания не выполнялось. Следующий урок продолжит тему внешних фактов: что делать, когда объект уже управляется Terraform, но его параметры или существование изменены вне конфигурации.
Импорт и постоянство исходников
После успешного будущего импорта конфигурация должна оставаться в репозитории. Удалить блок ресурса потому, что «он уже принят», означает убрать декларативное намерение. Обычный последующий план тогда предложит прекращение управления с удалением ресурса по его правилам. Import не создаёт вечное исключение из жизненного цикла Terraform. Он лишь начинает связь, которая затем обслуживается обычной конфигурацией.
Также храните запись о том, какие свойства сознательно оставлены провайдеру. Например, вычисляемый идентификатор не превращается в постоянный вход ресурса только потому, что виден в состоянии. Такие заметки помогают следующему владельцу отличить пробел в описании от нормального вычисляемого значения. Читаемое управление существующим объектом требует понимания схемы, а не механического переноса всего диагностического вывода в файл.
Оглавление серии, общая подборка и полный архив исходников. Для этого урока выберите lesson-09.
Первичные источники: Версии Terraform, Учебник Terraform и Docker, Схема Docker container 3.6.2, Схема Docker image 3.6.2, Адреса и moved, Локальный backend, Import, Refresh-only plan.
Редакционный статус: локальный черновик. Учебные команды, приложение и проверки не запускались; описанные результаты ожидаемые. Профиль версий закреплён, разрешённый lockfile не создавался.