はじめに
先日、ノリと勢いで企画した SRE.fm を行い、ゆるふわに Terraform や IaC の話をしました。
実際にやってみて、質問への回答を行う中で、IaC に関わるひとたちのマジョリティと自分たちには大きな隔たりがあるような感覚を持ちました。そういった中で、質問の1点1点に答えるというよりも、大局的な理解であったり、その本質的な要素であったり、段階に分けた学習ステップ等を言語化することが必要なのではないか、と(その後の二次会で)たどり着きました。
「IaC は当たり前になった」というのは Infra Study Meetup #1「Infrastructure as Code」 での Mizzy さんの言葉で、これに関しては大きく同意するものの、この「当たり前」は「誰でもしている状態になった」「できていないのはありえない」というものではなく、"Basic" - 基本となった、という意味合いが近いと思います。(簡単 - Easy という意味ではない)これはやる意義や方向性に関してはある程度揺るぎないものになってきた一方で、それを成し遂げる方法が簡単になったわけではないと思いますし、基本になったからこそ、より多くのひとが関心を持つようになりました。だからこそ、学習ステップの言語化がより重要になってくるのではないかと思います。
おことわり
というわけで本記事ではこういった IaC にまつわるいろいろの言語化に試みますが、全文章に(たぶん)(しらんけど)がついてると思って読んでください。
筆者は SRE Team で2年ほど IaC を行ってますが、すでにできているものを運用しながら覚えていきました。2年前は Terraform をちょこっと自分で動かしたことある程度でした。あと、Terraform と AWS がメインなので、そちらに視点が偏っていると思います。自分も学習に苦労した気がしつつ、もう忘れてしまっているので、再現性を持たせるためにも言語化することにしました。
あと後述する IaC Maturity Model だと Level 4 にいます。
IaC Maturity Model
@chaspy なんか IaC のレベル感とかをステップごとに分ければいいんかなー
@qsona よさそう。IaC Maturity Model
こういうノリで段階を区分けして、自分が今どの段階にいて、次はどこを目指すべきかを示すと学習の手助けになるかもしれません。
- Level 0 インフラリソースを全て Manual で作成しており、一切コード化されていない
- Level 1 インフラリソースが Code 化されているが、plan や apply は localmachine もしくは共有サーバ上で manual で行っている
- Level 2 インフラリソースの変更が CI/CD Pipeline の中で実行されている
- Level 3 インフラリソースの変更が Pull Request Based で実行結果のレビューができる
- Level 4 複数のチームが自律的に各チームの関心のあるインフラリソースを、レビューを通じて変更、適用ができる
- Level 5 複数の組織がそれぞれの IaC リポジトリを持ち、各チームで維持・運営ができている
その他関連しそうなことをまとめてテーブルにしてみました。
Level | Automation | Scope |
---|---|---|
0 | No | Personal |
1 | No | Personal |
2 | Yes | Team |
3 | Yes | Team |
4 | Yes | Multiple Team |
5 | Yes | Organization |
ここで重要なのは Scope の概念です。Effective DevOps がなぜ組織に着目したのか。それはツールを利用してソフトウェア開発のスピードを高めるには、どうしても組織でそれをうまく扱う方法を考える必要があるからです。IaC Maturity Model は組織のスケールに対してどのように適用していくかの段階を言語化したものになります。
Effective DevOps ―4本柱による持続可能な組織文化の育て方
- 作者:Jennifer Davis,Ryn Daniels
- 発売日: 2018/03/24
- メディア: 単行本(ソフトカバー)
IaC の難しさ
さて、学習ステップをどう考えていくかの前に、IaC の難しさに目を向けてみたいと思います。
IaC の難しさはその"運用"にあると思います。つまり複数人で運用するための仕組み作りです。Level2 以降の部分にあたります。
実際、ただコードに起こすだけならそんなに難しくありません。既存リソースのインポートは泥臭い作業が必要ですが、もうそれは(なるべく自動化しながら)愚直にやるしかありません。新規リソースの作成もサンプルを通じて HCL 定義を書いて Apply するだけです。
この"運用の難しさ"を考える点がこれまでなかなか言語化されてこなかった点だと思います。
運用を想像する難しさ
運用を想像するために、主要な要素をいくつかあげてみましょう。
State Unit
インフラリソースをどの単位で適用していくのか、その分割単位のことです。
これは特に Level3 から Level4 に移るときに考慮する必要があります。
monolithic な state であることの問題点は、対象のリソースが多くなることで、Plan や Apply に時間がかかる点や、その影響範囲が大きくなってしまい、変更がしづらくなってしまう点です。
これを"適切"に分割する、という答えが組織によるところで、多くのひとが(僕も含め)悩まれる点だと思います。これに関しては
- 原則 state 間の依存を作らない
- 作る場合は1方向にする
- データソースで持ってくる
- リソース名や ID をベタに書く
- オーナーシップを効かせるために、チームで扱う単位で分割する
というのが私見です。
Branch Strategy
開発と本番をどのように分け、どのように適用しているのかを Branch Strategy とともに想像する必要があります。これは前述の State をどう分けるかにも密接に関わってくるため、少し複雑です。
よくみるパターンとしては
1. リリースブランチパターン(コードは共通)
- master merge で Staging へ Apply, release branch merge で Production へ Apply
- CI の中で vars で切り替えるか、workspace を利用する
- フローが1本化されるため、かなり厳密な開発本番一致が求められる
- 例外をどう扱うか(sandbox を別に作るとか)がポイント
- 規模がある程度大きいとキツくなると思う。(Resource 200+ とか)
2. GitHub Flow パターン(コードはディレクトリ・state もわける)
- この場合、Feature Branch では Plan のみになるため、master 必ず apply される
- 開発と本番をディレクトリでコードを分割する
service_a/staging
service_b/production
- まぁ分割しなくても workspace を使えばできなくはないか。。。
- 開発本番一致を厳密に求めないものの、diff で確認できる
弊社は現状後者のパターンを取っています。変数が多いのでまとめると
Pattern | リリースブランチ | 開発本番でコードは | 開発本番でstateは |
---|---|---|---|
1 | Yes | 同じ | 違う |
2 | No | 違う | 違う |
Branch Strategy に合わせて State も分割されるため、その場合は実行時間が長くならないよう、変更検知をして変更があったものだけを plan, apply する仕組みや、1PR で複数の state を変更させないような仕組みが必要になってくるでしょう。
IaC の罠
IaC はインフラを Software のように扱うことで、Software 開発のプラクティスを利用できる、という言説がありますが、注意すべき点がいくつかあります。
共通化
ソフトウェアではよく Function を共通化したり、モジュールを使って再利用性を高めたりしますよね。IaC ではそれは影響範囲を広くすることに他ならないので、極力避けたほうが無難です。
特に Terraform の module を DRY のために使うと、その内容を変更しようとしたときに大変ですし、何より一段層が増えることで単純に可読性が悪くなります。
Terraform の module は"強制化したいもの" - 社内で決められたパラメータがある、これだけは絶対に必要なものである、そういったものを module 化するのが好ましく、必要になるまで使わないほうがいい、というのが私見です。
Repeat Yourself ですね。
ロジック
本当にまったく同じリソースを大量に必要になってくるなら必要ですが、ループや分岐といったロジックはどうしても必要になるまで使わないほうがいいです。
これも同じくそのコードを読み取るのに認知負荷がかかるからです。
IaC をどう捉えるか
Infrastructure を Code で表現できるようになったことで、Software 開発でよく使われる方法がすべて好ましいかというとそうではないことを述べました。
これまでの経験を踏まえて、ポイントをまとめてみます。
- IaC はインフラを宣言的に表現することができる
- 容易に内容が把握できる(grep ができる)
- コピペもできる
- バックアップにもなる
- IaC はインフラの API のラッパーである
- IaC をチームで運用する上でもっとも大事なのは認知負荷を下げることである
このあたりは実は誰も教えてくれなかったことなのかもしれないなーと、今思います。
IaC の学習ステップ
さて、いよいよどのように学習していけばいいか、Level ごとに考えていきましょう。再掲します。
- Level 0 インフラリソースを全て Manual で作成しており、一切コード化されていない
- Level 1 インフラリソースが Code 化されているが、plan や apply は localmachine もしくは共有サーバ上で manual で行っている
- Level 2 インフラリソースの変更が CI/CD Pipeline の中で実行されている
- Level 3 インフラリソースの変更が Pull Request Based で実行結果のレビューができる
- Level 4 複数のチームが自律的に各チームの関心のあるインフラリソースを、レビューを通じて変更、適用ができる
- Level 5 複数の組織がそれぞれの IaC リポジトリを持ち、各チームで維持・運営ができている
Level | Automation | Scope |
---|---|---|
0 | No | Personal |
1 | No | Personal |
2 | Yes | Team |
3 | Yes | Team |
4 | Yes | Multiple Team |
5 | Yes | Organization |
Level 0 -> 1
- Terraform といった IaC ツールそのものの理解
- 概念の理解:state, provider, init, plan, apply, import, refresh
- 実際にサンドボックスで動かしてみる。S3 を作るとか。EC2 を作るとか
- コード管理したい対象のリソースの理解
- 実際に GUI で作ったものを Import、変更をしてみる
- あとは気合で全部 Import する
Level 1 -> 2
- CI/CD ツールの理解
- Branch Strategy を考える
- CI 用のユーザの権限を考える
- 本当は最小権限が良いのはわかってるが、強い権限をあげがち
Level 2 -> 3
- Level 2 と 3 はあんまり大差ないかも
- 今なら tfnotify が便利そうです
- レビュー観点の整理
- とはいえ文法はだいたい plan で落ちる
- apply してこけるものもあるが、そういう前提で、リスクなく失敗できる環境作りに注力したほうが無難
Level 3 -> 4
- State 分割単位を考える
- はじめからここまで想定しておけば、インポートの段階から分けておいても良い
- plan 実行長期化を避けるための変更検知の導入
- 他のチームで使ってもらうための勉強会等の実施
- ドキュメント
- 頻繁に作るリソース - microservices ごとに RDS を作るとか - があれば tf file を scaffold する script を用意してあげるとか
Level 4 -> 5
到達してないので分かりません。たぶん Module 使ったり、Terraform Cloud 使ったりするのが便利なんだと思う。
おわりに
こう考えると、IaC そのものが登場するのはほとんど Level 0 ->1 の間であり、それ以外はチームでどのように扱うか、という点に難しさがあることが分かると思います。
本記事がこれから IaC をはじめるひとや、現状の運用に悩んでいるひとの学習指針になれば幸いです。
謝辞
今回、この記事を書くにいたり、SRE.fm にいきなりのお願いにも関わらず協力いただいた @ryok6t さん、@_inductor_ さんに心から感謝します。この場で話したおかげで、自分自身の思考の整理にもなりましたし、この記事のアウトプットにつながりました。
このアウトプットのきっかけをくれた同僚の@sona さんに心から感謝します。いつもイシュー度の高い問題を提起してくれるおかげで、僕自身も考えるきっかけになっています。
Quipper において Infrastructure as Code を高いレベルで構築、維持してくれた SRE Team の卒業生、および現 SRE Team メンバーに心から感謝します。僕が今このような知見を持つに至ったのはもともとお手本になる基盤があり、そこから学ぶことができたからです。特に現同僚の@suzuki-shunsuke さんの高い技術力にいつも助けられています。
Terraform-jp slack コミュニティ のスタッフ、および参加メンバーに心から感謝します。いつも有用な情報交換や相談に乗っていただけたおかげで理解を深めることができています。
突撃!隣の Terraform の際に突撃させていただいた Kyash の@lamanotrama さん、Mercari の @deeeet さん、@dtan4 さんに心から感謝します。他社事例を知ることで非常に多くの学びを得ることができました。
InfraStudy にて基調講演を発表された Mizzy さんに心から感謝します。心に残る言葉でシメていただいたおかげで、本記事を書くことができました。
おまけ:質問の回答
その場で回答しましたが、ひとはライブアーカイブを再度見ない生き物であることがわかっているので、僕の意見にはなりますが、ここで回答をまとめておきます。
https://app.sli.do/event/bk0aqupz/live/questions
Terraformのレビューに関して、どのような観点でレビューしてらっしゃるのでしょうか?
- そもそもこのリソースがなぜ必要か、というサービスレベルの観点
- 対象のリソースが正しく作られそうか、ほかに必要なリソースはないかというリソースレベルの観点
- 意図通り作られそうか。どのように通信されるのか、とか
- tag がちゃんとついてるか、とか
- あんまり HCL 自体のレビューはしない
- apply で落ちることもあるけど、はやく失敗したほうがいいかなという考え
- ざっと見てえいっとやってバーンするのが多い
tfstate の分割単位はどの単位でしょうか
- 各サービスのチーム単位
- 共通部分、VPC やネットワークは SRE が見ている
Terraform Workspaces を使っていますか?使っている/使っていないに関わらず、その選択をした理由をお聞かせください。
- 誰も使ってなかったと思う
- 開発本番を完全一致させていれば、開発本番の切り替えにつかることもできる
- たぶん大量の同一リソースを複数のテナントで使ってもらうときとかに有効な気がする
state を分割して、かつシェルスクリプトで実行時間を短縮しているかとは思いますが、複数 state にまたがる変更の plan/apply の実行時間は気になりませんか?(並列に実行したりしてるんでしょうか)
- 並列実行してます
- 変更検知して変更があるやつだけ実行するのが一般的だと思います
Terraform以外で気になっているインフラ管理系ツールはありますか?(ex CDK,Pulumiとか)
- chaspy は特にない
- 開発者が好きな言語でかけてテンションがあがるならそれでいいと思う
- (テンションがあがるのは大事)
- ツール自体はなんでもいいはずなので
- Provider 相当の部分がちゃんと公式の A{PI に追従しているかは気にした方がいいと思う
クレデンシャル情報の管理はどうしていますか?
インポート作業にどれぐらいの期間かかりましたか?
- kubota さん向け、3ヶ月だそうです
module分割する場合、役割単位、サービス単位どちらが良いのでしょうか
- サービス単位をお勧めします
- チーム単位というか
俗人化問題はどうやって解決してるんだろうか。
- たぶん kubota さんに対するもの
- なんだっけ。。。
CICDは会社さんによってまちまちでしょうけど、実際のところどうでしょうか?
- どうなんでしょう
- まちまちな感じですね
- お好みで良いと思います
新規プロダクトや少人数チームで IaC がどの程度必要なのか
- Team Level で扱うなら検討した方がよさそうです
- この質問も今回のモデルを考えるためのヒントになりました。ありがとうございます。
「dryに書く」という表現イマイチわかってないのですが、具体的にどんな感じなのでしょうか
- Don't Repeat Yourself といって、ソフトウェア開発で同じことを複数書くことを避けよ、という考えがあります
- ある Role の EC2 インスタンス と DNS record の module を作って、それをペタペラ複数作るとか、ですね
workspaceを使わない場合、環境毎のリソース名の違いはどのように吸収しているのでしょうか
- ディレクトリと State を分けてます
- inductor さんは vars でわけて、CI で injection してました
- コードレベルじゃなく、CIのところでなんとかしたほうがいいよね、って結論になったはず
tfstateを分けないとplanやapplyの速度は遅くなりませんか?
- なると思います
- 100 とか 200 とかなると分けざるを得ないと思います
dev/prdなどでtfstateを分割したときに共有のresourceをどう管理するか悩んでます。 flagを持たせたり変数で制御したりしてるのを見ますがif文を使うのは負けな気がして。
- リソースを共有しないほうがいいと思います
- if 文もやめたほうがいいと思います
使っているTerraform Providerにはどんなものがありますか
Terraform本体とProviderのバージョンアップ運用はどうしていますか。アップデート頻度も気になります。
- 基本は最新に追従したほうがいい、ためるとつらい
- chaspy は github を watch して最新版でたらバージョン書き換えて PR 作るジョブを使ってます
- plan みて問題なければマージ
- 差分あれば修正
CircleCIのほうが多機能な気がしますが、GithubActionsは今後も使っていきたいですか?
- inductor さん、actions は ssh できないとか制限があるところが好み、という話だったと思う
Jenkinsはどう稼働してますか?自前でサーバを準備ですかね 笑
- EC2 ですね
おすすめのゲーミングベッドを教えて下さい。
- 僕このときいなかったな。。。
IaC のテストステップはどんな分類があるでしょうか?(構文チェック、ユニットテストなど)
- 僕このときいなかったな。。。
- ユニットテストは書かないですね
- lint は tflint がある?
- tf fmt は CI でみてる
- ポリシーテストとかやってる事例はありますが、このメンバーは誰もしてなかった気がする
hcl2 の制御構文、関数型由来の function と for_each/count を用いて宣言的に書けるのは module 作るときに結構有用だと思うのですが、そのあたりどうでしょうか?
- 有用だと思います!