Terrafromの自分用メモ
参考
- Terraformバージョンを固定する - Terraformのきほんと応用
- terraformが怖くて震えていたかつての自分に捧ぐInfrastructure as Code入門(AWS)
- Backend Configuration
- Backend Type: s3 | Terraform
- Module Blocks
- Data Sources
主なワークフロー
- Initialize
- Terraforを実行するための、作業ディレクトリを準備する
- initコマンドでTerraformやプロバイダのバージョンをアップグレードもできる
- Plan
- 変更を適用する前にプレビューする
- 実環境に反映されることはない
- Terraformの設定と現状のリソースを照合する
- 特定のリソースをターゲットにすることも可能
- 状態ファイルと実際の構成を照合することも可能
- 変更を適用する前にプレビューする
- Apply
- Terraform の設定によって定義された変更を実行し、リソースを作成、更新、破棄する
- 部分的に完了した適用はロールバックされない
- 適用中にエラーになった場合、機能しない構成になっている可能性がある
主なファイル
Initialize
versions.tf
- Terrafrom本体等のバージョンを制限する
- 複数人開発時のバージョン差異によるリスクを低減できる
- バージョンは「MAJOR.MINOR.PATCH」と表現される
- 例えばマイナーバージョンが上がった場合、
パッチはそのマイナーバージョンアップに含まれることになる
- 例えばマイナーバージョンが上がった場合、
- バージョン表記は以下
- 0.15.0:v0.15.0のみ許容する
- >= 0.15:v0.15以上(v1.0.0含めて)を許容する
- ~> 0.15.0:0.15.Xは許容する
- マイナーおよびメジャーバージョンアップはしないがパッチは適用したい場合
- >= 0.15, < 2.0.0:v0.15.0以上、v2.0.0未満を許容する
例
terraform {
required_version = ">= 1.0.8" # Terrafromのバージョン
required_providers {
aws = {
source = "hashicorp/aws" # 利用するプロバイダを指定
version = "3.63.0" # プロバイダのバージョン
}
}
}
.terraform.lock.hcl
- プロバイダバージョンを指定するファイル
- 本ファイルが存在しない場合、versions.tfからプロバイダのバージョンを決定する
- versions.tfに記述がなく、本ファイルも存在しない場合は
最新のバージョンがダウンロードされる
例
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "3.63.0"
constraints = "3.63.0"
hashes = [
"h1:FyU8TUgpwfu+O+k+Uu58I/JWlEZk2PzQLJMluuaIQ=",
## ...
"zh:fd634e973eb2b6483a1ce92518093d04cb496f8e83ffcf3f0c4cad8c18f4c",
]
}
.terraform
- プロジェクトのプロバイダーとモジュールを格納するディレクトリ
- plan, applyを実行するときに、これらのコンポーネントは参照される
- 直接変更しないこと
例
$ tree .terraform/providers
.terraform/providers
└── registry.terraform.io
└── hashicorp
└── aws
└── 3.63.0
└── linux_amd64
└── terraform-provider-aws_v3.63.0_x5
5 directories, 1 file
variables.tf
- 変数の設定ファイル
- 変数の宣言はどこでも問題ないが、通例としてvariables.tfに記述する
使い方例
- 起動するインスタンス数を環境ごとに変える
- IPアドレスレンジが環境ごとに被らないようにする
- タグ付けを環境ごとに分ける
- apply時に変数に任意の値を入力する
- terraform.tfvarsに入力が必要な値をまとめて定義、読み込ませることも可能
Apply
outputs.tf
- 出力の設定ファイル
- 出力の宣言はどこでも問題ないが、通例としてoutputs.tfに記述する
- 別のTerraformワークスペースのデータソースとして利用する
output "aws_instance_tfer--i-bb85f7df195ffc5_aws-cloud9-bb85f356b29a1f096d8267_id" {
value = aws_instance.tfer--i-bb85f7df195ffc5_aws-cloud9-bb85f356b29a1f096d8267.id
}
output "aws_instance_tfer--i-d58229a1f09b18_bluegreen_id" {
value = aws_instance.tfer--i-d5829a1f0923b18_bluegreen.id
}
terraform.tfstate
- インフラに関する情報を状態を格納するファイル
- apply時に生成されるファイル
- 状態ファイルに書き込み後、実体のリソースが更新される
- 設定によって作成されたリソースを追跡し、実体のリソースにマッピングする
- 直接変更しないこと
- plan時はtfファイルとterraform.tfstateが比較され、差分が表示される
- 実環境と比較していないので、実環境とterraform.tfstateに差分があるのはNG
変数
- 入力変数
- 関数の引数のようなもの
- 手を加えずにモジュールを別環境で共有できるようになる
- 出力変数
- 関数の戻り値のようなもの
- インフラに関する情報をコマンドラインから利用できる
- 他のTerraform構成が利用できるようにできる
- ローカル変数
- 関数の一時的なローカル変数のようなもの
- 関連するローカル値のセットは、1つのローカルブロックにまとめて宣言できる
- 一箇所で簡単に値を変更できることが主な利点
- 多くの場所で使用されるが、その値が将来変更される可能性がある場合に使用する
- 実際に使われている値を隠してしまうので使いすぎは注意
入力変数
定義例
variable "image_id" {
type = string
}
variable "availability_zone_names" {
type = list(string)
default = ["us-west-1a"]
}
variable "docker_ports" {
type = list(object({
internal = number
external = number
protocol = string
}))
default = [
{
internal = 8300
external = 8300
protocol = "tcp"
}
]
}
各項目
variable
- 同じモジュール内のすべての変数の中で一意の値
default
- デフォルト値が存在する場合、変数はオプションとみなされる
- 値が設定されていない場合、デフォルト値が使用される
- リテラル値であること
- 設定内の他のオブジェクトを参照することはできない
type
- 変数の値の型宣言
- ない場合は、どのような型の値でも許容する
- 宣言することで間違った型が使われた場合、エラーメッセージが返る
description
- 各変数の目的を簡単に説明できる
- 説明文は、その変数の目的と、どのような値が期待されるかを簡潔に説明する
- モジュールを使う人の視点で書かれるべきもの
- モジュールをメンテする人に対する解説はコメントアウトを使う
validation
- 特定の変数に対するカスタム検証ルールを指定することができる
sensitive
- 計画や適用の出力にその値を表示するのを防ぐ
- エラー出力等では表示される場合もあるので注意
nullable
- 変数に null 値を代入してよいかどうかを制御
- デフォルト値はtrue
- trueの場合、変数値がnullであることを常に考慮する必要がある
- trueの場合、入力引数としてNULLを渡すと、デフォルト値が上書きされる
- falseかつデフォルト値がある場合、入力引数がNULLのとき、デフォルト値が使用される
利用方法
- var.で利用する
- 環境変数を設定し、利用する
- 変数のロード順序は以下、後勝ち
- 環境変数
- terraform.tfvars
- terraform.tfvars.json
- *.auto.tfvars または *.auto.tfvars.json
- コマンドラインのオプション
- 記載順に処理される
環境変数
- TF_VAR_の後に宣言された変数名をつけた環境変数が読み込まれる
- Terraformを自動化やTerraformコマンド実行時に便利
- 大文字小文字は区別される
設定例
$ export TF_VAR_image_id=ami-abc123
$ terraform plan
...
変数定義ファイル
- terraform.tfvarsまたはterraform.tfvars.jsonという名前で作成される
- キーバリューのみ記述する
- 定義された変数の値が変数定義ファイルにない場合、エラーにはならない
- 定義されていない変数の値が変数定義ファイルにある場合、エラーになる
設定例
terraform.tfvars
image_id = "ami-abc123"
availability_zone_names = [
"us-east-1a",
"us-west-1c",
]
terraform.tfvars.json
{
"image_id": "ami-abc123",
"availability_zone_names": ["us-west-1a", "us-west-1c"]
}
コマンドライン
- plan、apply時に-varオプションとして利用する
- 環境ごとに値を使い分けるとき便利
- 変数定義ファイルを作成し、plan、apply時に-var-fileオプションとして利用する
設定例
terraform apply -var="image_id=ami-abc123"
terraform apply -var='image_id_list=["ami-abc123","ami-def456"]' -var="instance_type=t2.micro"
terraform apply -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}'
terraform apply -var-file="testing.tfvars"
使い方例
resource "aws_instance" "example" {
instance_type = "t2.micro"
ami = var.image_id
}
出力変数
例
output "instance_ip_addr" {
value = aws_instance.server.private_ip
}
ローカル変数
記載例
locals {
# Ids for multiple sets of EC2 instances, merged together
instance_ids = concat(aws_instance.blue.*.id, aws_instance.green.*.id)
}
locals {
# Common tags to be assigned to all resources
common_tags = {
Service = local.service_name
Owner = local.owner
}
}
利用例
resource "aws_instance" "example" {
# ...
tags = local.common_tags
}
backend
- Terraformが状態データファイルを保存する場所のこと
例
terraform {
backend "s3" {
bucket = "mybucket"
key = "path/to/my/key"
region = "us-east-1"
}
}
module
- Terraformでは少なくともルートモジュールが1つある
- モジュールは他のモジュールを呼び出すことができる
モジュールの呼び出しかた
module "servers" {
source = "子モジュールへの相対パス"
xxx = "子モジュールで定義されている変数の値"
}
data source
- Terraformの外部で定義された情報を利用する
- AWSのdata sourceを調べられる
例
# Find the latest available AMI that is tagged with Component = web
data "aws_ami" "web" {
filter {
name = "state"
values = ["available"]
}
filter {
name = "tag:Component"
values = ["web"]
}
most_recent = true
}
resource "aws_instance" "web" {
ami = data.aws_ami.web.id
instance_type = "t1.micro"
}
感想
- アプリエンジニアは変数の持ち方など、知見を活かせられそう