diff --git a/dns_zones/.terraform.lock.hcl b/dns_zones/.terraform.lock.hcl new file mode 100644 index 0000000..24a8b31 --- /dev/null +++ b/dns_zones/.terraform.lock.hcl @@ -0,0 +1,10 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes" { + version = "3.4.0" + constraints = "3.4.0" + hashes = [ + "h1:7wpWUTAHpddZXHiecwezW5qaNq17WJLTEnE/kF8lNN4=", + ] +} diff --git a/dns_zones/README.md b/dns_zones/README.md new file mode 100644 index 0000000..860be41 --- /dev/null +++ b/dns_zones/README.md @@ -0,0 +1,40 @@ +# DNS-зоны и записи через Terraform + +Пример: доменные зоны компании и записи в них — целиком через Terraform. +Зоны задаются картой `var.zones` (`for_each`), записи — вложенным циклом +(`flatten` + `for_each`). + +## Ресурсы + +| Ресурс | Сервис | Назначение | +|---|---|---| +| `nubes_zones_v2` | 109 | DNS-зона | +| `nubes_zones_v2_record` | подресурс зоны | Запись внутри зоны (A / CNAME / …) | + +## Что в конфиге + +- N зон из `var.zones` (по умолчанию 2: `tfzone-a.test`, `tfzone-b.test`); +- по 3 записи в каждой зоне (`A`, `A`, `CNAME`). + +Чтобы добавить/убрать зону или запись — правьте `var.zones`, затем `apply`. + +## Как запустить + +```bash +cp terraform.tfvars.example terraform.tfvars # подставить api_endpoint (если нужно) +# api_token — в secrets.auto.tfvars (НЕ в terraform.tfvars!) +terraform init +terraform plan +terraform apply # запускает пользователь +``` + +## Проверки + +- После `apply` повторный `plan` должен давать `No changes`. +- Изменение значения записи → обычный `apply` (поле `record_input` модифицируемое). +- Чтобы зона работала в интернете, домен у регистратора надо делегировать на NS + `ns3.ngcloud.ru` / `ns4.ngcloud.ru`. + +## См. также + +- `../dns_zones_generated/` — тот же сценарий, но N зон генерируются программно. diff --git a/dns_zones/main.tf b/dns_zones/main.tf new file mode 100644 index 0000000..e9c79ca --- /dev/null +++ b/dns_zones/main.tf @@ -0,0 +1,45 @@ +# ============================================================================= +# Пример: доменные зоны компании и записи в них — через Terraform. +# +# Ресурсы провайдера Nubes: +# - nubes_zones_v2 (сервис 109) — DNS-зона; +# - nubes_zones_v2_record (подресурс зоны, record) — запись внутри зоны. +# +# ⚠️ Имя поля в HCL = `name` из схемы (snake_case); `code` (camelCase) — имя в API. +# +# Зоны задаются картой `var.zones` (ключ → zone_name + records). +# Чтобы добавить/убрать зону или запись — правьте `var.zones` и делайте `apply`. +# ============================================================================= + +locals { + # Плоская карта записей «зона:имя» (вложенный цикл → merge/flatten), + # чтобы `for_each` у записей давал стабильные адреса. + records = merge([ + for zk, z in var.zones : { + for rk, r in z.records : + "${zk}:${rk}" => { + zone = zk + name = rk + type = r.type + values = r.values + } + } + ]...) +} + +# Зоны: N штук из var.zones (for_each по ключам карты — стабильные адреса). +resource "nubes_zones_v2" "zone" { + for_each = var.zones + resource_name = "dns-zone-${each.key}" + zone_name = each.value.zone_name +} + +# Записи: record_input = [{record=<значение>}, ...] из списка values. +resource "nubes_zones_v2_record" "record" { + for_each = local.records + zones_v2_id = nubes_zones_v2.zone[each.value.zone].id + record_name = each.value.name + record_type = each.value.type + record_input = jsonencode([for v in each.value.values : { record = v }]) + record_ttl = 3600 +} diff --git a/dns_zones/provider.tf b/dns_zones/provider.tf new file mode 100644 index 0000000..9d91910 --- /dev/null +++ b/dns_zones/provider.tf @@ -0,0 +1,4 @@ +provider "nubes" { + api_token = var.api_token + api_endpoint = var.api_endpoint +} diff --git a/dns_zones/terraform.tfvars.example b/dns_zones/terraform.tfvars.example new file mode 100644 index 0000000..43e85f5 --- /dev/null +++ b/dns_zones/terraform.tfvars.example @@ -0,0 +1,15 @@ +# Копировать в terraform.tfvars и подставить значения. +# ⚠️ api_token — СЕКРЕТ: сюда НЕ класть. Держите в отдельном secrets.auto.tfvars +# (формат: api_token = ""). Оба файла (*.tfvars) закрыты в .gitignore. + +api_endpoint = "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc" + +# Зоны задаются переменной `zones` (карта: ключ → zone_name + records). +# Дефолт — в variables.tf; здесь можно переопределить, напр.: +# +# zones = { +# a = { zone_name = "tfzone-a.test", records = { +# www = { type = "A", values = ["10.0.0.1", "10.0.0.2"] } +# cdn = { type = "CNAME", values = ["www.tfzone-a.test."] } +# } } +# } diff --git a/dns_zones/variables.tf b/dns_zones/variables.tf new file mode 100644 index 0000000..1e05895 --- /dev/null +++ b/dns_zones/variables.tf @@ -0,0 +1,44 @@ +# Переменные примера. api_token — СЕКРЕТ, держать в secrets.auto.tfvars (не коммитить). + +variable "api_token" { + description = "Nubes API token (JWT). Секрет — в secrets.auto.tfvars." + type = string + sensitive = true +} + +variable "api_endpoint" { + description = "API Gateway URL стенда" + type = string + default = "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc" +} + +# Зоны: карта «короткое имя → { zone_name, records }». +# records — карта «имя записи → { type, values }». +variable "zones" { + description = "Зоны компании: имя + записи (type / values[])" + type = map(object({ + zone_name = string + records = map(object({ + type = optional(string, "A") + values = list(string) + })) + })) + default = { + a = { + zone_name = "tfzone-a.test" + records = { + www = { type = "A", values = ["10.0.0.77", "203.0.113.14"] } + api = { type = "A", values = ["192.168.3.14", "10.0.0.2"] } + cdn = { type = "CNAME", values = ["www.tfzone-a.test."] } + } + } + b = { + zone_name = "tfzone-b.test" + records = { + www = { type = "A", values = ["172.16.5.20", "10.0.0.9"] } + api = { type = "A", values = ["10.0.0.8", "198.51.100.7"] } + cdn = { type = "CNAME", values = ["www.tfzone-b.test."] } + } + } + } +} diff --git a/dns_zones/versions.tf b/dns_zones/versions.tf new file mode 100644 index 0000000..65635b6 --- /dev/null +++ b/dns_zones/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.5.0" + + required_providers { + nubes = { + source = "tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes" + version = "3.4.0" + } + } +} diff --git a/dns_zones_generated/.terraform.lock.hcl b/dns_zones_generated/.terraform.lock.hcl new file mode 100644 index 0000000..24a8b31 --- /dev/null +++ b/dns_zones_generated/.terraform.lock.hcl @@ -0,0 +1,10 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes" { + version = "3.4.0" + constraints = "3.4.0" + hashes = [ + "h1:7wpWUTAHpddZXHiecwezW5qaNq17WJLTEnE/kF8lNN4=", + ] +} diff --git a/dns_zones_generated/README.md b/dns_zones_generated/README.md new file mode 100644 index 0000000..b2a9e5f --- /dev/null +++ b/dns_zones_generated/README.md @@ -0,0 +1,47 @@ +# N DNS-зон, сгенерированных программно (в цикле) + +Пример-близнец `../dns_zones/`, но здесь зоны **не задаются вручную**, а +генерируются из числа `var.zone_count`: + +```hcl +zones = { + for i in range(1, var.zone_count + 1) : + "${var.zone_prefix}-${i}" => { + zone_name = "${var.zone_prefix}-${i}.${var.zone_domain}" + records = { www = ..., api = ... } + } +} +``` + +Удобно, когда зон много и они однотипны (напр. 10 зон `tfzone-1 … tfzone-10`). + +## Ресурсы + +| Ресурс | Сервис | Назначение | +|---|---|---| +| `nubes_zones_v2` | 109 | DNS-зона | +| `nubes_zones_v2_record` | подресурс зоны | Запись внутри зоны (A / CNAME / …) | + +## Разница с `../dns_zones/` + +| | `dns_zones` | `dns_zones_generated` | +|---|---|---| +| Источник зон | явная карта `var.zones` | `range(1, zone_count+1)` в `locals` | +| Когда удобно | разный набор зон/записей | много однотипных зон | + +## Как запустить + +```bash +cp terraform.tfvars.example terraform.tfvars # при желании: zone_count = N +# api_token — в secrets.auto.tfvars (НЕ в terraform.tfvars!) +terraform init +terraform plan +terraform apply # запускает пользователь +``` + +## Проверки + +- После `apply` повторный `plan` должен давать `No changes`. +- Изменение `zone_count` добавляет/убирает зоны (стабильные адреса `for_each`). +- Чтобы зоны работали в интернете, домен у регистратора надо делегировать на NS + `ns3.ngcloud.ru` / `ns4.ngcloud.ru`. diff --git a/dns_zones_generated/main.tf b/dns_zones_generated/main.tf new file mode 100644 index 0000000..49fa0a5 --- /dev/null +++ b/dns_zones_generated/main.tf @@ -0,0 +1,54 @@ +# ============================================================================= +# Пример: N DNS-зон генерируются ПРОГРАММНО (в цикле) — через Terraform. +# +# Отличие от ../dns_zones/: там зоны заданы явной картой `var.zones`, +# а здесь зоны генерируются из числа `var.zone_count` через `range(...)`. +# Удобно, когда зон много и они однотипны (tfzone-1 … tfzone-N). +# +# Ресурсы: nubes_zones_v2 (109) + подресурс nubes_zones_v2_record (записи). +# ⚠️ Имя поля в HCL = `name` из схемы (snake_case). +# ============================================================================= + +locals { + # N зон генерируются программно: tfzone-1 … tfzone-N. + zones = { + for i in range(1, var.zone_count + 1) : + "${var.zone_prefix}-${i}" => { + zone_name = "${var.zone_prefix}-${i}.${var.zone_domain}" + records = { + www = { type = "A", values = ["10.0.${i}.1"] } + api = { type = "A", values = ["10.0.${i}.2"] } + } + } + } + + # Плоская карта записей «зона:имя» (вложенный цикл → merge/flatten). + records = merge([ + for zk, z in local.zones : { + for rk, r in z.records : + "${zk}:${rk}" => { + zone = zk + name = rk + type = r.type + values = r.values + } + } + ]...) +} + +# Зоны: N штук, сгенерированных в locals (for_each по ключам — стабильные адреса). +resource "nubes_zones_v2" "zone" { + for_each = local.zones + resource_name = "dns-zone-${each.key}" + zone_name = each.value.zone_name +} + +# Записи: record_input = [{record=<значение>}, ...] из списка values. +resource "nubes_zones_v2_record" "record" { + for_each = local.records + zones_v2_id = nubes_zones_v2.zone[each.value.zone].id + record_name = each.value.name + record_type = each.value.type + record_input = jsonencode([for v in each.value.values : { record = v }]) + record_ttl = 3600 +} diff --git a/dns_zones_generated/provider.tf b/dns_zones_generated/provider.tf new file mode 100644 index 0000000..9d91910 --- /dev/null +++ b/dns_zones_generated/provider.tf @@ -0,0 +1,4 @@ +provider "nubes" { + api_token = var.api_token + api_endpoint = var.api_endpoint +} diff --git a/dns_zones_generated/terraform.tfvars.example b/dns_zones_generated/terraform.tfvars.example new file mode 100644 index 0000000..8c2e743 --- /dev/null +++ b/dns_zones_generated/terraform.tfvars.example @@ -0,0 +1,10 @@ +# Копировать в terraform.tfvars и подставить значения. +# ⚠️ api_token — СЕКРЕТ: сюда НЕ класть. Держите в отдельном secrets.auto.tfvars +# (формат: api_token = ""). Оба файла (*.tfvars) закрыты в .gitignore. + +api_endpoint = "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc" + +# Сколько зон сгенерировать (tfzone-1 … tfzone-N): +zone_count = 10 +zone_prefix = "tfzone" +zone_domain = "test" diff --git a/dns_zones_generated/variables.tf b/dns_zones_generated/variables.tf new file mode 100644 index 0000000..7fabd90 --- /dev/null +++ b/dns_zones_generated/variables.tf @@ -0,0 +1,31 @@ +# Переменные примера. api_token — СЕКРЕТ, держать в secrets.auto.tfvars. + +variable "api_token" { + description = "Nubes API token (JWT). Секрет — в secrets.auto.tfvars." + type = string + sensitive = true +} + +variable "api_endpoint" { + description = "API Gateway URL стенда" + type = string + default = "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc" +} + +variable "zone_count" { + description = "Сколько зон сгенерировать (tfzone-1 … tfzone-N)" + type = number + default = 10 +} + +variable "zone_prefix" { + description = "Префикс имени зоны" + type = string + default = "tfzone" +} + +variable "zone_domain" { + description = "Домен зон (суффикс FQDN)" + type = string + default = "test" +} diff --git a/dns_zones_generated/versions.tf b/dns_zones_generated/versions.tf new file mode 100644 index 0000000..65635b6 --- /dev/null +++ b/dns_zones_generated/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.5.0" + + required_providers { + nubes = { + source = "tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes" + version = "3.4.0" + } + } +}