HDE BLOG

コードもサーバも、雲の上

Terraformでクラウドを耕そう

クラウドプロダクト開発部のたなべです。

去る4月17日(金)に開催された社内勉強会 (HDE Monthly Technical Session; MTS) で Terraformについてライブデモを交えて話しました。今回はそのブログレポートです。

Terraformについての一般的な話はGoogle検索等で探してください(すみません。。)。

スライド

勉強会は基本英語なのでスライドも英語です。

スライド中に使用したデモはGithub上で公開しています。

github.com

ブランチを1から7まで用意しています。VPCに始まり、サブネット、セキュリティグループ、ルーティング、インターネットゲートウェイ、ELB、そして最後にWebサーバを起動するところまでを7ステップで試せるようになっています。

順に進めていき、ブランチ 7terraform destroy したとしても、再度 terraform apply すると一発で同じ環境が再度作成されます。再現性があるのもterraformのよいところです。

なぜTerraformなのか

Terraformをはじめて見たとき、すぐに「単なるプロバイダー非依存のCloudFormationみたいなものか」と解釈しました。

この解釈自体は間違いではありませんが、実際に使ってみるとそれ以上に「楽しい」ツールだということを実感しました。特にCloudFormationのJSONに嫌気がさしていたのもあり、もう戻りたくありません。

私がTerraformを使い出したのは現在開発中のサービスのステージング環境をAWS上に用意するためでした。 今日ではVPC以外の選択肢はないため、まずVPCを設計するところから始めました。

  • まずはネットワーク(サブネット)設計
  • 次にセキュリティグループを設計
  • おっと、ELBには専用のサブネットとセキュリティグループを割り当てたほうがよさそうだ
  • えー、インターネットゲートウェイを作成して、VPCに割り当てて…
  • あー、ルーティングテーブルのデフォルトゲートウェイをigwにして…
  • うー、RDSにはプライベートサブネットをだな…

というのを考えながらVPC全体を設計したのですが、さてこれをCloudFomationでやるのかAPIを自分で叩くのか、はたまた手順書を書くのか…そしてTerraformを思い出しました(0.3.2のころ)。

Terraform (0.4.2現在)を使うと上で設計したものをそのままコードへ落とし込めます。

  • VPCは "aws_vpc" リソースで定義
  • サブネットは "aws_subnet" リソースで ELB、バックエンド、RDSの3つでそれを各AZ向けに定義
  • セキュリティグループは"aws_security_group" リソースで定義
    • ELB向けにはサービスポートをフルオープン
    • バックエンド向けにはELB用サブネットからのみアクセスを許可
    • RDS向けにはバックエンドからのみアクセスを許可
  • インターネットゲートウェイは"aws_internet_gateway" リソースで定義。
  • ルートテーブルは"aws_route_table" リソースで定義
    • メインのルートテーブルにはigwをつけずにそのままプライベートサブネットとしておく
    • パブリックサブネット用のルートテーブルを作成し、デフォルトゲートウェイをigwに向ける
  • ルートテーブルとサブネットの紐付けは"aws_route_table_association" リソースで定義。
    • ELB、バックエンド用サブネットを上で作成したルートテーブルに紐付け
  • ELBは"aws_elb" リソースで定義。専用のサブネットとセキュリティグループをアタッチ

Terraformの使いどころと注意点

私が思うTerraformの使いどころは

  • VPCにまつわる細々としたリソース
  • ELB
  • KeyPair
  • Route53のレコード

などです。Terraformとの相性は抜群です。

一方で向いていない(あるいはより注意が必要)な部分としては、

  • RDSの管理

    terraform planでは些細な変更と思ってapplyしたらdestroyを共なう再作成が実施されてそれがプロダクションだった、みたいな話がGithubのissuesに書き込まれていました。

    github.com

    の修正で意図せずdestroyされないようにするフラグが導入されたので、0.5では回避できると思われます。

  • EC2インスタンスの管理

    プロジェクトによると思いますが、台数を動的に増減させつつ、それをELB配下に入れたりする場合、インスタンスはterraformに入れることは難しいと思います。ただ、TerraformではAutoScallingを管理できる(らしい)のでそちらで代用できるかもしれません。

    我々のプロジェクトではTerraformでVPC等を管理し、その上で動くインスタンスはすべてOpsWorksで管理しているため、EC2インスタンスはTerraformで管理していません。

  • Route53のHosted Zoneそのものの管理

    最初、Route53のHosted Zoneも"aws_route53_zone"リソースで管理していました。ステージングなのもあり、また当時はリソース単位でtaintできなかったため、EC2インスタンスを再作成するのに terraform destroy をしたところ、Hosted Zoneも消えてしまいました。消えたこと自体は問題ないのですが、ゾーンを再作成するとNSレコードが変更されるため、別部署の人に再度NSレコードを設定してもらうハメになりました。

    この件も今後 prevent_destroy フラグを設定することで防げそうです。ただし、 terraform destroy を必要とする場合はやはりHosted Zoneはidだけ変数として与えるほうがよさそうです。

Terraformの今後

TerraformはVagrant、Packer、Serf、Consul等を開発しているHashiCorp社の最新プロダクトで、個人的にはこれまでの集大成に位置付けられるプロダクトだと認識しています。

そのためか、開発は非常に活発で、次のリリースは 0.5.0 が予定されています。 ChangeLogをみると、 1つのプロバイダーに対して複数のインスタンスを設定できるようになります。これはつまり、リージョン違いのAWSリソースを持てることを意味します。まだドキュメントがありませんが、テストケースによると、以下のように書けるようになります。

provider "aws" {
    alias = "west"
    region = "us-west-2"
}
provider "aws" {
    alias = "east"
    region = "us-east-1"
}
resource "aws_instance" "foo" {
    # us-west-2
    provider = "aws.west"
    ami = "ami-4fccb37f"
    instance_type = "m1.small"
}
resource "aws_instance" "bar" {
    # us-east-1
    provider = "aws.east"
    ami = "ami-8c6ea9e4"
    instance_type = "m1.small"
}

すでにVPC設定がterraform化されていれば、別リージョンへの展開も非常に簡単になりそうです。

さいごに

Infrastructure as a Codeで進むべき道はCloudFormationにはなく、Terraformなどのツールにあると思います。 まだ細かなオプションがリソースになかったり(例えばELBでProxy Protocol有効にしたい!!でもまだない)しますが、Goで書かれているので開発に参加しやすいと思います。

これを読んでTerraformを使ってみたくなったと思います(そう願います)。しかし、残念なことに今現在は既存リソースをTerraform管理下に置くことはできません。 そのため、新規構築のタイミングがあればがんばってTerraformをねじ込みましょう!!!!