もりはやメモφ(・ω・ )

ITとか読書感想文とか

Terraformのfor_eachを使ってhosts運用からRoute53 private hosted zone運用 へ切り替える

これは terraform Advent Calendar 2020 の12/7の記事です。

書くこと

この記事では以下を書きます。できたサンプルコードはこちら。

  • Linux OSの /etc/hosts ファイルから
  • Terraform の aws_route53_record のための
  • for_each を使ったパラメタを生成する

これまでの /etc/hosts 運用はつらひ..

日頃運用している環境はAWSとオンプレミスのハイブリッド構成です。管理するリソースにはVMサーバやNW機器などが数多くあり、踏み台サーバの /etc/hosts にそれぞれのIPとホスト名を記載していました。*1

#/etc/hosts

192.168.1.21   l2sw01
192.168.1.22   l2sw02
192.168.1.31   l3sw01
192.168.1.32   l3sw02
192.168.2.11   web01
192.168.2.12   web02
192.168.10.11  db01
192.168.10.12  db02

この運用の問題点は/etc/hostsが踏み台サーバ上にしかないため、それ以外の場所でホスト名を利用できないことです。 hostsファイルを必要な全ての場所にデプロイしようにも、展開したい場所はサーバや個人のPCなど幅広くあるため現実的ではありません。

DNS(Route53 Private hosted zones)を使って問題解決する

hostsファイルのデプロイが問題であれば、それを解決するのがDNSです。AWSのRoute53には インバウンド エンドポイント 機能があり、他VPCやダイレクトコネクト経由のオンプレミスからも Private hosted zone で管理された名前解決を行うことができます。

Terraformを書く

Route53 が使えるなら、それはTerraformの出番です。既存のhostsファイルは数百行に育っていたので楽に変換する方法を検討しました。

[morihaya@jump ~]$ wc -l /etc/hosts
408 /etc/hosts

検討した方法は以下で、シンプルにかけるfor_eachを選択しました。

  • 普通に書く -> 行数も増えるしメンテもしづらいのでやりたくない
  • ipとホスト名を渡すだけでOKなmoduleを作る -> moduleはterraform registryのものしかできれば使いたくない
  • for_each -> シンプルでシュッとかけて読みやすい

以下がテンプレートで、生成したパラメタを挿入するだけです。

resource "aws_route53_record" "private" {
  zone_id = aws_route53_zone.private.zone_id
  for_each = {
    <ここへ生成したパラメタを入れる>
  }
  name    = each.key
  type    = "A"
  ttl     = "300"
  records = [each.value]
}

for_each では key = value のように記述するため、hostsファイルからのパラメタ生成は以下のような簡単なシェル芸で行いました。 *2

$  cat hosts.sample | awk '{printf("\"%s.morihaya.tech\" = \"%s\"\n",$2,$1)}'
"l2sw01.morihaya.tech" = "192.168.1.21"
"l2sw02.morihaya.tech" = "192.168.1.22"
"l3sw01.morihaya.tech" = "192.168.1.31"
"l3sw02.morihaya.tech" = "192.168.1.32"
"web01.morihaya.tech" = "192.168.2.11"
"web02.morihaya.tech" = "192.168.2.12"
"db01.morihaya.tech" = "192.168.10.11"
"db02.morihaya.tech" = "192.168.10.12"

出来上がったもの

こうして出来上がったものがこちらです。 ホスト名とIPが並びますのでメンテナンスもしやすいと感じています。

data "aws_vpc" "default" {
  default = true
}

resource "aws_route53_zone" "private" {
  name = "morihaya.tech"
  vpc {
    vpc_id = data.aws_vpc.default.id
  }
  tags = {
    "Make" = "Terraform"
  }
}

resource "aws_route53_record" "private" {
  zone_id = aws_route53_zone.private.zone_id
  for_each = {
    "l2sw01.morihaya.tech" = "192.168.1.21"
    "l2sw02.morihaya.tech" = "192.168.1.22"
    "l3sw01.morihaya.tech" = "192.168.1.31"
    "l3sw02.morihaya.tech" = "192.168.1.32"
    "web01.morihaya.tech"  = "192.168.2.11"
    "web02.morihaya.tech"  = "192.168.2.12"
    "db01.morihaya.tech"   = "192.168.10.11"
    "db02.morihaya.tech"   = "192.168.10.12"
  }
  name    = each.key
  type    = "A"
  ttl     = "300"
  records = [each.value]
}

まとめ

以上、/etc/hosts での運用を Terraform の aws_route53_record + for_each を使って Private zone 運用に切り替えた話でした。 for_each 関数は バージョン 0.12.6 から追加されましたが、先日(2020-12-02)には 0.14がGAとなり "Concise Diff " など良い機能が追加されましたし、今後も Terraform の進化が楽しみですね。

*1:ファイル自体はgitで管理

*2:morihaya.tech の部分ははそれぞれのドメイン名に変えること