当前位置: 首页 > Linux > [企业DNS系列四]通过Terraform管理PowerDNS

[企业DNS系列四]通过Terraform管理PowerDNS

Linux 0条评论 2021-8-8 2,376 views

通过前面三篇文章,企业DNS已经可以稳定运行了,下一步就是DNS日常的运维管理,其中工作量最大的就在于正反向(A/PTR)解析记录的维护,下来我带大家使用通过Terraform工具,以IaC(基础架构即代码)的方式维护DNS解析记录。

Terraform管理PowerDNS概述

Terraform是我个人常用的基础架构即代码工具,之前的文章中,通过Terraform实现虚拟机的批量部署,对于DNS的管理Terraform支持也非常好,目前有两种方式:1)基于TSIG(RFC 2845)协议,Terraform官方的DNS插件;2)第三方的PowerDNS插件;本示例中我们使用第三方PowerDNS插件。

Terraform安装

Terraform采用GO语言编写,安装非常简单,只需要将terraform二进制文件拷贝到bin目录即可。

wget https://releases.hashicorp.com/terraform/1.0.4/terraform_1.0.4_linux_amd64.zip
unzip terraform_1.0.4_linux_amd64.zip
cp terraform /usr/local/bin/
chmod +x /usr/local/bin/terraform
export PATH=/usr/local/bin:$PATH
terraform version

准备Terraform相关HCL文件

Terraform是基于目录的,所以必须为每个计划创建一个独立的工作目录,实际上工作目录管理是后期使用很重要的一点,包括公用module等,请大家通过官网进行学习。

cd ~
mkdir terraform-powerdns
cd terraform-powerdns

Terraform 执行命令时会读取工作目录中所有的 .tf, .tfvars 文件,所以我们不必把所有的东西都写在单个文件中去,应按职责分列在不同的文件中,例如:

文件名说明
terraform.tfvars配置provider要用的变量
varable.tf通用变量
main.tf资源定义
output.tf输出定义

准备main.tf文件

main.tf文件用于执行编排工作,其中provide代表你要编排的目标平台,resource用于声明资源,terraform会基于此声明对比环境中是否一致,如果不一致terraform将修复到一致状态。

  1. 第1-12行,定义provide是PowerDNS,并从terraform.tfvars中读取配置
  2. 第14-21行,定义A记录资源,通过读取terraform.tfvars中的变量动态生成多个资源
  3. 第22-29行,定义PTR记录资源,通过读取terraform.tfvars中的变量动态生成多个资源
terraform {
  required_providers {
    powerdns = {
      source = "pan-net/powerdns"
    }
  }
}

provider "powerdns" {
  server_url = var.pdns_api_server
  api_key    = var.pdns_api_key
}

resource "powerdns_record" "dns_a_record" {
  for_each = var.hosts
  zone     = var.dnszonename
  name     = each.value.name
  type     = "A"
  ttl      = each.value.ttl
  records  = [each.value.ipv4_addr]
}
resource "powerdns_record" "dns_ptr_record" {
  for_each = var.hosts
  zone     = each.value.ptr_zone_name
  name     = "${element(split(".", each.value.ipv4_addr), 3)}.${each.value.ptr_zone_name}"
  type     = "PTR"
  ttl      = each.value.ttl
  records  = [each.value.name]
}

准备terraform.tfvars文件

terraform.tfvars文件用于变量赋值,例如:PowerDNS地址、Key、DNS记录等。

  1. 第1-14行,以数组的方式定义需要创建的DNS记录(Name和Ptr_zone_name必须以"."结尾)
  2. 第15行,以字符串方式定义Domain Zone名称(必须以"."结尾)
  3. 第16-17行,定义PowerDNS API URL和Key(必须是Master节点)

提示1:如果增加或删除记录,只需在Hosts数组中添加内容即可。 提示2:正反向解析Zones需要预先创建。

hosts = {
  blog = {
    name          = "blog.test.local."
    ipv4_addr     = "10.208.0.66"
    ttl           = "60"
    ptr_zone_name = "0.208.10.in-addr.arpa."
  },
  demo = {
    name          = "demo.test.local."
    ipv4_addr     = "10.208.0.67"
    ttl           = "60"
    ptr_zone_name = "0.208.10.in-addr.arpa."
  },
}
dnszonename     = "test.local."
pdns_api_server = "http://10.208.0.101:8081"
pdns_api_key    = "vmware"

