通过前面三篇文章,企业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-12行,定义provide是PowerDNS,并从terraform.tfvars中读取配置
- 第14-21行,定义A记录资源,通过读取terraform.tfvars中的变量动态生成多个资源
- 第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-14行,以数组的方式定义需要创建的DNS记录(Name和Ptr_zone_name必须以"."结尾)
- 第15行,以字符串方式定义Domain Zone名称(必须以"."结尾)
- 第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,有需要的可以自行尝试。