インフラ自動化ツールの一つである「Terraform」について、これから学ぼうという方、使っていきたい方を対象に、Terraformの導入方法や基本的な使い方を紹介していく本連載。最終回は、Terraformでクラウドリソースを効率的に管理するモジュールについて。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
インフラ自動化ツールの一つである「Terraform」について、Terraformの導入方法や基本的な使い方を紹介していく本連載。本連載で紹介してきた内容を知っておくことで、Terraformを使ってクラウドリソースを管理することは十分に可能です。最終回となる今回は、Terraformの「モジュール」について解説します。
モジュールが何者なのか、ある程度想像がつく人もいるかと思いますが、簡単に言えばリソースの集合体です。Amazon Web Services(AWS)の「Amazon Elastic Compute Cloud(Amazon EC2)」のインスタンス(以下、EC2インスタンス)を作成する場合、EC2インスタンスを用意するだけではなく、目的に応じたセキュリティグループを作成したり、インスタンスプロファイルを作成したりするでしょう。
これをTerraformコードで表現する場合、EC2インスタンスリソースと、セキュリティグループリソースと、「AWS Identity and Access Management(AWS IAM)」ロール(以下、IAMロール)リソースを作成する必要があります。用途別にリソースを記述する場合、次のように、リソースブロックを複数記述することになります。
resource "aws_instance" "webserver" { # Web サーバ用 EC2 インスタンスの内容 } resource "aws_security_group" "webserver" { # Web サーバ用セキュリティグループの内容 } resource "aws_iam_role" "webserver" { # Web サーバ用インスタンスロールの内容 } resource "aws_iam_instance_profile" "webserver" { # Web サーバ用インスタンスプロファイルの内容 } resource "aws_instance" "dbserver" { # データベースサーバ用 EC2 インスタンスの内容 } resource "aws_security_group" "dbserver" { # データベースサーバ用セキュリティグループの内容 } resource "aws_iam_role" "dbserver" { # データベースサーバ用インスタンスロールの内容 } resource "aws_iam_instance_profile" "dbserver" { # データベースサーバ用インスタンスプロファイルの内容 } ……以下、目的別に同じような内容が続く。
これに対し、モジュールが使えると次のような内容になります。目的別に分かりやすい表記となり、視認性がかなり上がっていることが分かるでしょう。
module "webserver" { # Web サーバ用の各リソース設定 } module "dbserver" { # データベースサーバ用の各リソース設定 }
このように、同じようなリソースを1つにまとめようとするのが、モジュールの概念です。
では、早速、モジュールを作ってみましょう。前述の例をそのままモジュールとして表現するとして、まずはモジュール用のディレクトリを作成します。その中に、main.tfとvariables.tfという2つのファイルを作成します。今回は「example-module」という名前でディレクトリを作成するとして、以下のようなディレクトリ構造にしました。
terraform/ ├ main.tf └ example-module/ ├ main.tf └ variables.tf
次に、モジュールを構成するリソースを定義します。example-module/main.tfの中に、前述の例のようにリソースを定義していきます。各リソースの名前は、モジュールの呼び出し側で設定できるように変数を利用します。
resource "aws_instance" "this" { ami = "ami-0dfa284c9d7b2adad" instance_type = "t2.micro" iam_instance_profile = aws_iam_instance_profile.this.id vpc_security_group_ids = [aws_security_group.this.id] tags = { Name = var.name } } resource "aws_security_group" "this" { name = var.name } resource "aws_iam_role" "this" { name = var.name assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Sid = "" Principal = { Service = "ec2.amazonaws.com" } } ] }) } resource "aws_iam_instance_profile" "this" { name = var.name role = aws_iam_role.this.name }
次に、変数を定義します。前述のTerraformコードでnameという変数を使用しているので、この変数を定義します。
variable "name" { type = string nullable = false }
これでモジュールを作成できました。さて、気付いた人もいるかもしれませんが、モジュールとして書いた内容は、今まで書いてきたTerraformコードとほとんど変わりません。実は、これまで書いてきたTerraformコードも「ルートモジュール」というモジュールの一つだったのです。ディレクトリを分けてTerraformコードを記述することで、モジュールという単位で内容を書き分けられますし、モジュールを再利用できます。
では、ルートモジュール(前述のディレクトリ構造におけるterraformディレクトリ直下のTerraformコード)から、先ほど作成したモジュールを呼び出して、2つのリソース群を作ってみましょう。ルートモジュールのmain.tfに、以下の内容を記述します。
module "webserver" { source = "./example-module" name = "webserver" } module "dbserver" { source = "./example-module" name = "dbserver" }
モジュールの呼び出し側がTerraformコードとして設定する内容は非常に少なく、モジュールのTerraformコードが存在する場所を指定するsourceパラメーターと、モジュールに渡す変数の内容をパラメーターとして記述しているだけです。
最後に、リソースを作成してみましょう。これまで通り、terraform planコマンドで実行内容に問題がないかどうかを確認した後、terraform applyコマンドを実行してリソースを作成します。なお、今回のようにmoduleブロックを追加した場合は、初回のみterraform initコマンドの実行が必要です。
※初回だけ必要 $ terraform init (中略) $ terraform apply (中略) Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes module.dbserver.aws_iam_role.this: Creating... module.dbserver.aws_security_group.this: Creating... module.webserver.aws_iam_role.this: Creating... module.webserver.aws_security_group.this: Creating... module.webserver.aws_iam_role.this: Creation complete after 1s [id=webserver] module.dbserver.aws_iam_role.this: Creation complete after 1s [id=dbserver] module.webserver.aws_iam_instance_profile.this: Creating... module.dbserver.aws_iam_instance_profile.this: Creating... module.webserver.aws_security_group.this: Creation complete after 1s [id=sg-xxxxxxxxxxxxxxxxx] module.dbserver.aws_security_group.this: Creation complete after 1s [id=sg-xxxxxxxxxxxxxxxxx] module.dbserver.aws_iam_instance_profile.this: Creation complete after 1s [id=dbserver] module.webserver.aws_iam_instance_profile.this: Creation complete after 1s [id=webserver] module.dbserver.aws_instance.this: Creating... module.webserver.aws_instance.this: Creating... module.dbserver.aws_instance.this: Still creating... [10s elapsed] module.webserver.aws_instance.this: Still creating... [10s elapsed] module.dbserver.aws_instance.this: Still creating... [20s elapsed] module.webserver.aws_instance.this: Still creating... [20s elapsed] module.dbserver.aws_instance.this: Creation complete after 27s [id=i-xxxxxxxxxxxxxxxxx] module.webserver.aws_instance.this: Still creating... [30s elapsed] module.webserver.aws_instance.this: Creation complete after 31s [id=i-xxxxxxxxxxxxxxxxx] Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
実行結果を見てみると、それぞれのモジュール内でどのようなリソースが作成されたかが分かります。モジュールを使えるようになるとTerraformコードの視認性が上がり、メンテナンスも容易になります。
前述のように自分自身でモジュールを作成するのもよいですが、有志が作成、公開している既存のモジュールを使用できます。そのようなモジュールは「Terraform Registry」で公開されています。かなりたくさんのモジュールが公開されていますが、ここではAWS向けに作成されたモジュールの一例を紹介します。
モジュール名 | 概要 |
---|---|
terraform-aws-modules/ec2-instance | Amazon EC2に関するモジュール |
terraform-aws-modules/iam | AWS IAMに関するモジュール |
terraform-aws-modules/s3-bucket | Amazon Simple Storage Service(Amazon S3)のS3バケットに関するモジュール |
terraform-aws-modules/route53 | Amazon Route 53に関するモジュール |
terraform-aws-modules/security-group | Amazon Virtual Private Cloud(Amazon VPC)のセキュリティグループに関するモジュール |
AWS向けに作成されたTerraformモジュールの例 |
全9回にわたってTerraformの入門からTerraformを利用してAWSリソースを管理する実践的な内容まで紹介してきました。インフラリソースをコードで管理するメリットが読者の皆さまに少しでも認識いただけたのなら幸いです。
業務の自動化はミスを減らすのみならず、業務を効率的に進めることができる上に、QoL(生活の質)を上げられる可能性も十分に秘めています。まだTerraformを利用されていない人は、本連載を参考にしてTerraformに触れていただき、ぜひ活用してみてください。
サイオステクノロジー所属。OSS よろず相談室でサポート対応をしているテクニカルサポートエンジニア。Ansibleに出会ってから自動化に取りつかれ、自身の業務やプライベートであらゆるものの自動化に取り組む。プライベートではJavaでちょっとしたツールの開発を趣味にしている。
Copyright © ITmedia, Inc. All Rights Reserved.