はじめに
インフラ構成をコード化するIaC(Infrastructure as Code)の代表的サービスであるTerraform。
このTerraformを学ぶ上で書籍『実践Terraform AWSにおけるシステム設計とベストプラクティス』がよく参考にされています。
本記事ではこの書籍をこれから読む方向けに、書籍内で紹介されているサンプルプロジェクトを構成するリソースを図にして紹介します。
『実践Terraform』
タイトル:『実践Terraform AWSにおけるシステム設計とベストプラクティス』
著者:野村友樹(@tmknom)氏
発行:株式会社インプレスR&D
※@tmknomさん、インプレスR&Dさん、書影掲載許可いただきありがとうございます!
『実践Terraform AWSにおけるシステム設計とベストプラクティス』(以下『実践Terraform』とします)は、著者が技術書展やBOOTHなどで頒布されていた『Pragmatic Terraform on AWS』という同人誌を元にした内容となっています。
出版にあたり、同人誌時代から、100ページ近くページ追記・改定した内容になっており、Terraform界隈では神本として多くの人に認知されているようです。
Terraformの環境整備から、サンプルプロジェクトでのアーキテクチャ構築ハンズオン、Tipsまで幅広く掲載されており、初心者向けの参考書籍として最適です。
紹介記事(一部)
- 「Pragmatic Terraform on AWS」が神本だったので紹介する
- Terraformのエッセンスが凝縮された「Pragmatic Terraform on AWS」が素晴らしい
- 「Pragmatic Terraform on AWS」を読んだ
書籍を利用してみて
Terraformに初めて触れる初心者の私でも、この本の通りにイチから順序立てて作業することで、立派なAWSのアーキテクチャを構築することができました!
※なお、AWS SAAの学習をしている時期でもあったため、AWSの超基礎的な知識は持っていました。
ただ、正直に言うと、組み上げているものの全体像が把握できず、とりあえず写経をしている、という状況になっていたのも事実です。
著者のサンプルコードリポジトリにコード等も載っているのですが、章ごとに追記する内容のみがまとめられているため、Terraform初心者の私としては全体の構造の把握に苦労してしまいました。
そこで、実際にTerraformで構築するリソースを図式化してみて、理解を深めようと考えました。
ここでは、その成果物とともに振り返り、同じ思いをする人を少しでも減らせられれば良いかなと思っています。
全体図
今回は「第5章 権限管理」から「第16章 ロギング」までを対象として説明させていただきます。
1章から4章はTerraformの使い方や基本的な構文の説明で、17章以降はベストプラクティスとか継続的Applyとか、オプショナルな感じなので、図解はあまり有効ではないと判断しました。
早速ですが下記が全体のイメージです。
※結構細かいのでクリックして拡大すると見やすいと思います。
作成するリソースは種類も数もとても多いため、大きくAWSサービスと、汎用的に用いるモジュールという分類で下記の形でレイヤーとして分割をしています。
さらに、具体的に作成するリソースやデータも下記のような形、色にて分類をしてみました。
リソース(青)は下記のような構造で表現しています。
上から順に「リソースの説明」「リソース種類名」「リソースに付けた名前」を表記しました。
書籍内ではリソースに名前をつけていない場合もあるのですが、そのような場合はとりあえずexample
と名付けています。(多分)
また、データ(黄)も同様の構造なので、同じルールにて記載しています。
モジュール(緑)は「リソース種類名」が必要ないため、除外しています。
その他、output
やprovider
といった記載も書籍内では紹介されますが、アーキテクチャの理解にはそれほど影響を与えないため、除外しています。
矢印はリソース間の関係を示しています。
ただし、VPC等多くのリソースから依存されているものの関係性をすべて記載すると矢印の量がすごいことになるので、理解をする上でそれほど重要ではなさそうな部分は除外しています。
上記の前提で図を見ていただければと思います。
なんとなく、作ろうとしているシステムの全体像が見えてくるのではないでしょうか。
各章ごとの対応箇所
ざっと全体のイメージをご紹介しました。
ここからは、各章ごとに生成したリソースを抽出して見ていこうと思います。
第5章 権限管理
第5章では権限管理のためのIAMロールを作成します。
一通りのIAMロール説明が完了したところで、作成するサンプルプロジェクトで多様されるIAMロールモジュールを作成します。
図は最終的なIAMロールモジュールの構成です。
作成したIAMロールモジュール用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_iam_role | default | IAMロール |
data | aws_iam_policy_document | assume_role | 信頼ポリシー(ポリシードキュメント) |
resource | aws_iam_policy | default | IAMポリシー |
resource | aws_iam_role_policy_attachment | default | IAMポリシーのアタッチ(IAMロールにIAMポリシーをアタッチする) |
第6章 ストレージ
第6章ではストレージとして用いるS3バケットを作成します。
サンプルとしてパブリックバケット、プライベートバケット、ALBログ用バケットを作成しますが、ALBログ用バケットは第7章 ネットワークでも利用されます。
作成したS3用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_s3_bucket | private | プライベートバケット |
resource | aws_s3_bucket_public_access_block | private | プライベートバケットのパブリックアクセス定義 |
resource | aws_s3_bucket | public | パブリックバケット |
resource | aws_s3_bucket | alb_log | ログバケット(後に定義するALB用のログを格納する) |
data | aws_iam_policy_document | alb_log | ALBログを書き込むためのIAMポリシー |
なお、リスト6.5
にidentifiers
を直接記載する箇所がありますが、ソース管理上アカウントIDを直接記載したくないため、aws_elb_service_account
のデータを参照する形に調整を行いました。
# ログの書き込みに使用されるアカウントIDを自動的にフェッチできる
data "aws_elb_service_account" "alb_log" {}
# リスト6.5 ALBログを書き込むためのIAMポリシー
data "aws_iam_policy_document" "alb_log" {
statement {
effect = "Allow"
actions = ["s3:PutObject"]
resources = ["arn:aws:s3:::${aws_s3_bucket.alb_log.id}/*"]
principals {
type = "AWS"
identifiers = ["${data.aws_elb_service_account.alb_log.id}"] # 参照
}
}
}
追加したサービスアカウント取得用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
data | aws_elb_service_account | alb_log | ログの書き込みに使用されるアカウントIDを自動的にフェッチする |
第7章 ネットワーク
第7章ではネットワーク(VPC)とセキュリティグループを作成します。
章内の7.1パブリックネットワーク
、7.2 プライベートネットワーク
で構築された下記リソースは、7.3マルチAZ
以降でマルチAZ化に伴って細分化変更されます。
上図は7章完了状態の図のため、マルチAZ前のリソースは図中には存在しません。
調整前リストNo. | 名称 | 調整後リストNo. |
---|---|---|
リスト7.2 | パブリックサブネット | リスト7.12 |
リスト7.6 | パブリックサブネット用ルートテーブルの関連付け | リスト7.13 |
リスト7.7 | プライベートサブネット | リスト7.14 |
リスト7.8 | プライベートサブネット用ルートテーブルと関連付け | リスト7.16 |
リスト7.9 | プライベートサブネット用のEIP | リスト7.15 |
リスト7.10 | プライベートサブネット用のNATゲートウェイ | リスト7.15 |
リスト7.11 | プライベートサブネット用のルート | リスト7.16 |
また、セキュリティグループ
は第5章 権限管理で作成したIAMモジュール
と同様に、他の章で生成するリソースからも多用されるため、モジュールとして生成されています。
作成したマルチAZのVPC用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_vpc | example | VPC |
resource | aws_internet_gateway | example | インターネットゲートウェイ |
resource | aws_subnet | public_0 | AZ0のパブリックサブネット |
resource | aws_subnet | public_1 | AZ1のパブリックサブネット |
resource | aws_route_table | public | パブリックサブネット用ルートテーブル |
resource | aws_route | public | パブリックサブネット用ルート(ルートテーブルのレコード) |
resource | aws_route_table_association | public_0 | AZ0のパブリックサブネットとルートテーブルの関連付け |
resource | aws_route_table_association | public_1 | AZ1のパブリックサブネットとルートテーブルの関連付け |
resource | aws_subnet | private_0 | AZ0のプライベートサブネット |
resource | aws_subnet | private_1 | AZ1のプライベートサブネット |
resource | aws_eip | nat_gateway_0 | AZ0のNATゲートウェイ用EIP |
resource | aws_eip | nat_gateway_1 | AZ1のNATゲートウェイ用EIP |
resource | aws_nat_gateway | nat_gateway_0 | AZ0のNATゲートウェイ |
resource | aws_nat_gateway | nat_gateway_1 | AZ1のNATゲートウェイ |
resource | aws_route_table | private_0 | AZ0のプライベートサブネットのルートテーブル |
resource | aws_route_table | private_1 | AZ1のプライベートサブネットのルートテーブル |
resource | aws_route | private_0 | AZ0のプライベートサブネットのルート |
resource | aws_route | private_1 | AZ1のプライベートサブネットのルート |
resource | aws_route_table_association | private_0 | AZ0のプライベートサブネットのルートテーブルの関連付け |
resource | aws_route_table_association | private_1 | AZ1のプライベートサブネットのルートテーブルの関連付け |
作成したセキュリティグループモジュール用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_security_group | default | セキュリティグループ |
resource | aws_security_group_rule | ingress | セキュリティグループルール(インバウンド) |
resource | aws_security_group_rule | egress | セキュリティグループルール(アウトバウンド) |
第8章 ロードバランサーとDNS
第8章ではロードバランサー(ALB)を作成し、Route53でDNSを設定します。また、SSL化のためにACMを利用します。
学習を行う上で、ドメインとSSLを入れない選択を取ることもできます。
その場合は、Route53、ACMを設定せずにELBのみ作成して試すことが可能なので、図内ELBのHTTPS化を行わない場合の構成を作成すれば良いです。
図中にsg
というモジュールがありますが、これは第7章 ネットワークで作成したセキュリティグループモジュール
を示しています。
また、図中のALBログ用バケット
は第6章 ストレージで作成済みのリソースを利用するため、この章で追加で作る必要はありません。
作成したELB用のリソースは下記です。
HTTPS化を行う場合と行わない場合、両方に関して記載しています。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_lb | example | ALB |
module | - | http_sg | HTTP用セキュリティグループ |
module | - | https_sg | HTTPS用セキュリティグループ |
module | - | http_redirect_sg | HTTPからHTTPSへのリダイレクト用セキュリティグループ |
resource | aws_lb_listener | http | HTTPリスナーの定義(HTTPS化を行わない場合) |
resource | aws_lb_listener | https | HTTPSリスナーの定義(HTTPS化を行う場合) |
resource | aws_lb_listener | redirect_http_to_https | HTTPからHTTPSへのリダイレクトリスナーの定義(HTTPS化を行う場合) |
resource | aws_lb_target_group | example | ターゲットグループ |
resource | aws_lb_listener_rule | example | リスナールール(HTTPS化を行う場合と行わない場合でlistener_arnの設定値が異なる) |
作成したRoute53用のリソースは下記です。
図はホストゾーンが既にある状態を想定していますが、下記には新規に作成する場合に関しても記載しています。
また、SSL証明書を利用しない場合は、SSL証明書検証用レコード定義は必要なくなります。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
data | aws_route53_zone | example | ホストゾーンの参照(ホストゾーンがすでにある場合) |
resource | aws_route53_zone | example_test | ホストゾーンの作成(ホストゾーンを新規に作成する場合) |
resource | aws_route53_record | example | ALBのDNSレコード |
resource | aws_route53_record | example_certificate | SSL証明書の検証用レコード |
作成したACM用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_acm_certificate | example | SSL証明書 |
resource | aws_acm_certificate_validation | example | SSL証明書の検証完了まで待機(apply時にSSL証明書の検証が完了するまで待つ。何かのリソースが作られるわけではない。) |
第9章 コンテナオーケストレーション
第9章ではコンテナオーケストレーション環境を作成します。
コンテナ定義はcontainer_definition.json
で行われています。
これはTerraformプロジェクト内に置かれる定義ファイルで、構成図に本来載るものではないとは思うのですが、関係性を明示したかったので記載しました。(わかりやすければええやん精神)
図中にiam
というモジュールがありますが、これは第5章 権限管理で作成したIAMモジュール
を示しています。
また、図中のターゲットグループ
は第8章 ロードバランサーとDNSで作成済みのリソースを利用するため、この章で追加で作る必要はありません。
作成したCloudWatch用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_ecs_cluster | example | ECSクラスター |
resource | aws_ecs_task_definition | example | ECSタスク定義 |
resource | aws_ecs_service | example | ECSサービス(起動タスクの数やタスクの維持、ALBとの橋渡し) |
module | - | nginx_sg | Nginx用セキュリティグループ |
作成したACM用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_cloudwatch_log_group | for_ecs | CloudWatch Logs |
data | aws_iam_policy | ecs_task_execution_role_policy | ECSタスク実行IAMロールポリシーの参照(AWSが管理しているポリシー) |
data | aws_iam_policy_document | ecs_task_execution | ECSタスク実行IAMロールのポリシードキュメント |
module | - | ecs_task_execution_role | ECSタスク実行IAMロール |
第10章 バッチ & 第12章 設定管理
第10章ではECSとCloudWatchを用いたバッチ処理を作成します。
バッチの作成で用いるバッチ用コンテナ定義は、第12章でSSMパラメータを使う形に調整されています。
そのため、第10章と第12章は一つにまとめて図を紹介しました。
また、図中のECSタスク実行IAMロール
は第9章 コンテナオーケストレーションで作成済みのリソースを利用するため、この章で追加で作る必要はありません。
作成したECS用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_ecs_task_definition | example_batch | バッチ用ECSタスク定義 |
作成したCloudWatch用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_cloudwatch_log_group | for_ecs_scheduled_tasks | バッチ用CloudWatch Logs |
module | - | ecs_events_role | CloudWatchイベントIAMロール |
data | aws_iam_policy | ecs_events_role_policy | CloudWatchイベントIAMロールポリシー |
resource | aws_cloudwatch_event_rule | example_batch | CLoudWatchイベントルール |
resource | aws_cloudwatch_event_target | example_batch | CloudWatchイベントターゲット |
作成したSSM用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_ssm_parameter | db_username | DBのユーザ名の定義 |
resource | aws_ssm_parameter | db_password | DBのダミーパスワードの定義 |
第11章 鍵管理
第11章では第13章で用いるためのカスタマーキーを作成します。
作成するカスタマーマスターキー
にはUUIDが割り当てられているのですが、人には識別しづらい体系であるため、分かりやすい名前のエイリアス
を作成しています。
作成したKMS用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_kms_key | example | カスタマーマスターキー |
resource | aws_kms_alias | example | エイリアスの定義(カスタマーキーのUUIDでは判別しづらいため) |
第13章 データストア
第13章ではRDB向けデータストアのRDSとインメモリデータストアのElastiCacheを作成します。
作成するデータストアは、それぞれマルチAZに構築するため、第7章 ネットワークで作成したリージョンの異なるプライベートサブネット2つを指定しています。
※プライベートサブネット0
、プライベートサブネット1
はVPC内に作成したサブネットとして見ていただければと思います。(図示が難しかった)
また、図中のカスタマーマスターキー
は第11章 鍵管理で作成済みのリソースを利用するため、この章で追加で作る必要はありません。
作成したRDS用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_db_parameter_group | example | DBパラメータグループ |
resource | aws_db_option_group | example | DBオプショングループ(DBエンジンにオプション機能を追加する。例はMariaDB監査プラグイン) |
resource | aws_db_subnet_group | example | DBサブネットグループ(DBを稼働させるサブネットの定義) |
resource | aws_db_instance | example | DBインスタンス |
module | - | mysql_sg | DBインスタンスのセキュリティグループ |
作成したElastiCache用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_elasticache_parameter_group | example | ElastiCacheパラメータグループ |
resource | aws_elasticache_subnet_group | example | ElastiCacheサブネットグループ |
resource | aws_elasticache_replication_group | example | ElastiCacheレプリケーショングループ(Redisサーバの作成) |
module | - | redis_sg | ElastiCacheレプリケーショングループのセキュリティグループ |
第14章 デプロイメントパイプライン
第14章では継続的にシステムをデプロイするためのデプロイパイプラインをCodePipelineを中心にして作成します。
図中にECRへの矢印(関係性)が見えないと思うかもしれませんが、デプロイメントパイプラインで使われないわけではありません。
ビルドされるアプリケーションコード内にあるbuildspec.yml
にてプッシュ先リポジトリに指定されています。
今回はTerraformプロジェクト内には無いリソースのため、図中へは記載しませんでした。
また、図中のECSサービス
は第9章 コンテナオーケストレーションで作成済みのリソースを利用するため、この章で追加で作る必要はありません。
作成したECR用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_ecr_repository | example | ECRレポジトリ |
resource | aws_ecr_lifecycle_policy | example | ECRライフサイクルポリシー |
作成したS3用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_s3_bucket | artifact | アーティファクトストア用バケット |
作成したCodeBuild用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
data | aws_iam_policy_document | codebuild | CodeBuildサービスロールのポリシードキュメント |
module | - | codebuild_role | CodeBuildサービルロール |
resource | aws_codebuild_project | example | CodeBuildプロジェクト |
作成したCodePipeline用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
data | aws_iam_policy_document | codepipeline | CodePipelineサービスロールのポリシードキュメント |
module | - | codepipeline_role | CodePipelineサービスロール |
resource | aws_codepipeline | example | CodePipeline(例では3つのステージで実装する) |
resource | aws_codepipeline_webhook | example | CodePipeline Webhook |
resource | github_repository_webhook | example | GitHub Webhook(GitHub上でのイベントを検知し、コードの変更を通知するWebhookの定義) |
なお、AWSプロバイダ3.3.0から新規で作る時はOAuthToken
が必須らしく、書籍内の14.10のコードのままだとSourceステージでコケてしまいます。
そのため、github_token
をSSMパラメータとして定義し、それを用いることにしました。
data "aws_ssm_parameter" "github_token" {
name = "/continuous_apply/github_token"
}
# リスト14.10
# CodePipelineの定義(例では3つのステージで実装する)
resource "aws_codepipeline" "example" {
name = "example"
role_arn = module.codepipeline_role.iam_role_arn
# Sourceステージ:GitHubからソースコードを取得する
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "ThirdParty"
provider = "GitHub"
version = 1
output_artifacts = ["Source"]
configuration = {
~中略~
PollForSourceChanges = false
OAuthToken = data.aws_ssm_parameter.github_token.value # SSMパラメータから指定
}
}
}
~後略~
追加したSSM用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_ssm_parameter | github_token | GitHub TokenをSSMパラメータとして定義 |
第15章 SSHレスオペレーション
第15章ではオペレーション用のサーバをSession ManagerとEC2を用いて作成します。
また、オペレーションログとしてSession Managerの操作ログを保存する仕組みを構築します。
オペレーションサーバ自体は第7章 ネットワークでVPC内に作成したプライベートサブネットに作成します。
user_data.sh
はTerraformプロジェクト内に配置されているshファイルですが、EC2インスタンス作成時に実行されるプロビジョニングスクリプトとして指定されています。
追加したEC2用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
data | aws_iam_policy_document | ec2_for_ssm | オペレーションサーバ用ポリシードキュメント |
data | aws_iam_policy | ec2_for_ssm | Session Manager用に定義されているポリシーをベースに利用する |
module | - | ec2_for_ssm_role | オペレーションサーバ用IAMロール |
resource | aws_iam_instance_profile | ec2_for_ssm | インスタンスプロファイル(EC2は直接IAMロールを関連付けられないため、IAMロールをラップしたインスタンスプロファイルを関連付ける) |
resource | aws_instance | example_for_operation | オペレーションサーバ用EC2インスタンス |
追加したS3用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_s3_bucket | operation_instance_id | オペレーションログを保存するS3バケットの定義 |
作成したCloudWatch用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_cloudwatch_log_group | operation | オペレーションログを保存するCloudWatch Logs |
作成したSSM用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_ssm_document | session_manager_run_shell | Session Manager用SSM document |
第16章 ロギング
第16章ではロギングの仕組みを作成します。
ロギングにはCloudWatch Logsが便利であることを書籍では紹介した上で、サンプルプロジェクトではログをKinesis Data Firehoseの配信ストリームを用いてS3に永続化する方法を紹介しています。
作成したS3用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
resource | aws_s3_bucket | cloudwatch_logs | CloudWatch Logs永続化バケット |
作成したKinesis Data Firehose用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
data | aws_iam_policy_document | kinesis_data_firehose | Kinesis Data Firehose IAMロールのポリシードキュメントの定義 |
module | - | kinesis_data_firehose_role | Kinesis Data Firehose用IAMロール |
resource | aws_kinesis_firehose_delivery_stream | example | Kinesis Data Firehose配信ストリーム(Kinesis Data Firehoseにログが流れるとこの配信ストリームに設定したS3バケットへログを保存する) |
作成したCloudWatch用のリソースは下記です。
種別 | リソース種類 | 名前 | 備考 |
---|---|---|---|
data | aws_iam_policy_document | cloudwatch_logs | CloudWatch Logs用IAMロールポリシードキュメント |
module | - | cloudwatch_logs_role | CloudWatch Logs用IAMロール |
resource | aws_cloudwatch_log_subscription_filter | example | CloudWatch Logsサブスクリプションフィルタ |
おわりに
本記事で挙げている図は完全に筆者のイメージで作られています。
そのため、実際のものと異なる可能性が多分にあります。
何かお気づきの点等あればコメント等にてお知らせいただけますと幸いです。
この記事が少しでも参考になっていたら嬉しいです。