准备variables.tf文件

variables.tf文件用于定义变量名称和类型,这是必须的,如果您希望使用新的变量或者修改变量类型,请在对应修改variables.tf文件。

variable "hosts" {
  type        = map(any)
  description = "Host list for dns record."
}
variable "dnszonename" {
  description = "The Zone name in PowerDNS."
}
variable "pdns_api_server" {
  description = "The Powerdns API Server URL."
}
variable "pdns_api_key" {
  description = "The Powerdns API Key."
}

执行初始化和测试

需要先在工作目录下初始化插件,Terraform会自动下载缺少的插件到本地目录中(.terraform)。

terraform init
terraform plan

Terraform Plan显示需要创建/删除的对象,可以用于判断HCL是否正确。

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # powerdns_record.dns_a_record["blog"] will be created
  + resource "powerdns_record" "dns_a_record" {
      + id      = (known after apply)
      + name    = "blog.test.local."
      + records = [
          + "10.208.0.66",
        ]
      + ttl     = 60
      + type    = "A"
      + zone    = "test.local."
    }

  # powerdns_record.dns_a_record["demo"] will be created
  + resource "powerdns_record" "dns_a_record" {
      + id      = (known after apply)
      + name    = "demo.test.local."
      + records = [
          + "10.208.0.67",
        ]
      + ttl     = 60
      + type    = "A"
      + zone    = "test.local."
    }

  # powerdns_record.dns_ptr_record["blog"] will be created
  + resource "powerdns_record" "dns_ptr_record" {
      + id      = (known after apply)
      + name    = "66.0.208.10.in-addr.arpa."
      + records = [
          + "blog.test.local.",
        ]
      + ttl     = 60
      + type    = "PTR"
      + zone    = "0.208.10.in-addr.arpa."
    }

  # powerdns_record.dns_ptr_record["demo"] will be created
  + resource "powerdns_record" "dns_ptr_record" {
      + id      = (known after apply)
      + name    = "67.0.208.10.in-addr.arpa."
      + records = [
          + "demo.test.local.",
        ]
      + ttl     = 60
      + type    = "PTR"
      + zone    = "0.208.10.in-addr.arpa."
    }

Plan: 4 to add, 0 to change, 0 to destroy.

执行部署计划

确认是目标期望状态后,执行计划,完成部署。

terraform apply -auto-approve

通过命令输出可以看到有4个资源被创建,2个A记录和2个PTR记录。

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # powerdns_record.dns_a_record["blog"] will be created
  + resource "powerdns_record" "dns_a_record" {
      + id      = (known after apply)
      + name    = "blog.test.local."
      + records = [
          + "10.208.0.66",
        ]
      + ttl     = 60
      + type    = "A"
      + zone    = "test.local."
    }

  # powerdns_record.dns_a_record["demo"] will be created
  + resource "powerdns_record" "dns_a_record" {
      + id      = (known after apply)
      + name    = "demo.test.local."
      + records = [
          + "10.208.0.67",
        ]
      + ttl     = 60
      + type    = "A"
      + zone    = "test.local."
    }

  # powerdns_record.dns_ptr_record["blog"] will be created
  + resource "powerdns_record" "dns_ptr_record" {
      + id      = (known after apply)
      + name    = "66.0.208.10.in-addr.arpa."
      + records = [
          + "blog.test.local.",
        ]
      + ttl     = 60
      + type    = "PTR"
      + zone    = "0.208.10.in-addr.arpa."
    }

  # powerdns_record.dns_ptr_record["demo"] will be created
  + resource "powerdns_record" "dns_ptr_record" {
      + id      = (known after apply)
      + name    = "67.0.208.10.in-addr.arpa."
      + records = [
          + "demo.test.local.",
        ]
      + ttl     = 60
      + type    = "PTR"
      + zone    = "0.208.10.in-addr.arpa."
    }

