Skip to content

DNS-зоны и записи

Управление доменными зонами и их записями через Terraform вместо ручного ввода в личном кабинете. Показаны два подхода: зоны картой (разный набор) и зоны циклом (много однотипных).

Ресурсы

Ресурс Назначение
nubes_zones_v2 DNS-зона
nubes_zones_v2_record запись внутри зоны (A, AAAA, CNAME, MX, SRV, TXT, LUA, NS, SSHFP)

Запись — отдельный ресурс, поэтому одну запись можно изменить или удалить, не трогая зону целиком.

Провайдер

terraform {
  required_providers {
    nubes = {
      source  = "tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes"
      version = "3.6.3"
    }
  }
}

variable "api_token" { type = string; sensitive = true }

provider "nubes" {
  api_token    = var.api_token
  api_endpoint = "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc"
}

Токен держите в secrets.auto.tfvars (не в terraform.tfvars):

api_token = "***"   # ЛК → Профиль → Токены

Проверить файл поможет ИИ

Кнопка «TF» справа внизу: вставьте terraform.tfvars — ИИ вернёт исправленный файл и список изменений. Секреты не вставляйте.


Вариант 1 — зоны картой

Когда набор зон и записей разный, задайте всё одной картой zones.

variable "zones" {
  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"] }
        cdn = { type = "CNAME", values = ["www.tfzone-a.test."] }
      }
    }
    b = {
      zone_name = "tfzone-b.test"
      records = {
        www = { type = "A", values = ["10.0.0.9"] }
        api = { type = "A", values = ["10.0.0.8"] }
      }
    }
  }
}

# «Уплощаем» вложенную карту «зона → записи» в плоский набор записей.
locals {
  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
      }
    }
  ]...)
}

resource "nubes_zones_v2" "zone" {
  for_each      = var.zones
  resource_name = "dns-zone-${each.key}"
  zone_name     = each.value.zone_name
}

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
}

Вариант 2 — зоны циклом

Когда зон много и они однотипны (например поддомены app-1 … app-50), сгенерируйте их из одного числа:

variable "zone_count"  { type = number; default = 10 }
variable "zone_prefix" { type = string; default = "tfzone" }
variable "zone_domain" { type = string; default = "test" }

locals {
  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"] }
      }
    }
  }

  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
      }
    }
  ]...)
}

resource "nubes_zones_v2" "zone" {
  for_each      = local.zones
  resource_name = "dns-zone-${each.key}"
  zone_name     = each.value.zone_name
}

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
}

Итоговое имя зоны = <zone_prefix>-<i>.<zone_domain>, например tfzone-3.test.

Готовые файлы

Примеры лежат в репозитории tf_examples (клонируйте и зайдите в нужную папку):

git clone https://gitea.services.ngcloud.ru/Nail/tf_examples.git
cd tf_examples/dns_zones
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform plan
terraform apply
  • dns_zones/ — вариант 1 (карта зон);
  • dns_zones_generated/ — вариант 2 (цикл).

Важно

  • Ключ карты (a, b, www…) — это адрес объекта в state. Смена ключа = удалить + создать заново, а не переименовать. Значение (zone_name, values) меняйте свободно — обычный apply.
  • CNAME пишется с точкой на конце (www.example.com.).
  • Несколько адресов у одной записи — это один ресурс, а не несколько.
  • record_ttl допустим от 30 до 84000 секунд; record_type — только из списка типов выше (неверное значение отклонится ещё на этапе plan).
  • Чтобы зоны работали в интернете, делегируйте домен у регистратора на NS ns3.ngcloud.ru / ns4.ngcloud.ru.
  • После apply повторный plan должен показать No changes.