インフラチームエンジニアの藤田 (@dtan4) です。Terraform でインフラをコードで管理するようになって1年が経ちました。
Wantedly のインフラは AWS + DNSimple 上で稼働していますが、そのリソースの殆どをおよそ1年前から Terraform のコードで管理しています。もちろん1年前の時点で既存のリソースは数多くあったわけですが、それらも Terraform のコードに落としこむため Terraforming という変換ツールを作りました。現在ではインフラ変更の際に GitHub 上で Pull Request によるレビュー + CI 上で自動適用を行う体制が整っております。
以前 Wantedly Advent Calendar '15 で Wantedly での Terraform 運用事情を一通り紹介しましたが (Terraform と CI で実現するインフラのコード化と構築の自動化 - Qiita)、今回はそれをさらいつつ最近どうなのといった話を書こうと思います。
なぜインフラをコード化するのか
Terraform 導入前は、以下の様な問題点がありました。
- 開発チームからインフラチームへの依頼によるスタイル
- 新しいリソースを作るのに Management Console 上でポチポチ操作してくのが面倒であり、工数もかかる
- しかもポチポチ作業の履歴を残すのが困難
- Management Console に行かないとリソースの一覧が把握できない
- 同じ構成でもリソースの複製が面倒
これらを、
- 開発者が欲しいリソースをコードという形で記述して、インフラチームに Pull Request を送る
- インフラチームは送られてきたコードを GitHub 上でレビューして、"Merge Pull Request" ボタンを押すだけでリソースが作られる
- リソースの追加や変更履歴は、git の diff という形で残るリソース複製もコードのコピペで済む
という形で解決しようと考えたのです。
なぜ Terraform を選ぶのか
Wantedly では多くの AWS サービスを利用していますが、それらをひとつのツールで一元的に管理できるというのが決め手でした。DNS に関しては Route53 ではなく DNSimple を利用しているのですが、それも含めて管理できるというのは大きかったです。
Terraform の他にも同様の機能を持つツールはありましたが、
- CloudFormation は Visual Editor があるけどやっぱり JSON を管理 / 修正するのが面倒。リソース一覧をひと目で俯瞰しにくい
- codenize.tools はサービス単位でツールが別れており、一元的に管理するのが困難。また、対応サービスが限られていた
といった理由で採用を見送りました。
実際の運用構成
GitHub 上に Terraform のコードを管理するリポジトリを1個用意し、リソースの追加修正を行う場合はそこに Pull Request を出してもらうフローにしています。GitHub への push に連動して、wercker 上で `terraform plan` が実行されるのでインフラチームがその結果を確認します。master への merge はインフラチームが行います。master に merge されると wercker 上で `terraform apply` が実行され、実際のインフラ上に変更が反映されます。
最近は Wantedly の Facebook bot など新しいサービスをリリースする機会が多かったのですが、それらのインフラも Terraform で構築しました。既存のインフラ構成をコピーする箇所が多かったのですが、コードで管理している場合はコピペで対応できるためやりやすかったです。
実際の効果
一番 Terraform のコードを触るのはインフラチームですが、それ以外の開発チームからも積極的に Pull Request が飛んできます。例えばランディングページ公開にあたって DNS レコードを設定したい場合は、担当している開発者が Terraform リポジトリにレコード追加の Pull Request を発行しています。また、新しいメンバーが入ってきた時の IAM ユーザ発行は、その人自身に IAM ユーザ追加の Pull Request を出してもらうフローをとっています。
従来こういった作業はインフラチームにチャットでメンションするなどして依頼ベースになっていたところ、GitHub Pull Request で非同期化されました。これにより、開発者側とインフラチーム側双方において開発効率が向上したと考えられます。
導入の仕方
Terraforming で既存リソースのコード化
現時点での Terraform 最新版 (v0.6.16) では、既存リソースを Terraform の管理下に置くことがそのままではできません。しかし、Wantedly では www.wantedly.com をはじめ既に稼働しているインフラリソースが数多くあったので、それらをどう Terraform の管理下に置くかというのが課題でした。
これは現在では Terraforming を利用すれば解決します。この Terraforming は、私 @dtan4 が、実際に Wantedly の既存の AWS リソースをコード化する際に作成し、OSS として公開したものです。Terraforming は Wantedlyだけでなく、他社さんでも Terraform 導入時にご利用いただいています。
TerraformとPackerを使ったインフラ構築の効率化 - SideCI TechBlog
Terraformingで既存のIAMユーザをTerraform管理下に入れる - クラウドワークス エンジニアブログ
今後も、積極的に開発は続けていく方針です。
ところで、次期マイナーバージョンである Terraform v0.7.0 では待望の既存リソース import 機能が搭載される予定です。が、一通り内容を見た限りは「tfstate の生成しかできない」「リソース ID を指定して1つずつ import しかできない」という仕様になっており、まだまだ Terraforming が生きられる気はしています (Terraforming は tf の生成やリソース一括生成に対応しているため)。
今後の課題と対策
課題:Terraform リポジトリが肥大化してきてつらい
発表のたびに紹介している管理下のリソース数ですが、2016/06/27 現在だと 455 個になります。これらのリソースをすべて単一のリポジトリ上で管理しています。
さて、これだけのリソースを単一リポジトリ上で管理すると何が起こるか。ある Pull Request が飛んできて terraform plan が走った時、「加えた変更と関係ない箇所で差分が出る」ことが起こりやすくなるのです。IAM ユーザ追加しただけなのに Security Group の差分が出るみたいな。
対策:サービス単位でのリポジトリ分割の検討
対策としては、Terraform のリポジトリを分けることを考えています。リポジトリ分割にあたっては何を境界にするのか?という問題がありますが、まずは「S3 や IAM といった VPC 外のリソース」「それ以外」というのが分けやすいのかなと思っています。特に IAM に関しては新しくジョインしたメンバーが Pull Request でアカウント発行を申請するなど触る人が多いので、ここだけでも別にしておきたいと思っています。
一方でリポジトリを分けると、別リポジトリにある他のリソースを参照することが Terraform の変数展開 ${} が使えなくなるため、困難になります。このあたりはトレードオフになってくるので、検討の余地があります。
最近だとモノリシックつらい -> マイクロサービスだと影響を局所化できる、といった話題を耳にしますが、それが Infrastructure as Code の文脈にも降りてきてしまった感じです。
おわりに
Terraform を導入した経緯と1年間運用してみて良かったところ、困ったところを紹介しました。Wantedly では非同期コミュニケーションを推進しており、インフラチームはその一環としてコードと GitHub によるインフラ管理を導入しました。
最近ではインフラ構築にあたって、Terraform / Terraforming を導入するケースがちょくちょく見受けられるようになりました。この記事が少しでも参考になれば幸いです。