Plan: 4 to add, 0 to change, 0 to destroy.
powerdns_record.dns_a_record["demo"]: Creating...
powerdns_record.dns_a_record["blog"]: Creating...
powerdns_record.dns_ptr_record["demo"]: Creating...
powerdns_record.dns_ptr_record["blog"]: Creating...
powerdns_record.dns_ptr_record["demo"]: Creation complete after 0s [id=67.0.208.10.in-addr.arpa.:::PTR]
powerdns_record.dns_a_record["demo"]: Creation complete after 0s [id=demo.test.local.:::A]
powerdns_record.dns_ptr_record["blog"]: Creation complete after 0s [id=66.0.208.10.in-addr.arpa.:::PTR]
powerdns_record.dns_a_record["blog"]: Creation complete after 0s [id=blog.test.local.:::A]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

登录PowerDNS-Admin检查记录

(可选)销毁资源测试

terraform destory
yes

通过执行日志可以看到,Terraform成功的删除了4个对象。

powerdns_record.dns_ptr_record["demo"]: Refreshing state... [id=67.0.208.10.in-addr.arpa.:::PTR]
powerdns_record.dns_a_record["blog"]: Refreshing state... [id=blog.test.local.:::A]
powerdns_record.dns_ptr_record["blog"]: Refreshing state... [id=66.0.208.10.in-addr.arpa.:::PTR]
powerdns_record.dns_a_record["demo"]: Refreshing state... [id=demo.test.local.:::A]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  - destroy

Terraform will perform the following actions:

  # powerdns_record.dns_a_record["blog"] will be destroyed
  - resource "powerdns_record" "dns_a_record" {
      - id      = "blog.test.local.:::A" -> null
      - name    = "blog.test.local." -> null
      - records = [
          - "10.208.0.66",
        ] -> null
      - ttl     = 60 -> null
      - type    = "A" -> null
      - zone    = "test.local." -> null
    }

  # powerdns_record.dns_a_record["demo"] will be destroyed
  - resource "powerdns_record" "dns_a_record" {
      - id      = "demo.test.local.:::A" -> null
      - name    = "demo.test.local." -> null
      - records = [
          - "10.208.0.67",
        ] -> null
      - ttl     = 60 -> null
      - type    = "A" -> null
      - zone    = "test.local." -> null
    }

  # powerdns_record.dns_ptr_record["blog"] will be destroyed
  - resource "powerdns_record" "dns_ptr_record" {
      - id      = "66.0.208.10.in-addr.arpa.:::PTR" -> null
      - name    = "66.0.208.10.in-addr.arpa." -> null
      - records = [
          - "blog.test.local.",
        ] -> null
      - ttl     = 60 -> null
      - type    = "PTR" -> null
      - zone    = "0.208.10.in-addr.arpa." -> null
    }

  # powerdns_record.dns_ptr_record["demo"] will be destroyed
  - resource "powerdns_record" "dns_ptr_record" {
      - id      = "67.0.208.10.in-addr.arpa.:::PTR" -> null
      - name    = "67.0.208.10.in-addr.arpa." -> null
      - records = [
          - "demo.test.local.",
        ] -> null
      - ttl     = 60 -> null
      - type    = "PTR" -> null
      - zone    = "0.208.10.in-addr.arpa." -> null
    }

Plan: 0 to add, 0 to change, 4 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

powerdns_record.dns_ptr_record["blog"]: Destroying... [id=66.0.208.10.in-addr.arpa.:::PTR]
powerdns_record.dns_a_record["demo"]: Destroying... [id=demo.test.local.:::A]
powerdns_record.dns_a_record["blog"]: Destroying... [id=blog.test.local.:::A]
powerdns_record.dns_ptr_record["demo"]: Destroying... [id=67.0.208.10.in-addr.arpa.:::PTR]
powerdns_record.dns_ptr_record["blog"]: Destruction complete after 0s
powerdns_record.dns_a_record["blog"]: Destruction complete after 0s
powerdns_record.dns_ptr_record["demo"]: Destruction complete after 0s
powerdns_record.dns_a_record["demo"]: Destruction complete after 0s

Destroy complete! Resources: 4 destroyed.

Gitlab+Terraform实现基于Git的管理

虽然我们通过Terraform实现了PowerDNS的解析记录管理,但每次创建的记录的原因依然难于管理,这里推荐使用GitLab进行Terraform的HCL版本管理,并使用Gitlab CI/CD执行Terraform的流水线。

至此,我们实现了通过IaC方式管理PowerDNS的解析记录,当然Terraform也支持管理Zones,有需要的可以自行尝试。


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注