Как я могу заставить поставщика Docker в Terraform ждать, пока адрес станет доступным, прежде чем пытаться подключиться к нему?
В Terraform у меня есть следующий ресурс:
provider "docker" {
host = "tcp://${digitalocean_droplet.docker_server.ipv4_address}:2376/"
}
Это зависит от значения ipv4_address
быть известным до того, как он сможет подключиться к докеру. Это значение неизвестно, пока не будет предоставлен другой ресурс:
resource "digitalocean_droplet" "docker_server" {
image = "docker-18-04"
name = "docker_server"
region = "nyc2"
size = "512mb"
private_networking = true
ssh_keys = [
var.ssh_fingerprint
]
connection {
user = "root"
type = "ssh"
private_key = file(var.pvt_key)
timeout = "2m"
}
}
Когда я бегу terraform plan
, Я получаю следующую ошибку:
Ошибка: ошибка инициализации клиента Docker: невозможно проанализировать хост докера ''
в строке 1 docker.tf в провайдере "docker": 1: provider "docker" {
Похоже, что ipv4_address
пусто, потому что подключаемый модуль докера пытается подключиться к докеру до его подготовки. Как мне сказать ему дождаться подготовки машины, прежде чем пытаться подключиться к ней?
Я пробовал одну вещь:
provider "docker" {
host = "tcp://${digitalocean_droplet.docker_server.ipv4_address}:2376/"
depends_on = [
digitalocean_droplet.docker_server.ipv4_address,
]
}
Когда я это сделаю, я получаю такую ошибку:
Ошибка: зарезервированное имя аргумента в блоке поставщика
в строке 4 docker.tf в "docker" провайдера: 4: depends_on = [
Имя аргумента поставщика "зависит_он" зарезервировано для использования Terraform в будущей версии.
Но читая больше в depends_on
, Я все равно не думаю, что это решение.
1 ответ
К сожалению, блок поставщика не поддерживает выражения, относящиеся к атрибуту ресурса.
Это ограничение объясняется в документации по конфигурации провайдера:
Аргументы конфигурации, определенные поставщиком, могут быть назначены с помощью выражений, которые, например, могут позволить параметризовать их с помощью входных переменных.
Однако, поскольку конфигурации поставщика должны быть оценены для выполнения любого действия типа ресурса, конфигурации поставщика могут относиться только к значениям, которые известны до применения конфигурации.
В частности, избегайте ссылок на атрибуты, экспортируемые другими ресурсами, если их значения не указаны непосредственно в конфигурации.
Например, это сработает (но не решит вашу проблему):
variable "docker_host" {
type = string
}
provider "docker" {
host = "tcp://${var.docker_host}:2376/"
}
Но выход есть.
Решение состоит из двух шагов:
- разделите вашу конфигурацию terraform на две части (каждая должна находиться в своем собственном каталоге), где одна с поставщиком докеров зависит от того, который развертывает дроплет. Обратите внимание, что это означает, что вам придется вводить команды терраформирования отдельно (вам нужно применить дважды).
- Установите однонаправленное "соединение" только для чтения между двумя состояниями с помощью функции, называемой удаленным состоянием:
Получает данные о состоянии из серверной части Terraform. Это позволяет вам использовать выходные данные корневого уровня одной или нескольких конфигураций Terraform в качестве входных данных для другой конфигурации.
Если вы еще не используете "настоящий" удаленный сервер, такой как S3 + DynamoDB, вы все равно можете легко экспериментировать с локальным сервером, как показано ниже.
Макет каталога:
├── docker <== this performs docker operation
│ ├── main.tf
│ └── terraform.tfstate
└── server <== this deploys the droplet
├── main.tf
└── terraform.tfstate
В приведенных ниже фрагментах используется AWS, но адаптировать его к DO несложно.
Файловый сервер /main.tf содержит нечто похожее на
resource "aws_instance" "server" { <= equivalent to the Droplet
...
}
output "ipv4_address" {
value = aws_instance.server.public_ip
}
Файл docker/main.tf содержит нечто похожее на
data "terraform_remote_state" "docker_server" {
backend = "local"
config = {
path = "${path.module}/../server/terraform.tfstate"
}
}
provider "docker" {
host = "tcp://${data.terraform_remote_state.docker_server.outputs.ipv4_address}:2376/"
}
В заключение:
cd server
terraform apply
cd ../docker
terraform apply
Помните: вы должны выполнять также отдельные terraform destroy
, в порядке LIFO: сначала уничтожить docker
, затем уничтожить server
.