7K Views
September 07, 22
スライド概要
Terraform 入門
Terraform入門 つまずきポイント集 @nlog2n2 Sekiguchi Toshihiro
ssmjp は運用とセキュリティの勉強会 • 最近書いた Ansible の Playbook ssmjp の slack に security チャンネルができました!! 今日、一番の見せ場(スクショチャンス)
コメント稼ぎ(Twitterで猫可愛いって言ってね!) • 質問・コメントがあればTwitterへお願いします!
おしながき • 経緯と今日話さないこと • Terraformとは • Terraformのつまずきポイント • 秘匿情報と環境変数 • 配列の利用 • module化の罠 • 既存リソースの参照 • tfstateファイルの管理 保護猫カフェ たまゆら ショウくん@人形町
経緯と 今日話さないこと
経緯と今日話さないこと • 経緯 • お仕事で某クラウドの構築を任された • AWSではないため、GUI コンソールの知見がない • リストア方式として IaC を利用したかった • 今日話さないこと • Terraform のインストール • Terraform の構文 • GithubAcitonsでの CI/CD
IaC使ってますか? https://www.mentimeter.com/app/presentation/e37e498d4ab4646b64e26aa571e91a5b/40672e9303cc
Terraformとは
Terraformとは • 公式(https://www.terraform.io/) Compose infrastructure as code in a Terraform le using HCL to provision resources from any infrastructure provider. • ざっくり日本語翻訳 Terraformで、どんなクラウドのリソースも作成できます。 Terraform は HCL (HashiCorp Con guration Language)のコードで定義 されています。 • 要約 fi fi Terraform、最高!!
Terraformとは • 対応ベンダー • Amazon Web Service • Microsoft Azure • Google Cloud Platform • Oracle Cloud Infrastructure 公式ページのチュートリアル
VS Code の拡張機能あり 補足:Visual Studio Code に拡張機能あり(fmt コマンド自動補完機能もあり)
Terraformのベストプラクティス Google 先生、Terraformのベストプラクティスも教えてくれる。 https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl=ja
使い方
Terraformの利用方法 1. コードを頑張って書きます *.tf ファイルにインフラ構成を書く 2. Terraform の初期化(もしくはmoduleの読み込み) terraform init 3. Terraformの現状のインフラ構成との比較 terraform plan -var- le env.tfvars 4. クラウドサービスへのデプロイ実施 terraform apply -var- le env.tfvars fi fi fi 5. リソースの削除(バルス) terraform destroy -var- le env.tfvars
init の実行 • 初期化を実行する
plan の実行 • vpc.tf で VPCを作って、plan を実行する resource "aws_vpc" "sample_vpc" { cidr_block = "192.168.100.0/24" tags = { "Name" = "sample_vpc" } }
よしっ!
apply の実行 • 本当に実行するのか聞かれる。反映する場合は yes とだけ入力する。 リソースをAWSコンソール上で確認した。 左は現在のリソース情報をまとめた tfstate ファイル。
バルス!(destroyの実行)
1.秘匿情報と環境変数
秘匿情報と環境変数 ここで変数の定義と変数の値を代入するが、 利用するファイル • 環境変数:env.tfvars • 変数定義:variables.tf • 自動生成:terraform.tfstate • リソース:provider.tf, vpc.tf env.tfvars *.tf だと Git で管理されてしまう。 AWS の接続情報などを入れると、 AWS に対する非常強い権限をGithubなどで 変数の値の参照 管理することになるため、よろしくない。 variables.tf 変数(定義、値)の参照 provider.tf vpc.tf AWSへの接続 VPCの作成 terraform の実行結果 terraform.tfstate
秘匿情報と環境変数 というわけで、.gitignore に env.tfvars を追加し、 利用するファイル • 環境変数:env.tfvars • 変数定義:variables.tf • 自動生成:terraform.tfstate • リソース:provider.tf, vpc.tf env.tfvars コマンド実行時に環境変数を読み込む方式にする。 AWS 相手なら git-secrets とか入れると幸せになる かもしれない。 変数の値の参照 実行時のコマンド variables.tf terraform plan -var- le env.tfvars 変数(定義、値)の参照 provider.tf vpc.tf AWSへの接続 VPCの作成 terraform の実行結果 fi terraform.tfstate
変数の受け渡し env.tfvars variables.tf provider.tf 変数の値の参照 変数(定義、値)の参照
.gitignore(Githubのものに追加) # Local .terraform directories **/.terraform/* # .tfstate files *.tfstate *.tfstate.* # Crash log files crash.log # # # # # Ignore any .tfvars files that are generated automatically for each Terraform run. Most .tfvars files are managed as part of configuration and so should be included in version control. example.tfvars # Ignore override files as they are usually used to override resources locally and so # are not checked in override.tf override.tf.json *_override.tf *_override.tf.json # Include override files you do wish to add to version control using negated pattern # # !example_override.tf # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan # example: *tfplan* env.tfvars
つまずきポイント
つまずいたポイント 利用するファイル • 環境変数:env.tfvars • 変数定義:variables.tf • 自動生成:terraform.tfstate • リソース:provider.tf, vpc.tf env.tfvars ここの定義が抜けており、env.tfvars の定義のみ で変数を参照してくれるものだと思っていた。 しばらく、この変数定義のファイルの扱いで何度 もつまづくことになる。 変数の値の参照 variables.tf 変数(定義、値)の参照 provider.tf vpc.tf AWSへの接続 VPCの作成 terraform の実行結果 terraform.tfstate
変数の受け渡し env.tfvars variables.tf 変数の値の参照 ここの定義を忘れており、provider.tf で変数が使えなかった。 provider.tf 変数(定義、値)の参照
2.配列の利用
配列の利用 • 地獄のセキュリティグループ設定 • 同じポートを複数のソースIPアドレスまたはセグメントから受け付ける • 何度も同じような定義をコピー&ペーストするコードは避けたい 配列を使おう!となったが、 Terraform に for 文みたいな概念なかったような...
配列の利用 • 地獄のセキュリティグループ設定 • 同じポートを複数のソースIPアドレスまたはセグメントから受け付ける • 何度も同じような定義をコピー&ペーストするコードは避けたい 配列を使おう!となったが、 Terraform に for 文みたいな概念なかったような... for.each でリストを定義し、 each.key でループ処理を定義できるらしい
配列の利用
配列の利用 AWSでセキュリティグループのサンプル書こうとしたら、 AWSは元からソースIPがリストで定義できるやん。AWS素敵。 しゃーないWAFの設定書くか。
WAFのIPセット設定(サンプル) 基本的な書き方 リストに書き換え 実行結果 申し訳程度のセキュリティ要素
つまずきポイント
配列の利用 例は配列ですが、何が定義されているか、 どういう処理をしているかパッと見で理解しにくい。 他人が書いたコードはこういう表現が大量にあって、 Terraform 初心者(3日目)の心をえぐってくるw
3.module 化の罠
module • 公式(https://www.terraform.io/language/modules) Modules are containers for multiple resources that are used together. A module consists of a collection of .tf and/or .tf.json les kept together in a directory. Modules are the main way to package and reuse resource con gurations with Terraform. • ざっくり日本語翻訳 コンテナ化された複数のリソースをつかうための仕組みです。 モジュールはディレクトリにまとめられた .tf と .tf.json ファイルで構成されています。 モジュールは、Terraformでのリソース定義をパッケージ化しリソース再利用するための主な手法です。 • 要約 fi fi なるほど。わからん。
ざっくりとした理解 env.tfvars モジュール化 変数の値の参照 ネットワーク部分 値の代入と リソースの作成 モジュール化 値の代入と リソースの作成 インスタンス部分 variables.tf 変数(定義、値)の参照 main.tf モジュールの変数(値)の代入 terraform の実行結果 terraform.tfstate
ざっくりとした理解 ネットワーク部分 variables.tf 値の代入と リソースの作成 network.tf env.tfvars 変数の値の参照 variables.tf output.tf 変数(定義、値)の参照 インスタンス部分 variables.tf instance.tf 値の代入と リソースの作成 main.tf モジュールの変数(値)の代入 terraform の実行結果 terraform.tfstate output.tf
output.tf とは? ネットワーク部分 variables.tf network.tf output.tf env.tfvars 値の代入と リソースの作成 変数の値の参照 出力する ここで他のモジュールが参照する変 数と値を定義する。 variables.tf 参照する インスタンス部分 variables.tf instance.tf 値の代入と 他のモジュールで定義された リソースの作成 サブネットを参照したい。 変数(定義、値)の参照 main.tf モジュールの変数(値)の代入 参照する terraform の実行結果 terraform.tfstate output.tf アウトプットしないのは知的な便秘
メリット:完コピ環境がつくれる env.tfvars env.tfvars env.tfvars variables.tf variables.tf variables.tf main.tf main.tf terraform.tfstate terraform.tfstate 開発環境 ステージング環境 main.tf ここのパラメータを変えるだけ terraform.tfstate 本番環境
つまずきポイント
変数の参照と定義、煩雑になるコード ネットワーク部分 variables.tf network.tf output.tf 1.作り忘れた 値の代入と リソースの作成 instance.tf output.tf 変数の値の参照 出力する variables.tf 1.作り忘れた ここで他のモジュールが参照する変 数と値を定義する。 インスタンス部分 variables.tf env.tfvars 1.作り忘れた 値の代入と main.tf の variables.tf が使えない 他のoutput.tf で定義した値を参照で リソースの作成 きてない 参照する 2.変数の定義も忘れる 変数(定義、値)の参照 main.tf 3.モジュールの変数(値)に、 ・変数の値 参照する terraform の実行結果 ・output.tf 代入することを理解してなかった terraform.tfstate
変数の参照と定義、煩雑になるコード ネットワーク部分 variables.tf network.tf output.tf 1.作り忘れた env.tfvars 値の代入と リソースの作成 変数の値の参照 出力する variables.tf 1.作り忘れた ここで他のモジュールが参照する変 2.変数の定義も忘れる 変数の扱いで1日ぐらい苦しむ 数と値を定義する。 インスタンス部分 variables.tf instance.tf output.tf 1.作り忘れた 値の代入と main.tf の variables.tf が使えない 他のoutput.tf で定義した値を参照で リソースの作成 きてない 参照する 変数(定義、値)の参照 main.tf 3.モジュールの変数(値)に、 ・変数の値 参照する terraform の実行結果 ・output.tf 代入することを理解してなかった terraform.tfstate
変数の参照と定義、煩雑になるコード ネットワーク部分 variables.tf network.tf 1.作り忘れた env.tfvars 値の代入と リソースの作成 変数の値の参照 出力する そして今は var で定義しているけど、 output.tf variables.tf 1.作り忘れた ここで他のモジュールが参照する変 数と値を定義する。 参照する 2.変数の定義も忘れる 変数(定義、値)の参照 local で定義しなおしが必要そう😅 インスタンス部分 variables.tf instance.tf output.tf 1.作り忘れた 値の代入と main.tf の variables.tf が使えない 他のoutput.tf で定義した値を参照で リソースの作成 きてない main.tf 3.モジュールの変数(値)に、 ・変数の値 参照する terraform の実行結果 ・output.tf 代入することを理解してなかった terraform.tfstate
つまずきポイント (追加)
モジュールの依存関係 モジュールの依存関係を工夫しないと意図しないリソースの削除が発生したり する(完全に罠) 依存関係を明示的に書いて、依存元のコードを修正すると、依存しているリソ ースは再作成されるみたい...(ssmjp の cloud チャンネルで教えてもらった) 依存関係は自動的に tfstate が管理するみたいなので、そっちに任せて意図的 に書かなくてもいいかという境地になった。
つまずきポイント (追加)
どうモジュール化するか • 変数やモジュールの制御に if 文が使えないため、 モジュールの構成をどうするかは、結構、重要なことだと思っている。 • モジュールA群(開発環境の main.tf で読み込む) • モジュール1 • モジュール2 • モジュールB群(ステージング環境の main.tf で読み込む) • モジュール1 • モジュール3(モジュール2の派生) • モジュールC群(本番環境の main.tf で読み込む) • モジュール1 • モジュール4(モジュール2の派生) モジュール2、モジュール3、モジュール4ってどうやって統制をとりながら管理するんだ?みたいな課題が発生する。 なお、モジュール化を諦めて各環境の *.tf とかで書くこともできるけど、Terraformの旨味の1つが消えることになる。 モジュール2、モジュール3、モジュール4の制御を三項演算子で書くこともできるだろうけど、素人には辛いコードになる。
そんな貴方に override.tf
どうモジュール化するか • Terraform には、override.tf を用意した場合、読み込んだモジュールの値を上書きするという機能が存在する。 従って、以下のようなディレクトリ構成にし、設定が変わる部分に関しては override.tf で書き換えることがよさそう。 追加で必要なリソースがある場合は、追加で *.tf を作って、その中で定義してあげると追加でリソースが作られる。 • 適当な名前の親ディレクトリ • 機能別モジュール群専用ディレクトリ • 機能別モジュールA(main.tf,variables.tf,output.tf) ここは全体的な変更があったとき、各環境で apply を実施すると一括で構成変更ができ • 機能別モジュールB(main.tf,variables.tf,output.tf) る。パッと思いつく範囲だと、セキュリティで空けたいIPアドレスが増減した時です。 • 機能別モジュールC(main.tf,variables.tf,output.tf) 注意事項 • プロダクト別ディレクトリ • ネストされている値はマージされない仕様 • プロダクトA専用ディレクトリ • 過度な利用は控えろと公式が言っている • 開発環境 • すべてのプロダクトで使える共通モジュールを作れるというのは幻想 • 機能モジュールA読み込みディレクトリ • (既存)機能別モジュールAのmain.tfをシンボリックリンク、variables.tf はコピーを置く • (新規)override.tfでパラメータの値をカスタマイズ、additional.tf で新規リソースの作成しカスタマイズ • 機能モジュールB読み込みディレクトリ • (既存)機能別モジュールAのmain.tfをシンボリックリンク、variables.tf はコピーを置く • (新規)override.tfでパラメータの値をカスタマイズ、additional.tf で新規リソースの作成しカスタマイズ • main.tf (機能別モジュールA読み込みディレクトリ、機能別モジュールB読み込みディレクトリ、機能別モジュールCのパラメータを設定) • variables.tf 申し訳程度の運用要素
4.既存リソースの参照
つまずきポイント
既存のリソースの参照 Terraformは既にクラウド上に作ってしまったリソース、もしくはベンダーが標準で提供してい るリソースを参照することは可能です。 しかし、配列で既存のリソースを取得すると、配列の順序が変わる(いわゆるガチャ状態)にな ることがあるらしく、ここは文字列型で固定にした方がよいという知見を最近得た。 もしくは lifecycle の ignore̲changes で状態の変更管理から外す。
5.tfstateファイルの管理
tfstate.tf とは? ざっくりとした理解 • Terraformで作ったリソースをまとめたもので、 terraform apply した時に更新される。 • Terraform外で作ったリソースに関しては、このフ ァイルでは扱われない。 • もし terraform の管理下に既存のインフラ構成を取 り込みたいのであれば、心をこめて、terraform import を行い、差分の修正作業を行うことになる。 • デフォルトではローカルに保存されるが、クラウド ストレージに自動アップロードする機能が存在す る。
つまずきポイント
どの単位で保存するのか どこに保存するのか
tfstate ファイルの管理 • S3への保存で管理? → 手動でアップロードしてて非常に手間である → backend 機能が存在することを知る(tfstateの自動アップロード機能) → どのAWSアカウントのS3バケットに保存するのか(バージョニングはONに) • どの単位で保存するのか?環境ごとに保存するのか? → 多分、どの単位(構成別)で設計するか方針決めが必要では 申し訳程度の運用要素
どのように メンテナンスを していくのか
tfstate ファイルの管理 冪等性の維持のために必ず IaC で構成を変更する必要がある。以下のようなコストが発生する。 1. 現状の構成の確認(tfsate と現状がずれているとそこの修正から入る) 2. 手動での環境構築し、とりたい構成が取れるか確認 3. 手動の環境構築を消す、もしくは terraform import し tfsate ファイル配下に構成を取り込む 4. Terraform化して Terraform の検証とデバッグ 5. モジュール化、メンテナンスが楽になるようにリファクタリングの実施 6. 各環境での適用チェック 申し訳程度の運用要素
tfstate ファイルの管理 これとは別にドキュメントの構成管理も実施しなければならない。 Terraform の冪等性はかなり高い水準にあるとおもう(Ansibleと比べてと言う感じですが) 大企業なら構成変更は少ないかもしれないが、小さい企業で構成変更のスピード感が求められる 会社だと、メンテナンスして維持すること自体が困難になる。 コード内のコメントからドキュメント生成するようなツールがないのが痛すぎると感じている。 IaCで受けられる恩恵・企業体力・技量のバランスは運用時に難しい課題だと感じている。 申し訳程度の運用要素
そもそもな話どこで実行するの?
tfstate ファイルの管理 • Terraformは IaC と言う性質から強烈な権限を持っているため、世の中にあるCI/CDのSaaS サービスを使って、プロバイダー情報が漏洩のリスク考えると、どうしてもローカルで実行み たいな環境になり、いつどこで最後にデプロイが走ったかわからない。 • 各環境に閉じた中でCD走らせるサービスがいいなぁとなると、AWSならクラウドフォーメー ションみたいにスタック残せるサービスないのか?と思っていたり。。。
まとめ
まとめ • とりあえず2週間ぐらい 2ヶ月やって苦しんだところ 発表を応募してからネタが溜まる溜まるw • おそらくこれからメンテナンスを続けると変数の扱いで苦しみそう • SREもしくはDevOpsのチーム内で IaC の運用方針とコーディング規約、テ ンプレートの作成&レビューなどが本来は必要そう • 最近、さらに Lv. があがったのか、2週間前のコードをリファクタリングした い病にかかっている
まとめ 変数を制すものが Terraformを制す
まとめ AWS でやりたいな
まとめ AWS は幸せ