今回は、記述言語であるHCL2の基礎と、Terraformファイルの概要についてアウトプットしていきます。環境構築等は前回のコラムを参照してください。
HCL2
HCL2(HashiCorp Language 2)言語とは
HCL(HashiCorp Configuration Language)2は、HashiCorpによって開発された設定言語の第二世代です。Terraformや他のHashiCorp製品で広く使用されている言語で、インフラストラクチャーの設定や管理を宣言的に記述するために設計されています。
<HCL2 例>
# ------------------------ # VPC # ------------------------ resource "aws_vpc" "vpc" { cidr_block = "192.168.0.0/20" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true assign_generated_ipv6_cidr_block = false # Tagづけ tags = { Name = "${var.project}-${var.environment}-vpc" Project = var.project Env = var.environment }
ブロック構造で記述されているため、パッと見はJSONに少し似ていますが、途中で # によるコメントを差し込めたりするなど、独自の構文となっています。
データ型
HCL2では、次のデータ型が使用できます。
データ型 | 概要 |
---|---|
string | 文字列を表します。 |
number | 数値を表します。 |
bool | 真偽値(true/false)を表します。 |
list | 配列やリストを表します。 |
map | キーと値のペアのマップを表します。 |
object | オブジェクトや構造体を表します。 |
tuple | 固定長の要素を持つタプルを表します。 |
set | 一意な値のセットを表します。 |
Terraformファイル
Terraformの管理ファイルには、主に以下のファイルが存在します。
- *.tfファイル:インフラリソース等の定義ファイル。ファイル内容はresource、data等、いくつかのブロックに分けて記述する(後述)
- terraform.tfvars:変数定義ファイル。Terraform全体で使用する変数を定義する。ファイル名は固定。
- terraform.tfstate:Terraformで生成されたリソースの状態管理ファイル。Terraform Applyによって固定のファイル名で自動生成される。
ディレクトリ構造については、現在も多くの議論が交わされているようですが、tfファイルはリソースごとに分離することは共通しているようです。
上記のうち、tfファイルについてご説明します。ファイル内容は、HCL2のテキスト形式で記述し、いくつかのブロックに分けて作成します。
ブロックタイプ
tfファイルは、ブロック
と呼ばれる次の記述に分かれています。
ブロックタイプ | 概要 |
---|---|
locals | 変数。外部から参照できないもの |
variable | 変数。外部から参照できるもの |
terraform | Terraformの設定 |
provider | プロバイダ |
data | Terraform管理していないリソースの取り込み |
resource | Terraformの管理対象となるリソース |
outputs | 外部から参照できるようにする値 |
ブロック詳細
locals
locals
は、tfファイル内で使用するローカル変数を定義するものです。
# localsブロックで変数をKey = valueで定義する locals { env = "dev" } resource "aws_instance" "hello-world" { ami = "ami-04e0b6d6cfa432943" instance_type = "t2.micro" # 変数は ${local.変数名}で使用する tags = { Name = "HelloWorld" Env = "test-ec2-${local.env}" } }
variables
variables
は、locals
と同様、変数を定義します。
定義した変数は、ファイルの外部から参照できます。
# 変数ごとにvariableブロックで変数を定義する # type にデータ型を指定する variable "env" { type = string default = "stg" } resource "aws_instance" "hello-world" { ami = "ami-04e0b6d6cfa432943" instance_type = "t2.micro" # 変数は ${var.変数名}で使用する tags = { Name = "HelloWorld" Env = "test-ec2-${var.env}" } }
上記で使用するデータ型には、以下のものが存在します。
- プリミティブ型
- string:Unicode文字列
- number:数値。整数と小数の両方を表現。
- bool:true/falseの2値
- 構造体
- object({<NAME=
, ...}):キーバリュー型データ - tuple([<TYPE], ...):各列の型が決まっている配列
- object({<NAME=
- コレクション
- list([TYPE]):特定の型で構成される配列
- map([TYPE]):キーが文字列の配列
- set([TYPE]):値の重複がない配列
変数 variables
は、以下に示すいくつかの方法で値を書き換えることができます。
OS環境変数で値を設定する。
変数ファイル
terraform.tfvars
で値を設定する。terraform.tfvars
(ファイル名固定)を定義し、その中で値を設定します。terraform.tfvars
env = "debug"
terraformコマンドの引数
-var
、-var-file [ファイル名]
で値を設定するterraform apply
コマンドの引数として値を設定します。実行コマンド
$ terraform apply -var env="test"
terraform
terraform
ブロックは、terraform自体の設定に関する値を指定します。代表的な例としては、required_version
でterraformの動作バージョン等を指定します。
# このtfファイルでは、terraform 1.8.2 以上のバージョンで動作することを定義 terraform { required_version = "~>1.8.2" }
また、Terraformのリソース状態を管理するファイルである .tfstate
ファイルを管理する場所を指定する場合は、backend
をこちらに記述します。
# backendブロックで、tfstateをS3上に保存するよう指示 terraform { backend "s3" { bucket = "tfstate-bucket-camelrush" key = "dev.tfstate" region = "ap-northeast-1" profile = "terraform" } }
provider
provider
には、Terraformで使用するプロバイダを指定します。ここには、Terraformが対応しているプロバイダリストの中から選択して指定します。今回はaws
ですが、azure
やgoogle
のほか、Oracle Cloudといった多くのプロバイダが公開されています。詳細は以下をご確認ください。
なお、awsプロバイダに指定できるパラメタはこちらを参照ください。
最低限の記述としては、AWSへのアクセス情報を設定します。
# ----------------------------- # Provider # ----------------------------- provider "aws" { profile = "terraform" region = "ap-northeast-1" }
access_key
やsecret_key
を指定する方法もありますが、セキュリティ上は非推奨であり、tfファイル管理もしづらくなりますので、ここはprofile
を指定しましょう。
別途、AWS CLIのaws configure -profile xxxxx
(xxxxxをprofile名と一致させる)を実行して、ローカルプロファイル名(上記の場合は terraform
)にアクセスキー等を設定しておきます。
data
data
ブロックは、少し特殊な使い方をします。こちらには、Terraform管理外のリソースを、tfファイル等で使用するためのデータ・リストとして取り込む役割があります。
管理外
とは、具体的にはAWSプロバイダが提供するID情報などが挙げられます。
以下では、EC2インスタンスを作成するために使用するAMI(PCのイメージ)のIDを指定するため、AWSが提供するAMIのリストから、希望する「Amazon Linux2の最新イメージ」をdata
として取得し、それを元にEC2を作成しています。
# --- data block --- data "aws_ami" "app" { most_recent = true owners = ["self", "amazon"] # filter.valuesに*を入れて複数をピックアップしたリストを取得 # 前述の`most_recent=true`でリストから最新を取得 filter { name = "name" values = ["amzn2-ami-kernel-5.10-hvm-2.0.*.0-x86_64-gp2"] } } # --- resource block --- resource "aws_instance" "app_server" { # amiには、前述で定義したdataブロックのAMIのIDを指定 ami = data.aws_ami.app.id # 以下、省略 : : }
dataブロックに使用できる項目は、リファレンスの各サービス下にData Sources
として書かれていますので、参照してください。
resource
resource
ブロックには、Terraformで作成する各種サービスリソースを定義します。以下の様に記述します。
resource <リソース種類> <リソース名> { <各種パラメタ> }
以下に例を記述します。
# ------------------------ # VPC # ------------------------ resource "aws_vpc" "vpc" { cidr_block = "192.168.0.0/20" instance_tenancy = "default" enable_dns_support = true enable_dns_hostnames = true assign_generated_ipv6_cidr_block = false } # ------------------------ # Subnet # ------------------------ resource "aws_subnet" "public_subnet_1a" { vpc_id = aws_vpc.vpc.id availability_zone = "ap-northeast-1a" cidr_block = "192.168.1.0/24" map_public_ip_on_launch = true }
作成できるAWSリソースと、リソース種類別のパラメタについては、こちらのドキュメントを参照してください。
output
output
は、Terraformの設定間での明示的なデータ共有、状態の可視化、および外部ツールとの統合を容易にするために使用します。
<ec2.tf>
resource "aws_instance" "app_server" { ami = data.aws_ami.app.id : } # 自動で割り当てられたパブリックIPアドレスを出力 output "public_ip" { value = aws_instance.app_server.public_ip }
上記のように定義することで、Terraformコマンドを行ったオペレータに対して、「状態が可視化」されます。
<terraform apply コマンド>
$ irohani-mba:terraform shinya.takada$ terraform apply -auto-approve random_string.db_password: Refreshing state... [id=gKCzffFsy6bmZDQl] aws_db_option_group.mysql_standalone_optiongroup: Refreshing state... [id=tastylog-dev-mysql-standalone-optiongroup] data.aws_prefix_list.s3_pl: Reading... : : Apply complete! Resources: 0 added, 0 changed, 0 destroyed. Outputs: public_ip = "54.249.38.103"
outputはリソース作成自体には、影響を与えません。Terraformは、実行フォルダ配下のtfファイルを全て参照して依存関係を見つけるため、outputを記述しなくても、エラーにはなりません。
外部ツールとの統合では、CI/CDツールとの連携などにも活用されます。
Terraformのファイル構成
Terraformプロジェクトでは、いくつかの主要なファイルとディレクトリが使用されます。これらのファイルは、インフラストラクチャをコードとして管理する際に重要な役割を果たします。以下に、一般的なTerraformプロジェクトのファイル構成の例と、それぞれのファイルの役割を説明します。
一般的なディレクトリ構成
my-terraform-project/
├ main.tf
├ variables.tf
├ outputs.tf
├ terraform.tfvars
├ terraform.tfstate
├ terraform.tfstate.backup
├ .terraform/
├ modules/
└ example_module/
├ main.tf
├ variables.tf
└ outputs.tf
ファイルの説明
main.tf
- Terraformの主要な設定ファイルで、リソースの定義やプロバイダーの設定が含まれます。
variables.tf
- 変数の定義ファイルです。Terraformで使用する変数をここで宣言します。
outputs.tf
- 出力値を定義するファイルです。Terraformが生成する値を他の場所で参照できるようにします。
terraform.tfvars
- 変数の値を設定するファイルです。環境ごとに異なる設定を行う場合に使用します。
terraform.tfstate
- Terraformの状態ファイルで、インフラストラクチャの現在の状態が記録されます。このファイルはTerraformによって自動的に管理されます。
terraform.tfstate.backup
- 状態ファイルのバックアップです。変更を行う前の状態が保存されます。
.terraform/
modules/
- モジュールを保存するディレクトリです。再利用可能なTerraformコードをモジュールとしてまとめます。
モジュールの説明
モジュールは、Terraformのコードを再利用可能な単位にまとめたもので、プロジェクト全体の構造を整理しやすくします。例えば、上記の例では example_module
というモジュールがあり、以下のファイルが含まれます。
modules/example_module/main.tf
- モジュール内の主要な設定ファイルです。
modules/example_module/variables.tf
- モジュール内で使用する変数を定義します。
modules/example_module/outputs.tf
- モジュールの出力値を定義します。
このようなファイル構成を採用することで、Terraformプロジェクトを整理しやすくし、再利用性を高めることができます。
まとめ
少し長くなってしまいましたので、一旦解説はこの辺にして、次回は、terraformを使用したEC2ネットワークの構成を作っていきます。