用 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)。

service account key

创建一个新的服务帐号。

create service account

完成后,您可以以 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应用程序。

make-my-app-public

一旦选择了将我的应用程序设为公开,即使它以前是一个私有仓库,也会被公开,所以需要注意。

构建步骤的设置

我们将在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)。

image

增加新的流水线以进行部署。

image

↓ pipeline 添加了部署。

image

点击Workflow editor构建右侧的+按钮,然后在branch中选择master,执行管道中选择deploy,并点击Add按钮添加。

image

如果按照以下方式进行操作,工作流设置将完成。

image

环境的设置

由于无法直接将认证信息放在wercker.yml文件中,所以需要设置为环境变量。

image

如果将选项”Protected”选中,基本上无法从Web上查看,这是很有用的。
然而,在构建和部署过程中可能会出现意外错误,并以错误消息的形式输出,因此需要采取预防措施,例如不将Wercker应用程序公开等。

然后,如果在GitHub上的远程仓库有更新,就通过Wercker运行构建(terraform plan)。当合并到主分支时,会运行构建和部署(terraform apply)。

最后

我虽然不是使用Terraform,但在工作中见到了类似的配置,负责管理DNS记录,给我带来了灵感。

如果有设置上不明白的地方,可以参考实际运作的内容。

这是github上的一个项目,你可以在https://github.com/ww24/dns找到它。请注意,目录结构可能会稍有不同。

广告
将在 10 秒后关闭
bannerAds