用 Terraform 和 Wercker 管理 DNS 记录.
首先
我最近使用Terraform在GitHub上構建了一個能夠管理Google Cloud DNS並從Wercker自動同步的環境,它的便利程度讓我感到非常驚喜。
这个有两个主要的益处。
-
- Terraform と Git による DNS レコードのバージョン管理
-
- GitHub と Wercker による自動反映
- チーム開発などで複数人がレコードを管理する事が容易になる (Pull Request を出してもらってレビュー後に master へ merge するだけ)
因为我挺喜欢这个,所以我会整理一下步骤。
假设您已经拥有 GCP 帐号,并且已经创建了项目。
https://console.cloud.google.com/
在中国,我有一些鄙陋的想法。
笔者以前一直使用Gehirn DNS。该服务可以在不使用Git等自己系统的情况下进行DNS记录的版本控制。此外,该服务还提供了API,并具有在指定时间切换到任意版本的功能(迁移)。
此次迁移到Google Cloud DNS的原因是,我们只使用了Gehirn DNS独有的功能,并且经过对包括Amazon Route 53在内的3个服务的成本估算后,Google Cloud DNS是最便宜的。
如果您想要方便地在Web控制台上进行DNS记录的版本管理,并且只要有API可用,无需使用Terraform,那么Gehirn DNS可能会更适合您。
使用Terraform进行Google Cloud DNS的配置。
文件结构
┬ .gitignore
├ account.json
├ dns_example_com.tf
├ gcp.tf
├ variables.tf
└ variables.tfvars
如果tf文件位于同一目录中,则配置可以自由选择,仅供参考。
.*
!.gitignore
# Terraform
*.log
*.tfstate
*.tfstate.backup
account.json
谷歌供应商的设置
provider "google" {
credentials = "${file("account.json")}"
project = "${var.project}"
region = "${var.region}"
}
区域和记录的设置
resource "google_dns_managed_zone" "example_com" {
name = "example-com"
dns_name = "example.com."
}
请注意,dns_name的末尾需要加上一个句点 (。)。
記錄的設定
将内容追加到与区域设置相同的文件中。
resource "google_dns_record_set" "a_example_com" {
managed_zone = "${google_dns_managed_zone.example_com.name}"
name = "${google_dns_managed_zone.appcloud_info.dns_name}"
type = "A"
ttl = 300
rrdatas = [
"192.30.252.153",
"192.30.252.154"
]
}
变量
variable "region" {
default = "asia-northeast1"
}
variable "project" {}
project = "project-id"
由于这次的地区将不会改变除东京地区以外的任何地方,所以我们将设置默认值。
身份认证信息
创建服务帐号密钥(JSON)。
创建一个新的服务帐号。
完成后,您可以以 JSON 格式下载认证信息,然后将其重命名为 account.json 并放置在相同的路径下。
域名服务器
在Google Cloud DNS和Amazon Route 53中,创建新的区域时会分配域名服务器。
因此,若在资源创建后输出名称服务器列表,可以节省打开Web控制台并进行确认的功夫,非常方便。
将内容添加到与Zone设置相同的文件中。
resource "null_resource" "nameservers_example_com" {
triggers {
name_servers = "${join("\n", google_dns_managed_zone.example_com.name_servers)}"
}
provisioner "local-exec" {
command = <<EOF
echo "nameservers: ${google_dns_managed_zone.example_com.dns_name}"
echo "${self.triggers.name_servers}"
EOF
}
}
计划与申请
建议您在Mac上使用brew来安装Terraform。
terraform plan -var-file=variables.tfvars
如果语法有问题,到了这一步就会出错。
如果确认没有问题,并且可以确认资源已经更新了,就执行应用。
terraform apply -var-file=variables.tfvars
以下是域名服务器列表的输出结果。
null_resource.nameservers_example_com (local-exec): nameservers: example.com.
null_resource.nameservers_example_com (local-exec): ns-cloud-d1.googledomains.com.
null_resource.nameservers_example_com (local-exec): ns-cloud-d2.googledomains.com.
null_resource.nameservers_example_com (local-exec): ns-cloud-d3.googledomains.com.
null_resource.nameservers_example_com (local-exec): ns-cloud-d4.googledomains.com.
只要在本地执行,这样就完成了。
在Wercker上自動部署
目前(2017年1月),您可以在GitHub或Bitbucket上创建代码库。如果使用Wercker,即使是私有代码库也可以免费使用。
文件结构
┬ .gitignore
├ account.json
├ dns_example_com.tf
├ gcp.tf
├ gcs.tf
├ variables.tf
├ variables.tfvars
└ wercker.yml
追加的是 gcs.tf 和 wercker.yml。
遥远的国度 de
如果在本地执行,则通过文件 terraform.tfstate 保存配置状态。要在本地以外正确地进行反映,需要以某种方式同步此状态。
这就是远程状态(remote state)功能。
远程状态有 S3 和 GCS(Google Cloud Storage)作为其后端。在这里我们选择了 GCS。
远程状态后端
resource "google_storage_bucket" "wercker_tfstate" {
name = "${var.remote_state_bucket}"
location = "${var.region}"
storage_class = "REGIONAL"
provisioner "local-exec" {
# Enable versioning (not supported by terraform)
# https://cloud.google.com/storage/docs/object-versioning
command = <<EOF
gcloud auth activate-service-account --key-file account.json
gsutil versioning set on "${var.remote_state_bucket}"
gsutil versioning get "${var.remote_state_bucket}"
EOF
}
}
当状态由于某种事故而被错误地覆盖时,我们将设置GCS版本控制功能作为应对措施。然而,目前terraform不支持此功能,所以我们将使用local-exec provisioner直接执行gsutil命令以启用它。
然后,在 variables.tf 和 variables.tfvars 文件中添加 remote_state_bucket 和 remote_state_path。
variable "region" {
default = "asia-northeast1"
}
variable "project" {}
variable "remote_state_bucket" {}
variable "remote_state_path" {
default = "terraform.tfstate"
}
project = "project-id"
remote_state_bucket = "bucket-name"
※ 如果桶名已被其他用户注册使用相同的名称,则无法使用。需要设置为不重复的名称。
在本地环境中尝试远程状态
首先,为了创建GCS存储桶,请先进行申请。
terraform plan -var-file=variables.tfvars
terraform apply -var-file=variables.tfvars
然后运行terraform remote config来同步本地的tfstate。
terraform remote config \
-backend=gcs \
-backend-config='bucket=bucket_name' \
-backend-config='path=terraform.tfstate' \
-backend-config='project=project_id' \
-backend-config="credentials=$(cat account.json)"
创建 Wercker 应用
注册代码库并创建Wercker应用程序。
一旦选择了将我的应用程序设为公开,即使它以前是一个私有仓库,也会被公开,所以需要注意。
构建步骤的设置
我们将在wercker.yml中进行构建和部署的设置。
在 “build” 过程中,通过执行 `terraform plan` 命令来验证 tf 文件,并在 “deploy” 过程中使用 `terraform apply` 命令来实际应用。
box: python:2.7
build:
steps:
- script:
name: generate account.json
code: |
cat <<EOF > account.json
{
"private_key": "$GCP_PRIVATE_KEY",
"client_email": "$GCP_CLIENT_EMAIL"
}
EOF
- ww24/terraform:
command: plan
var_file: variables.tfvars
remote_config: |
-backend=gcs \
-backend-config='bucket=bucket_name' \
-backend-config='path=terraform.tfstate' \
-backend-config='project=project_id' \
-backend-config='credentials={ \
"private_key": "$GCP_PRIVATE_KEY", \
"client_email": "$GCP_CLIENT_EMAIL" \
}'
deploy:
steps:
- script:
name: install gsutil
code: |
pip install gsutil
- ww24/terraform:
command: apply
var_file: variables.tfvars
remote_config: |
-backend=gcs \
-backend-config='bucket=bucket_name' \
-backend-config='path=terraform.tfstate' \
-backend-config='project=project_id' \
-backend-config='credentials={ \
"private_key": "$GCP_PRIVATE_KEY", \
"client_email": "$GCP_CLIENT_EMAIL" \
}'
请根据需要随意更改bucket_name和project_id。
我正在使用ww24/terraform在安装Terraform并执行plan和apply。
通过在 remote_config 中编写 -backend 或 -backend-config,可以确保在执行 plan 或 apply 之前必须先执行 terraform remote config。
工作流程的设置 de
将主分支的更改配置为在发生时进行部署(使用terraform apply)。
增加新的流水线以进行部署。
↓ pipeline 添加了部署。
点击Workflow editor构建右侧的+按钮,然后在branch中选择master,执行管道中选择deploy,并点击Add按钮添加。
如果按照以下方式进行操作,工作流设置将完成。
环境的设置
由于无法直接将认证信息放在wercker.yml文件中,所以需要设置为环境变量。
如果将选项”Protected”选中,基本上无法从Web上查看,这是很有用的。
然而,在构建和部署过程中可能会出现意外错误,并以错误消息的形式输出,因此需要采取预防措施,例如不将Wercker应用程序公开等。
然后,如果在GitHub上的远程仓库有更新,就通过Wercker运行构建(terraform plan)。当合并到主分支时,会运行构建和部署(terraform apply)。
最后
我虽然不是使用Terraform,但在工作中见到了类似的配置,负责管理DNS记录,给我带来了灵感。
如果有设置上不明白的地方,可以参考实际运作的内容。
这是github上的一个项目,你可以在https://github.com/ww24/dns找到它。请注意,目录结构可能会稍有不同。