TerraformからAWS SAMをデプロイしてみた
2019-06-26
TL; DR
terraform plan
によるレビューはできないけど動かすことは出来るsam build
は基本初回しか動いてくれないので, 毎回terraform taint null_resource.sam_build
してあげると良い
モチベーション
- 基本的にはterraformを使いたい
- でもterraformでlambda扱うのとかしんどい
- そこはAWS SAM使いたい
- terraformからsam扱いたい
ディレクトリ構成
.
├── sam
│ ├── hello_world
│ │ ├── __init__.py
│ │ ├── app.py
│ │ └── requirements.txt
│ └── template.yaml
└── sam.tf
sam/
は sam init --runtime python3.7
で作成したものと同等です。
sam . tf
provider "aws" {}
resource "aws_s3_bucket" "sam_source" {
bucket_prefix = "sam-source-"
force_destroy = true
}
resource "null_resource" "sam_build" {
provisioner "local-exec" {
command = "sam build --base-dir sam/ --template sam/template.yaml --use-container"
}
depends_on = [aws_s3_bucket.sam_source]
}
resource "null_resource" "sam_package" {
triggers = {
sam_build_id = join(",", [null_resource.sam_build.id])
}
provisioner "local-exec" {
command = "sam package --template-file .aws-sam/build/template.yaml --s3-bucket ${aws_s3_bucket.sam_source.id} --output-template-file sam-output.yaml"
}
depends_on = [aws_s3_bucket.sam_source, null_resource.sam_build]
}
data "local_file" "sam_output" {
filename = "sam-output.yaml"
depends_on = [null_resource.sam_package]
}
resource "aws_cloudformation_stack" "sam" {
name = "sam-stack"
template_body = data.local_file.sam_output.content
capabilities = ["CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
depends_on = [null_resource.sam_package, data.local_file.sam_output]
}
実行
# create
$ terraform plan
$ terraform apply -auto-approve
# update
$ terraform taint null_resource.sam_build
$ terraform plan
$ terraform apply -auto-approve
terraform plan での出力サンプル
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
<= read (data resources)
Terraform will perform the following actions:
# data.local_file.sam_output will be read during apply
# (config refers to values not yet known)
<= data "local_file" "sam_output" {
+ content = (known after apply)
+ filename = "sam-output.yaml"
+ id = (known after apply)
}
# aws_cloudformation_stack.sam will be created
+ resource "aws_cloudformation_stack" "sam" {
+ capabilities = [
+ "CAPABILITY_AUTO_EXPAND",
+ "CAPABILITY_NAMED_IAM",
]
+ id = (known after apply)
+ name = "sam-stack"
+ outputs = (known after apply)
+ parameters = (known after apply)
+ policy_body = (known after apply)
+ template_body = (known after apply)
}
# aws_s3_bucket.sam_source will be created
+ resource "aws_s3_bucket" "sam_source" {
+ acceleration_status = (known after apply)
+ acl = "private"
+ arn = (known after apply)
+ bucket = (known after apply)
+ bucket_domain_name = (known after apply)
+ bucket_prefix = "sam-source-"
+ bucket_regional_domain_name = (known after apply)
+ force_destroy = true
+ hosted_zone_id = (known after apply)
+ id = (known after apply)
+ region = (known after apply)
+ request_payer = (known after apply)
+ website_domain = (known after apply)
+ website_endpoint = (known after apply)
+ versioning {
+ enabled = (known after apply)
+ mfa_delete = (known after apply)
}
}
# null_resource.sam_build will be created
+ resource "null_resource" "sam_build" {
+ id = (known after apply)
}
# null_resource.sam_package will be created
+ resource "null_resource" "sam_package" {
+ id = (known after apply)
+ triggers = (known after apply)
}
Plan: 4 to add, 0 to change, 0 to destroy.
普通にyamlを渡していれば + template_body = (known after apply)
の部分にその内容が表示される(はず)のですが, 今回はこの段階では未定なのでこのような表記になっています。
ポイント
sam build
,sam package
はnull_resource
でlocal-exec
で実行。(2つのリソースに分けているけど, まとめてもいいかもしれない)aws_cloudformation_stack.sam
のtemplate_body
にyamlファイルの中身を渡す際に,file
ファンクションは使用せずにdata.local_file
を使用する。file
ファンクションで読み込むにはterraformコマンド実行時にそのファイルが存在していなければならない。しかし今回でいうsam-output.yaml
ファイルはterraformコマンド実行時には存在していないためエラーとなる。data.local_file
にさらにdepends_on = [null_resource.sam_package]
で依存関係を定義してあげるとうまい具合に動的に遅延読み込みしてくれる。- 2回目以降の実行時には基本
null_resource.sam_build
は実行されない。それだと困るので都度terraform taint null_resource.sam_build
で強制的に再実行されるようにしている。 null_resource.sam_package
も基本そのままだと再実行されないが,triggers
を設定しているのでnull_resource.sam_build
が再作成されてidが変わるとnull_resource.sam_package
が再度実行されるようになっている。
蛇足
terraform workspace
でdefault以外を使っているとstateファイルのパスが変わるけど, そうなるとterraform taint
実行時にいちいち-state=path
でstateファイルを渡す必要があってめんどくさいんだけどいい方法ないもんだろうか?