Slide 1

Slide 1 text

© 2024 Wantedly, Inc. 巨大 tfstate に立ち向かう技術 HashiTalks: Japan 2024 2024-11-13 Hayato Kawai (@fohte)

Slide 2

Slide 2 text

© 2024 Wantedly, Inc. 自己紹介 名前 Fohte (ふぉーて) 川井 颯人 (Hayato Kawai) 所属 ウォンテッドリー株式会社 趣味 🎮 🎹 https://techbookfest.org/product/fqhYCspDK80WBrGWJkEkP8?productVariantID=gzf9 X203XXhW87rBQnRxW2 Vim 入門書の 同人誌を作りました

Slide 3

Slide 3 text

© 2024 Wantedly, Inc. 究極の適材適所により、 シゴトでココロオドルひとを ふやすために Wantedlyはパーパス‧共感を軸にした、⼈と会社との出会いを2012 年から創出。 はたらくすべての⼈が共感を通じて「であい」「つながり」「つなが りを深める」ためのビジネスSNS「Wantedly」を提供しています。 1⼈でも多くの⼈がワクワクしたり、熱中してシゴトと向き合えるよ うな世界を実現するために、国境を超えて「はたらくすべての⼈の イ ンフラ」を創っていきます。 ウォンテッドリーの提供サービス

Slide 4

Slide 4 text

© 2024 Wantedly, Inc. 次世代型 採用管理システム 採⽤プロセスの悩みを解決 途中辞退を防ぐための業務を効率化 ● 繰り返しフローで候補者管理を⾃動化 ● 複数名の⾃動⽇程調整で80%時間を削減 多様化する採⽤プロセスに対応 ● 最適な選考プロセスを⾃由⾃在に構築 ● 多様なメンバーに適した権限 構造化⾯接で⾼精度の⾒極め可能 ● 採⽤基準の標準化‧カスタマイズ ● 各項⽬の評価を定量化 ウォンテッドリーの提供サービス (Wantedly Hire)

Slide 5

Slide 5 text

© 2024 Wantedly, Inc. 今日持ち帰ってほしいこと ● 巨大な tfstate はつらい ● が分割するのも一筋縄ではいかない ● 完璧を目指さず徐々に移行していこう

Slide 6

Slide 6 text

© 2024 Wantedly, Inc. ウォンテッドリーにおける Terraform の運用

Slide 7

Slide 7 text

© 2024 Wantedly, Inc. Wantedly を支えるインフラ環境 ● アプリケーションは Amazon EKS 上で 動いている ● Google Cloud も 一部で利用 https://docs.wantedly.dev/fields/infrastructure/infrastructure

Slide 8

Slide 8 text

© 2024 Wantedly, Inc. Terraform の利用箇所 青枠は Terraform で 管理している (つまりほとんどが Terraform 管理) https://docs.wantedly.dev/fields/infrastructure/infrastructure

Slide 9

Slide 9 text

© 2024 Wantedly, Inc. Terraform の CI/CD: GitHub Actions & tfaction ● ウォンテッドリーでは CI 環境として GitHub Actions を利用 中 ● Terraform の CI/CD を GitHub Actions で実現する フレームワークである tfaction を利用している ○ https://github.com/suzuki-shunsuke/tfaction ○ tfaction さえ導入すれば GitHub 上で Terraform の運用フローが作れる

Slide 10

Slide 10 text

© 2024 Wantedly, Inc. tfaction の紹介 ● GitHub での開発フローに則って terraform plan/apply が できる ○ PR を立てたら terraform plan が実行される ○ PR merge 時に terraform apply される ○ plan, apply 結果は PR にコメントされる https://suzuki-shunsuke.github.io/tfaction/docs/

Slide 11

Slide 11 text

© 2024 Wantedly, Inc. tfaction の紹介 ● monorepo に対応 ○ 1 つのリポジトリ内に複数の tfstate (= terraform init するディレクトリ) を置ける ○ それぞれのディレクトリに変更があったときだけ plan/apply される ● terraform apply 失敗時のフローも用意されている ○ https://suzuki-shunsuke.github.io/tfaction/docs/feature/follow-up-pr ● import や state mv などもコード管理・CI/CD できる ○ https://suzuki-shunsuke.github.io/tfaction/docs/feature/tfmigrate

Slide 12

Slide 12 text

© 2024 Wantedly, Inc. Terraform の CI/CD: Renovate ● Terraform 本体や provider、tfaction などの更新に 追従するための仕組みとして Renovate を利用 ● 利用しているバージョンを検知 => 更新があれば更新 PR を作成してくれる https://docs.renovatebot.com/

