- 概要
- Terraformバージョン
- プロバイダーのバージョン制約・指定
- Variable
- Localについて
- Countについて
- Dynamicブロックについて
- for_eachについて
- Provisionerについて
- Dataについて
- Moduleについて
- Workspaceについて
- チームコラボレーション
- マルチリージョン
- Logについて
- リソース間の依存関係
- フォルダ構成
- リソースが大規模な場合
- セキュリティ上の注意点
- Terraformコマンド
- Terraform Cloudについて
- Terraform Vaultについて
- 用語
- コメントアウトについて
- 関数
- Terraformがサポートしている言語
概要
Udemyで受講した「HashiCorp Certified: Terraform Associate 2022」のメモ。
すごいわかりやすいので、Terraform初心者の方はUdemyで視聴してみると良いと思います。
Terraformバージョン
初めてTerraformをローカルPCで実行させるようとしたとき、Windows PCではTerraformのウェブサイトからバイナリ実行ファイル(terraform.exe)をダウンロードしてくる。ウェブサイトでは、最新の安定バージョンと2~3世代前のバージョンがダウンロードできる。
それよりも前のバージョンはGithubからダウンロードできる。
Terraformバージョンの指定
terraformブロック内で、terraform.exeのバージョンを指定することができる。
terraform { required_version = "> 1.1.0" }
バージョンの指定に利用できる記号はこちらの通り。
もし実行するterraform.exeのバージョンが指定した条件を満たさない場合はUnsupported Terraform Core versionエラー
を返す。
プロバイダーのバージョン制約・指定
AWSやAzure、GCPといったパブリッククラウド毎(プロバイダーと呼ぶ)に、プラグインをダウンロードしてくる。 AWS上にプロビジョニングする場合には、AWSのプロバイダを指定する。
ちなみにProviderブロックは必須なわけではないことに注意。Providerを利用する場合でもProviderブロックを定義しなくて大丈夫。TerraformはProviderブロックが空とみなして、プラグインを取得する。ただ、ベストプラクティスとして、Providerを利用する場合は明示的にProviderブロックを設定すべき。
Terraform assumes an empty default configuration for any provider that is not explicitly configured.
Provider Configuration - Configuration Language | Terraform by HashiCorp
terraform { required_version = "> 1.1.0" } provider "aws" { region = "us-east-1" }
プロバイダーのバージョン制約をterraformブロック内にrequired_providers
として記載することができる。
また、providerブロック内にダウンロードしてくるプロバイダーのバージョンをversion
として指定できる。
terraformブロック
required_version
:terraform.exeのバージョン制約required_providers
:プロバイダーのバージョン制約
providerブロック
version
:プロバイダーのバージョン指定
terraform { required_version = "> 1.1.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 2.0" } } } provider "aws" { region = "us-east-1" version = ">=2.10,<=2.30" }
もし、実行するプロバイダープラグインのバージョンが指定した条件を満たさない場合には、Failed to query available provider packagesエラー
を返す。
注意
Terraform 0.13以降、providerブロック内のversion引数は非推奨となった。
The version argument in provider configurations is deprecated. In Terraform 0.13 and later, always declare provider version constraints in the required_providers block. The version argument will be removed in a future version of Terraform.
.terraform.lock.hcl ファイル
terraform init
コマンドでプロバイダープラグインがダウンロードされる。一度プラグインがダウンロードされると.terraform.lock.hcl
ファイルでプロバイダープラグインのバージョンがロックされる。プラグインのバージョンを変更したい場合には、.terraform.lock.hcl
ファイルを削除する必要がある。
# This file is maintained automatically by "terraform init". # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { version = "2.30.0" constraints = "~> 2.0, >= 2.10.0, <= 2.30.0" hashes = [ "h1:fSYy...", ..., ..., ] }
Terraformバージョン毎の違い
Terraform v0.13の前後で大きな違いがある。
Terraform v0.13以降
Hashicorpが管理しているプロバイダーについては、required_providersブロックは必須ではないが、required_providersブロックを書くのが推奨される
terraform { required_providers { github = { source = "integrations/github" version = "4.3.2" } } } provider "github" { token = "8c6f0e838e998844a8bb32b0050a7dee6a31a4df" }
Terraform v0.12以前
required_providersブロックは記載しない
provider "github" { token = "8c6f0e838e998844a8bb32b0050a7dee6a31a4df" }
AWSプロバイダの認証設定
AWS Providerの場合、認証方法にはいろんな方法がある。
- Parameters in the provider configuration
- Environment variables
- Shared credentials files
- Shared configuration files
- Container credentials
- Instance profile credentials and region
providerブロック内にクレデンシャルを記述する場合は次のようになる、
provider "aws" { region = "us-west-2" access_key = "my-access-key" secret_key = "my-secret-key" }
Variable
.tf
コード内に変数を定義できる。
必須ではないが型制約は記述すること。変数に型制約を設けることで、誤ったデータ型の値を代入してしまうという
ミスを防げる。
descriptionも記述すること。
variable "instance_name" { description = "Value of the Name tag for the EC2 instance" type = string default = "AppServerInstance" }
データ型
データ型には次の種類がある。
- string
- number
- bool
- list
- map
- set
- object
- tuple
Terraformでは、number型とbool型は自動的にstring型に変換される。 string型からnumber型、bool型にも自動で変換される。
- number/bool ⇔ string
Variableへの代入
こちらの通り、変数の代入方法は次の5つの方法がある。
本番環境ではterraform.tfvars
ファイルに変数値を設定するのがベストらしい。
- Terraform Cloud workspace (口述)
- -var command line option
terraform apply -var="image_id=ami-abc123"
という形式で指定して実行する
- Variable definitions (.tfvars) files
- デフォルトでは
terraform.tfvars
を探して読み込む。カスタムファイル名を利用したい場合はterraform apply -var-file="custom_name.tfvars"
とファイル名を指定して実行する
- デフォルトでは
- Environment variables
- 環境変数として設定しておく。
export TF_VAR_image_id='ami-abc123'
- Variable Defaults
json variable "image_id" { default = "ami-abc123" }
変数の読込み優先順位
次の優先順位で変数が読み込まれる。
同じ変数に複数回値が代入される場合には、最後に読み込んだ値で上書きされる。
- Environment variables
- The terraform.tfvars file, if present.
- The terraform.tfvars.json file, if present.
- Any .auto.tfvars or .auto.tfvars.json files, processed in lexical order of their filenames.
- Any -var and -var-file options on the command line, in the order they are provided. (This includes variables set by a Terraform Cloud workspace.)
Localについて
localを利用しすぎると可読性が低くなり、メンテナンス性も下がるので、利用しすぎには要注意。
locals { ami = "ami-a1b2c3d4" instance_type = "t2.micro" } resource "aws_instance" "server" { ami = local.ami instance_type = local.instance_type }
Countについて
リソースの単純な複製
resourceブロック内で、count = 3
とすると単純に同じリソースが3つ作られる。
resource "aws_instance" "server" { count = 3 ami = "ami-a1b2c3d4" instance_type = "t2.micro" }
ListとCountを組み合わせた利用法
count.index
とリスト型の変数を組み合わせることで、異なる名称でリソースを複製することができる。
variable "name" { default = ["dev", "stg", "prd"] } resource "aws_iam_user" "lb"{ count = length(var.name) name = var.name[count.index] }
参考演算子とCountを組み合わせた利用法
countと三項演算子を組み合わせることでリソースを生成するかどうかの判定を実現する。 以下により、変数がtrueであればリソースを生成し、falseであれば生成しない。
variable creation { type = bool default = true } resource "aws_instance" "server" { count = var.creation == true ? 1 : 0 ami = "ami-a1b2c3d4" instance_type = "t2.micro" }
三項演算子とは
<条件式> ? <条件が真の場合の値> : <条件が偽の場合の値>
Dynamicブロックについて
dynamicブロックにより、ブロックを動的に複製することができる。
for_eachにリスト型の変数をセットし、<dynamicブロック名>.valueでリスト型変数の値を取得してブロックを複製する。
variable "sg_ports" { type = list(number) description = "list of ingress ports" default = [8200, 8201,8300, 9200, 9500] } resource "aws_security_group" "dynamicsg" { name = "dynamic-sg" description = "Ingress for Vault" dynamic "ingress" { for_each = var.sg_ports iterator = port content { from_port = port.value to_port = port.value protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } }
for_eachについて
countでArgument Valueが異なるリソースを複数作成しようとした場合、元となるリストの要素順序が変更されると影響がでてしまう可能性がある。そうした場合にはfor_each
を使う。
同じものを複製するなら、countを利用する。Argument Value一部でも異なる場合には、for_eachを利用する。
for_eachとtosetを組み合わせることで、インデックスと要素を同じ値にすることができる。 for_eachに集合のkeyだけを格納できる。その場合、each.keyでkey値を取り出すことができる。
resource "aws_iam_user" "iam" { for_each = toset( ["user-01","user-02", "user-03"] ) name = each.key }
for_eachにmap型を格納することで、keyだけでなくvalueも格納できる。key値はeach.key
で取り出す。value値はeach.value
で取り出す。for_eachにmap型を格納した場合も、リソースを複数生成できる。
resource "aws_instance" "myec2" { ami = "ami-0cea098ed2ac54925" for_each = { small = "t2.micro" normal = "t2.medium" } instance_type = each.value key_name = each.key tags = { Name = each.key } }
Provisionerについて
remote-exec、local-execといった、色んな種類のprovisionerが存在する。
Provisionerは最後の手段。一般的にそれ以外に良い方法がある。
remote-exec
リソース作成後にリモートリソース側でスクリプトを呼び出し実行する。例えば、作成したEC2にSSH接続してスクリプトを実行できる。Ansibleの代わりになる。
resource "aws_instance" "web" { # ... connection { type = "ssh" user = "root" password = var.root_password host = self.public_ip } provisioner "remote-exec" { on_failure = continue inline = [ "puppet apply", "consul join ${aws_instance.web.private_ip}", ] } }
selfオブジェクト
ブロック内の式はprovisioner、親リソースを名前で参照できない。代わりに、特別なselfオブジェクトを使用できる。
selfオブジェクトはプロビジョナーの親リソースを表し、そのリソースのすべての属性を持っている。例えば、aws_instance.public_ip
の属性を参照するためにself.public_ip
使用します。
local-exec
リソース作成後に、ローカル側で実行可能なファイルを呼び出す。例えば、ローカルPCに配置したAnsibleプレイブックを実行できる。
resource "aws_instance" "web" { # ... provisioner "local-exec" { command = "echo ${self.private_ip} >> private_ips.txt" } }
on_failure パラメータ
on_failure = continue
とすると、もしProvisionerの実行に失敗してもProvisionerの処理が正常に完了したとみなす。on_failure = fail
あるいはon_failure
パラメータを設定しない状態で、もしProvisionerの実行に失敗した場合はリソースがtainted
状態となり、次回のterraform apply実行時に再作成される。
destroy-timeプロビジョナー
destroy-timeプロビジョナー:
Provisionerブロック内にwhen = destroy
と記載するとdestroy-timeプロビジョナーになる。destroy-timeプロビジョナーはリソース削除(=terraform destroy
)時にのみ実行される。
creation-timeプロビジョナー:
デフォルトのProvisionerはcreation-timeプロビジョナーである。明示的に記載するにはwhen = creation
とする。リソース作成時にのみ実行される。Provisionerの実行に失敗した場合には、.tfstate
ファイルにtainted
とマークされる。tainted
になっているため、再度terraform applyした際にいったんリソースが削除されてその後にリソースが再作成される。
null_resource
null_resourceを使うことで、null_resourceでGoogleサーバが起動していることが確認できた場合に、リソースを作成するといったフローが実現できる。
null_resource内では、プロビジョナーによりcurlコマンドを実行し、Googleサーバが起動していることを確認している。
resource "aws_eip" "lb" { vpc = true depends_on = [null_resource.health_check] } resource "null_resource" "health_check" { provisioner "local-exec" { command = "curl https://google.com" } }
triggersをnull_resourceブロック内にパラメータとして設定できる。
triggersにはmap型のデータを格納できる。格納したデータが変更された場合に、プロビジョナーが再実行され、null_resourceが再作成される。
以下の例では、aws_eip.lbのcountが0になっている。つまり、EIPは作成されない。このコードでterraform applyを実行すると、null_resource.ip_checkのみ作成される。
次にcountの値を0から1に変更してEIPが作成されるよう変更する。null_resource.ip_checkはすでに作成済みのため、triggersがなければ再作成されない。しかし、triggersがあることでnull_resource.ip_checkが再作成され、Provisionerも再実行される。
resource "aws_eip" "lb" { vpc = true count = 0 } resource "null_resource" "ip_check" { triggers = { latest_ips = join(",", aws_eip.lb[*].public_ip) } provisioner "local-exec" { command = "echo Latest IPs are ${null_resource.ip_check.triggers.latest_ips} > sample.txt" } }
Dataについて
data
でAWSからAMIの値を取得することができる。filterでフィルタリングすることができる。
data "aws_ami" "web" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["amzn2-ami-hvm*"] } }
Moduleについて
DRY原則とは
DRYとは、Don’t Repeat Yourselfの略で、ソフトウェア開発の原則の一つ。同じソフトウェアパターンの繰り返しはやめようということ。
→ 繰り返し利用するリソースは「モジュール」にして、再利用できるようにする。
以下例では、./modue/ec2
配下にec2.tf
(モジュール)を配置し、./myec2.tf
でモジュールを参照している。
moduleをapplyするには、まずはterraform initコマンドでモジュールを読み込む必要がある。
./modules/ec2/ec2.tf
resource "aws_instance" "myec2" { ami = "ami-082b5a644766e0e6f" instance_type = "t2.micro" }
./myec2.tf
module "ec2module" { source = "./modules/ec2" }
リソース内で変数を代入しておくと、モジュールブロック内で変数の値をオーバーライトできる。 変数を使いたいがオーバーライトさせたくない場合は、localを利用する。
モジュール内で定義したoutputブロックはCLI上に出力されないことに注意。
モジュール側でoutput
ブロックを利用することで、他のリソース作成時にモジュールのoutput値を利用できる。module.<Module_Name>.<Output_Name>
という形式でoutput値を参照する。
./modules/ec2/ec2.tf
resource "aws_instance" "myec2" { ami = "ami-082b5a644766e0e6f" instance_type = var.instance_type } variable "instance_type" { default = "t2.nano" } output "instance" { value = aws_instance.myec2 }
./myec2.tf
module "ec2module" { source = "./modules/ec2" instance_type = "t2.micro" } output "module_output" { value = module.ec2module.instance }
moduleブロック内で、version = "0.0.5"
という形式でモジュールの version
を指定することができる。
モジュールのversion制約指定について詳しくはこちら
Terraform Registry
モジュールをTerraformレジストリから直接取ってくることもできる。
Terraformレジストリから取得したモジュールは、terraform init後にローカルの./.terraform/modules
内に格納される。
module "ec2_cluster" { source = "terraform-aws-modules/ec2-instance/aws" version = "~> 4.0" name = "my-cluster" ami = "ami-0d6621c01e8c2de2c" instance_type = "t2.micro" subnet_id = "subnet-4dbfb206" tags = { Terraform = "true" Environment = "dev" } }
Terraformレジストリには、Terraformコミュニティのメンバーが作成したモジュールが置かれている。まずはTerraformレジストリに参考となるモジュールがないか探すと良い。
特にverified moduleはHashicorpにレビューされており、コントリビューターによって最新であるよう維持管理されている。
verified moduleである場合は、モジュールの横に青いバッジが記されている。
Terraformレジストリの各モジュールの”Notes”はちゃんと読んだほうがよい。必須のパラメータについて解説がある。
Terraform Registryへのモジュールのパブリッシュ
モジュールをTerraformレジストリにパブリッシュすることもできる。
モジュールをTerraformレジストリにパブリッシュするための要件は全部で5つある。全部満たしてないといけない。
標準のモジュール構造を適用すること
x.y.z バージョンタグを記載すること
標準のModule構造
基本的には以下の4つのファイルをModule用のフォルダに配置することが多い。
(ファイル名は任意だが以下のように命名することが多く、デファクトスタンダードになっている)
- READEME.md
- main.tf
- variables.tf
- outputs.tf
Workspaceについて
terraform workspace new <workspace_name>
によりワークスペースを作成すると、カレントディレクトにterraform.tfstate.d
フォルダが作成され、その中にワークスペース名のフォルダが作られる。ワークスペース名のフォルダ配下に.tfstate
ファイルが作成される。このステートファイルはdefaultワークスペースの.tfstate
ファイルとは異なる。
.tf
ファイル内で terraform.workspace
とすればワークスペース名を取得できる。
さらにlookup関数を使って、lookup(var.<map変数>, terraform.workspace)
とすれば、ワークスペース名に紐づけた値を取得できる。
terraform workspace
でワークスペース毎にリソースを作り分けることができる。
ワークスペースのリストを確認するには、terraform workspace list
を実行する。
チームコラボレーション
チームでTerraformコードを開発するには以下の環境を準備する。
git:.tf
ファイルを配置し、共同で開発する。
S3:terraform.tfstate
ファイルを配置することで、チームメンバー間でステートファイルを共有する。ステートファイルにはパスワード等も平文で記載されているため、S3にはアクセス制限を設定する。
DynamoDB:.terraform.lock.hcl
ファイルを配置する。ステートファイルのロック状態をチームメンバー間で共有する。
上記が理想的なアーキテクチャである。
ちなみに、ステートファイルがS3にあり、ロック状態をDynamoDBで管理しながら(つまり、AWSでBackendとステートロックを管理しながら)、AzureやGCP上にリソースを作成することもできる。
ここで.terraform
フォルダやterraform.tfvars
ファイル、terraform.tfstate
ファイル、crash.log
ファイルはgit commitを避けるべきなので、間違えてコミットされないよう.gitignore
ファイルに記載しておく。
git status
コマンドでコミットされてないファイルとフォルダを一覧表示できるので、誤ってコミットされてないか確認しておく。
.gitignore
ファイル
.terraform *.tfvars *.tfstate *.tfstate.* crash.log
Gitについて
ローカルのモジュールを参照するには./
や../
で始まるローカルパスを source
に記述する。
一方、Gitリポジトリにアップロードした .tf
ファイルのモジュールを参照するにはリポジトリのURLにプレフィックスとして git::
を付ける。
コードのリビジョン(ブランチ)を指定するには ?ref=
をサフィックスに付ける。
module "demomodule" { source = "git::https://github.com/zealvora/tmp-repo.git?ref=v1.2.0" }
Backends
terraform.tfstateファイルを保存する場所のことを、Backendと呼んでいる。
デフォルトでは、BackendはローカルPCである。
S3をBackendに指定するには、terraformブロックにbackendブロックを記載する。S3バケットは事前に作成しておく。
terraform { backend "s3" { bucket = "kplabs-terraform-backend" key = "network/terraform.tfstate" region = "us-east-1" } }
上記に加えてS3バケットにアクセスするためのアクセスキーが必要になる。
アクセスキーは ~/.aws/config
ファイルに記載しておく。AWS CLIをダウンロードし、aws configure
コマンドで~/.aws/config
ファイルを作成できる。
ステートファイルロック
誰かがterraform.tfstateファイルを変更するような操作を行っている場合は、terraform.tfstateファイルがロックされている必要がある。さもなければ、他の人がterraform.tfstateファイルに変更を加えて一貫性がなくなる。
誰かがterraform apply
やterraform destroy
を実行すると、ロックが取得される。すると、.terraform.tfstate.lock.info
というファイルが自動的に作成される。Terraformはこのファイルの有無によってロック中かどうかを見分ける。書き込み操作が終了したら、.terraform.tfstate.lock.info
ファイルは自動的に削除される。
ロックが取得されている間に他のユーザーが書き込み操作をした場合、Error acquiring the state lock
エラーが出力される。
チームでState Lock機能を使うためには、DynamoDBを利用する。
注意!
Backendによってはロック機能をサポートしてない。サポートしているかどうかは各Backendのドキュメントを確認すること。S3はサポートしており、DynamoDBを利用する。
DynamoDBを利用してステートロック機能を実現するには、backendブロックに dynamodb_table
変数に、事前に作成しておいたDynamoDBの名前を格納する。
ここで、DynamoDBのパーティションキー名は必ず LockID
で、かつ String
型でなければならない。さもなければ、ステートロック機能がDisableになる。
terraform { backend "s3" { bucket = "kplabs-terraform-backend" key = "network/demo.tfstate" region = "us-east-1" dynamodb_table = "terraform-state-locking" } }
パスワードをGitHub上に保存しないテクニック
GitHubとクローンしたフォルダの外にパスワードファイルを置く。
.tf
からパスワードファイルをfile関数で参照する。file("../password.txt")のような感じ。
.gitignore
ファイルで、Gitコミットしたくないファイルやフォルダを指定できる。
.tfstate
ファイルの保護
上記のやり方でも.tfstate
ファイルに平文のパスワードが記載されてしまっている。
マルチリージョン
providerブロック内にaliasを記載すると、2つ以上のproviderを記述できる。
resourceブロック内で利用するproviderを指定する。
provider "aws" { region = "us-west-1" } provider "aws" { alias = "aws02" region = "ap-south-1" profile = "account02" } resource "aws_eip" "myeip" { vpc = "true" } resource "aws_eip" "myeip01" { vpc = "true" provider = "aws.aws02" }
Logについて
環境変数を設定することでログを出力できる。
ログレベルはこちらを参照。
export TF_LOG=TRACE
環境変数TF_LOG_PATH
にログファイルのパスをセットすることで、ログをファイルに出力することも可能。
export TF_LOG_PATH=./trace.log
リソース間の依存関係
Terraformが自動でImplicit dependency(暗黙の依存関係)を見つけて、リソースの作成順序を決めてくれる。
一方、depends_on変数によって、明示的に依存関係を定義することもできる。
depends_on変数を利用する場合、なぜdepends_on変数が必要なのかをコメントで説明することが推奨される。
resource "aws_iam_role" "example" { name = "example" # assume_role_policy is omitted for brevity in this example. Refer to the # documentation for aws_iam_role for a complete example. assume_role_policy = "..." } resource "aws_iam_instance_profile" "example" { # Because this expression refers to the role, Terraform can infer # automatically that the role must be created first. role = aws_iam_role.example.name } resource "aws_iam_role_policy" "example" { name = "example" role = aws_iam_role.example.name policy = jsonencode({ "Statement" = [{ # This policy allows software running on the EC2 instance to # access the S3 API. "Action" = "s3:*", "Effect" = "Allow", }], }) } resource "aws_instance" "example" { ami = "ami-a1b2c3d4" instance_type = "t2.micro" # Terraform can infer from this that the instance profile must # be created before the EC2 instance. iam_instance_profile = aws_iam_instance_profile.example # However, if software running in this EC2 instance needs access # to the S3 API in order to boot properly, there is also a "hidden" # dependency on the aws_iam_role_policy that Terraform cannot # automatically infer, so it must be declared explicitly: depends_on = [ aws_iam_role_policy.example ] }
フォルダ構成
本番環境では、provider.tf
、variables.tf
、<リソース>.tf
、output.tf
といった形でファイルを分割するのが望ましい。
こうすることでどのファイルに何が記載されているかが一目でわかる。新しくPJに参加した人でもわかりやすい。
リソースが大規模な場合
大規模なリソースを作成しようとすると、AWS等プロバイダー側のAPI上限に達する可能性がある。達しないまでも、処理に時間を要するようになる。
大量のリソースを作成済みの場合、terraform applyにより作成済みリソースのステータスを取得しようと大量にAPIリクエストを投げることになる。そういった場合に、terraform apply -refresh=false
とすることでAPIリクエストの量を軽減できる。
リソース種別ごとにフォルダを分けてterraform applyを実行することで、一度に大量のAPIリクエストを送信することを防ぐことができる。
セキュリティ上の注意点
- クレデンシャルはproviderブロックに記載せずに、
~/.aws/config
ファイルに記載しておく。 .terraform
フォルダやterraform.tfvars
ファイル、terraform.tfstate
ファイル、crash.log
ファイルはgitにアップしないterraform.tfstate
ファイルにはクレデンシャルが平文で記載されるため、S3でアクセス管理を行う。- クレデンシャルを
.tf
ファイルに記載しない。.tf
からパスワードファイルをfile関数で参照する。file("../password.txt")のような感じ。 - outputブロック内にsensitiveパラメータをtrueで設定すると、標準出力にoutputの値が\
と表示されるようになる。但し、ステートファイルには記載されてしまうので要注意。
Terraformコマンド
terraform taint
- 特定のリソースをtaintすることで、terraform apply時にリソースが再作成される。
terraform taint aws_instance.mydc2
- taintされたリソースは、terraform.tfstateファイル上でステータスが
tainted
になる。 - terraform taintでリソースが再作成されることで、EC2に割り当てられたIPが変更されるかもしれない。依存関係などの再作成に伴うリスクは事前に確認しておくこと。
- 多くの会社ではマニュアルでのリソース変更を認めておらず、マニュアルで変更を加えた場合には
terraform taint
でリソースの状態をもとに戻している、らしい。
- 特定のリソースをtaintすることで、terraform apply時にリソースが再作成される。
terraform refresh
terraform.tfstate
ファイルに、現在のプロビジョニングされているリソースの状態を反映する
terraform graph
- リソース作成順序を図示する(グラフ化する)ことができる。
terraform init
terraform init
でプラグインがダウンロードされる。
terraform init -upgrade
- Providerのバージョンをアップグレードできる。
terrafrom fmt
- インデントのズレをあわせてくれる。
terraform plan -out=<出力先パス名>
- terraform planの解析結果をバイナリとして出力する。
terraform apply <出力先パス名>
とすることで解析結果をもとにリソース作成できる。
terraform output <output変数>
- ステートファイルに記載されているoutput変数の値を出力する。
- もちろん.tfstateを直接確認することでもoutput変数に格納されている値を確認できる。あるいは、terraform applyコマンドでoutputを出力させることもできる。
terraform apply -target=ec2
terraform apply -refresh=false
terraform apply -refresh-only
- こちらによると、どうやら
terraform refresh
コマンドは非推奨で、terraform apply -refresh-only
を利用するのが良いそう。
In previous versions of Terraform, the only way to refresh your state file was by using the terraform refresh subcommand. However, this was less safe than the -refresh-only plan and apply mode since it would automatically overwrite your state file without giving you the option to review the modifications first. In this case, that would mean automatically dropping all of your resources from your state file.
- こちらによると、どうやら
terraform login
- The terraform login command can be used to automatically obtain and save an API token for Terraform Cloud, Terraform Enterprise, or any other host that offers Terraform services.
terraform force-unlock
- ステートロックを解除する。
terraform plan -destroy
- terraform destroyコマンドをプレビューすることができる。
terraform show
- The terraform show command is used to provide human-readable output from a state or plan file. This can be used to inspect a plan to ensure that the planned operations are expected, or to inspect the current state as Terraform sees it.
Machine-readable output is generated by adding the -json command-line flag.
terraform state コマンド
terraform stateコマンドにより、ステートファイルを確認したり、変更することができる。
terraform state pull
- backendにあるステートファイルをダウンロードできる。
terraform state show
- 特定のリソースに対するterraform state pullと同義
terraform state mv <既存リソース名> <新リソース名>
- terraformのリソース名を変更しようとすると、リソースがいったん削除されてしまう。terraform state mvを使うことで、リソースを削除せずにリソース名を変更できる。
terraform state list
- ステートファイルに含まれるリソースのリスト表示
terraform state rm <リソースタイプ>.<ローカル名> 【重要】
- ステートファイルから削除される。Terraformでの管理を止めたい場合に利用する。
terraform import コマンド
マニュアル作成したリソースをステートファイルに取り込むことができる。但し、インポートできるリソースは限られているの事前に確認が必要。
インポートする場合は、事前に .tf
ファイルにresourceブロックを記述しておく。
次に terraform import
コマンドを実行する。
terraform import aws_instance.foo i-abcd1234
Terraform Cloudについて
Terraform Cloudは以下の機能を提供する
コスト確認
事前に設定したポリシーを満たしているかのチェック(Sentinel)
コードレビューの記録
モジュールのレジストリ
Gitに保管したTerraformコードとの連携
どうやら、Terraform Enterpriseや有償のTerraform Cloudを使っている会社は多くないらしい。というか、実質ほとんどいない。無料のTerraform Cloudで十分らしい。
Terraform Cloud 無料版
- State management
- Remote operations
- Private module registry
Terraform Cloud 有償版(Team & Governance)
- Team management
- Sentinel policy as code
- Run tasks
- Additional concurrency
Terraform Cloud 有償版(Enterprise)
- Drift detection
- SSO
- Audit logs
- Self-hosted agents
- Custom concurrency
OSS、Terraform Cloudの比較は以下に詳細がわかりやすくまとめられている。
こちらの画像は抜粋。比較表の全文はこちら
Sentinel
SentinelはPolicy as a Codeなフレームワークの1つ。ポリシーの記述に利用する。
Sentinelを利用して、コードレベルのポリシーチェックができる。ポリシーに沿ってないコードは弾かれる。SentinelはTerraformコードのポリシーチェックのみなので、AWS Configなどを使ってマニュアル作成されたリソースについてもポリシーチェックが必要となる。
Terraform Vaultについて
Vaultはリクエストに応じてクレデンシャル情報を払い出してくれる。払い出されたクレデンシャルは一定時間経過後にVaultが自動で削除する。そのため、クレデンシャルが外部に漏れた場合のリスクを低減できる。
Vaultにクレデンシャル払い出しをリクエストする際に、権限も指定できる。
用語
resource "aws_instance" "server" { ami = "ami-a1b2c3d4" instance_type = "t2.micro" }
Resource block
- resourceで始まる{...}
範囲のこと
Resource type
- 上記例での"aws_instance"
のこと
Resource name (= local name)
- 上記例での"server"
のこと
Argument Name
- 上記例でのami
、instance_type
のこと
Argument Value
- 上記例での"ami-a1b2c3d4"
、"t2.micro"
のこと
Child module
- いわゆるmoduleのこと。Child moduleを呼び出す.tf
のメインの部分を「Root module」と呼ぶ。
Address (Resource Address) - リソースを特定できる文字列のこと。モジュールパスと、リソーススペックから成る。[module path][resource spec]
Module path
- A module path addresses a module within the tree of modules. It takes the form module.module_name[module index]
Resource spec
- A resource spec addresses a specific resource instance in the selected module. It has the following syntax resource_type.resource_name[instance index]
aws_instance.myec2
やmodule.foo[0].module.bar["a"]
https://www.terraform.io/cli/state/resource-addressing
コメントアウトについて
コメントアウトに利用できる記号は3種類。
# // /* */
関数
TerraformではUDF(ユーザ定義関数)は作れない。Terraformの組み込み関数のみ。
toset関数
リストを集合に変換できる。
「SET」 = 「集合」のことで、リスト型とは異なり、重複した値を持つことはできない。
Terraformがサポートしている言語
HCLだけでなく、JSONでも記述できる。