Slide 13

Slide 13 text

© 2024 Wantedly, Inc. 巨大 tfstate の歴史

Slide 14

Slide 14 text

© 2024 Wantedly, Inc. 言葉の定義: tfstate とはなにか ● ここでは便宜上 "tfstate" を 「terraform init を実行するディレクトリ」とします ○ *.tfstate というファイル (Terraform の state) がこの単位で作られること から "tfstate" と呼んでいます

Slide 15

Slide 15 text

© 2024 Wantedly, Inc. Terraform ディレクトリ構成 ● 単一リポジトリで管理 ● aws/ ○ CloudFront や WAF など 複数アプリケーションで跨いで 利用するリソース ● eks/ ○ EKS の Cluster, Node など ● monolith/ ○ それ以外 https://docs.wantedly.dev/fields/infrastructure/infrastructure

Slide 16

Slide 16 text

© 2024 Wantedly, Inc. このディレクトリ構成の課題 ● monolith がとにかく巨大になった ○ 先に述べたディレクトリ構成は明確な決まりがなかった ■ 「とりあえず monolith に置く」が多発 ○ resource 数は 1,000 をゆうに超える ○ plan/apply に 5 分以上かかる 😇

Slide 17

Slide 17 text

© 2024 Wantedly, Inc. monolith tfstate を分割する機運が生まれる ● 障害対応等で迅速に apply したいときに plan/apply が遅 くて困る ● configuration drift 発生時に apply できなくなる ○ Terraform 外で変更が発生したときに、その変更が巻き戻らないように Terraform コードへの変更が必要 ○ ちょっとした変更を加えたくても、まず drift を解消する手間がある

Slide 18

Slide 18 text

© 2024 Wantedly, Inc. monolith tfstate を分割する機運が生まれる ● どのリソースがどこに定義されているのかわからない ○ 特に新しく参加したインフラメンバーにとって認知負荷が高い ○ これもリソース定義が多すぎることが原因のひとつ

Slide 19

Slide 19 text

© 2024 Wantedly, Inc. plan/apply はなんとか高速化できる、が… ● 速度は並列数を上げると一定の改善ができた ○ terraform plan/apply には -parallelism オプションがある ■ デフォルト: 10 ■ これを 30 など増やせばよい ○ 5 分くらいが 2 分くらいまで短縮された 🎉

Slide 20

Slide 20 text

© 2024 Wantedly, Inc. plan/apply はなんとか高速化できる、が… ● が、今度は各サービスの API rate limit に引っ掛かる 問題が顕在化 ○ 具体的には大量に ElastiCache 系のリソースを定義している箇所で Describe* 系の API が多数発行され rate limit に引っ掛かっていた ○ API rate limit に引っ掛かると、大体の場合は時間を置いて plan/apply をやり直す必要があり、かなりの手間

Slide 21

Slide 21 text

© 2024 Wantedly, Inc. そして分割へ…

Slide 22

Slide 22 text

© 2024 Wantedly, Inc. 解決したい課題 ● plan/apply を高速化したい ● rate limit に引っ掛からないようにしたい ● 人にとってわかりやすい構成にしたい

Slide 23

Slide 23 text

© 2024 Wantedly, Inc. 課題にどう立ち向かうか ● monolith tfstate を細かい単位で分割していく ○ tfstate を小さくすればその分 plan/apply 速度は改善するはず ○ rate limit にも引っ掛かりにくくなるはず ○ tfstate の分割単位を工夫すれば人にとって分かりやすくなるはず

Slide 24

Slide 24 text

© 2024 Wantedly, Inc. tfstate 指針を決める tfstate の分割指針 ● アプリケーションや サービスごとに tfstate を わける ● 環境ごとに tfstate を わける 例 ● visit/ ○ sandbox/, qa/, prod/ ● hire/ ○ sandbox/, qa/, prod/ ● datadog/ ○ sandbox/, qa/, prod/

Slide 25

Slide 25 text

© 2024 Wantedly, Inc. 分割は一筋縄ではいかない ● 実際に分割するのはハードルが高い ○ 1,000 以上のリソースを適切な粒度で分割する、というのは時間がかかる ■ 数が多いと単に時間がかかる ○ 「適切な粒度」というのも先の例に嵌らないものもあり難しい ■ 困る例: 複数のアプリケーションから参照されている Aurora cluster は どう分割する? ● =>「初めから完璧を目指さない」という方針で進める

Slide 26

Slide 26 text

© 2024 Wantedly, Inc. 徐々に分割する 具体的にどうするか? ● monolith tfstate には新しいリソースを置かない

Slide 27

Slide 27 text

© 2024 Wantedly, Inc. 徐々に分割する ● 直近の例: Wantedly Hire 系のリソース定義は hire/ 下に 置く ● ただし必ず従わなくてもよい ○ tfstate の新規作成が手間なら一旦 monolith tfstate に置いてもよい ○ 「分割」はあくまでも困り事を解消するための手段なので、本来の仕事を優先する ○ 分割によって困り事が増えるのは本末転倒

Slide 28

Slide 28 text

© 2024 Wantedly, Inc. 徐々に分割する すでに monolith tfstate にあるリソースはどうする? ● すべては分割せず、困ったものから tfstate を 分割していく

Slide 29

Slide 29 text

© 2024 Wantedly, Inc. 徐々に分割する ● 具体例: rate limit に引っ掛かりがちだった ElastiCache の定義のみ elasticache/ ディレクトリに切り出す ○ 本来は ElastiCache が使われているサービスごとに分割したい ■ (Wantedly Visit で使っている ElastiCache は visit 配下に置く、など) ○ しかし「サービスごと」という分割の粒度を決めるのは、それはそれで大変 ○ 直近の困り事の解決を優先して、一旦分割しやすい elasticache/ という粒度で分割 する

Slide 30

Slide 30 text

© 2024 Wantedly, Inc. 分割して得られた嬉しさ ● 「完璧を目指さない」という方針のため分割は道半ば ● それでも直近の問題は解消された ○ 5 分かかっていた plan/apply は 10 秒ほどで終わるようになった ○ 分割したディレクトリで configuration drift が発生しても 他のディレクトリに影響がなくなった ○ API rate limit に引っ掛からなくなった

Slide 31

Slide 31 text

© 2024 Wantedly, Inc. ファイルの見通しもよくなった ● monolith tfstate はファイル単位でも monolithic になっ ていた ○ 例: ElastiCache cluster の定義はすべて elasticache.tf に置く ○ 中には 4,000 行近くのファイルも…

Slide 32

Slide 32 text

© 2024 Wantedly, Inc. ファイルの見通しもよくなった ● tfstate 分割に伴い ファイルを分割しやすくなっ た 例: ● hire/prod/ ○ s3.tf ○ cloudfront.tf ○ rds.tf

Slide 33

Slide 33 text

© 2024 Wantedly, Inc. Renovate PR を分割する ● Renovate が作成する PR の分割単位はパッケージごと ○ 例: AWS provider の更新 PR、Google Cloud provider の更新 PR、… ● つまり複数 tfstate をまたいで 1 つの PR が作成される

Slide 34

Slide 34 text

© 2024 Wantedly, Inc. Renovate PR を分割する これのつらいところ: ● AWS provider の更新があると大量の tfstate を変更した PR が作られる ○ 分割した tfstate ではほぼ全て AWS provider に依存しているため ● 頻繁に & 大量に plan/apply されるため CI 時間も無駄 ○ Renovate はベースブランチに更新があるとその更新を取り込むため、 頻繁に実行される

Slide 35

Slide 35 text

© 2024 Wantedly, Inc. Renovate PR を分割する ● 対策: Renovate PR を tfstate ごとに分割する ○ renovate.json 例: { "packageRules": [ { "matchManagers": ["terraform"], "matchDatasources": ["terraform-provider"], "additionalBranchPrefix": "{{packageFileDir}}-", "commitMessagePrefix": "{{packageFileDir}}: ", }, ] }

Slide 36

Slide 36 text

© 2024 Wantedly, Inc. 分割によって見えてきた新たな課題 ● Renovate PR が多い ○ tfstate の数 × provider 等のバージョン更新の回数だけ PR が作成される ○ 特に AWS provider は更新頻度も高く、利用している tfstate も多い ● tfstate ごとに分けるほどでもないファイルの変更が困難 ○ 例: tflint の設定ファイルは共通のルールを使いたい ○ Renovate と同様に複数の tfstate をまたいだ変更になるため plan/apply の 回数が多くなる

Slide 37

Slide 37 text

© 2024 Wantedly, Inc. 今日持ち帰ってほしいこと (再掲) ● 巨大な tfstate はつらい ● が分割するのも一筋縄ではいかない ● 完璧を目指さず徐々に移行していこう

Slide 38

Slide 38 text

© 2024 Wantedly, Inc. https://www.wantedly.com/projects/522096

Slide 39

Slide 39 text

© 2024 Wantedly, Inc. https://wantedly.connpass.com/event/332164/