
開幕宣言
この記事は estie 夏のブログ祭りの1日目の記事です。
8月ですね 🍉
今年は梅雨明けが早く、でもそのあとに雨が続いたり、またご時世もあったりしますが皆様いかがお過ごしでしょうか。
本格的な夏が始まったということで、estie 夏のブログ祭りを開催します!! 🏄🏄♀️🏄♂️
エンジニア、非エンジニア含め平日毎日ブログを更新していきます。テクニカルな話、カルチャーな話などなど更新されていきますので、皆さんチェックしてくださいね!
はじめに
普段はRuby on Rails や Python を使って開発をしている、アプリケーションエンジニアのえりりんです。
以前 Terraform でアプリの設定を変更する記事を書きました。
記事はこちら
アプリケーションエンジニアが Terraform 触ってみた|えりりん|note
あれから半年強経ってだいぶ Terraform に慣れてきたので1サービス管理できるようになった記事を書いて見ます。
管理対象の作成
AWS Step Functions というサービスはご存知でしょうか?
そうです。ワークフローサービスです。
処理の順番や条件を定義しておくと、再実行やタイムアウトを管理しながら実行してくれるものです。
AWS Management Console 上のGUIから以下のように処理したいサービスのパーツを順番に組み立てて設定ができます。

この組み立てた内容は JSON で定義されます。

では、これを Terraform で書いたらどうなるのでしょうか。
Terraform 編
今回書くコードは以下に push してありますので、よろしければ参考にしてみてください。
まずは repository を作成して Terraform が使える準備をします。
こちらを参考に書いていきます。
main.tf
erraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "ap-northeast-1"
}
terraform {
backend "s3" {
bucket = "stepfunction-tf-state"
key = "test.tfstate"
region = "ap-northeast-1"
}
}
初期化します。
terraform init
AWS Step Functions を定義するリソースを用意します (23行目〜25行目)。
main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "ap-northeast-1"
}
terraform {
backend "s3" {
bucket = "stepfunction-tf-state"
key = "test.tfstate"
region = "ap-northeast-1"
}
}
resource "aws_sfn_state_machine" "sfn_state_machine" {
}
続いて AWS Management Console で行った設定を import します。
リソースによって import の仕方が違うので注意です。
AWS Step Functions の場合はどうかというと、以下のページを参照します。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sfn_state_machine
一番下に import 時のコマンドが書いてありますね。
State Machines can be imported using the arn
とのことなので arn を指定して import します。
terraform import aws_sfn_state_machine.sfn_state_machine arn:aws:states:ap-northeast-1:XXXXXX:stateMachine:HelloWorld
import 成功です!🎉

main.tf の中身を埋めていきます。
state file から中身を参照しましょう。
terraform state show aws_sfn_state_machine.sfn_state_machine
# aws_sfn_state_machine.sfn_state_machine:
resource "aws_sfn_state_machine" "sfn_state_machine" {
arn = "arn:aws:states:ap-northeast-1:
...
...
...
...
...
definition = jsonencode(
{
Comment = "A Hello World example demonstrating various state types of the Amazon States Language"
StartAt = "Pass"
States = {
"Hello World" = {
End = true
Type = "Pass"
}
"Hello World example?" = {
Choices = [
{
BooleanEquals = true
Next = "Yes"
Variable = "$.IsHelloWorldExample"
},
{
BooleanEquals = false
Next = "No"
Variable = "$.IsHelloWorldExample"
},
]
Comment = "A Choice state adds branching logic to a state machine. Choice rules can implement 16 different comparison operators, and can be combined using And, Or, and Not"
Default = "Yes"
Type = "Choice"
}
No = {
Cause = "Not Hello World"
Type = "Fail"
}
"Parallel State" = {
Branches = [
{
StartAt = "Hello"
States = {
Hello = {
End = true
Type = "Pass"
}
}
},
{
StartAt = "World"
States = {
World = {
End = true
Type = "Pass"
}
}
},
]
Comment = "A Parallel state can be used to create parallel branches of execution in your state machine."
Next = "Hello World"
Type = "Parallel"
}
Pass = {
Comment = "A Pass state passes its input to its output, without performing work. Pass states are useful when constructing and debugging state machines."
Next = "Hello World example?"
Type = "Pass"
}
"Wait 3 sec" = {
Comment = "A Wait state delays the state machine from continuing for a specified time."
Next = "Parallel State"
Seconds = 3
Type = "Wait"
}
Yes = {
Next = "Wait 3 sec"
Type = "Pass"
}
}
}
)
}
と表示されるのでこの内容をそのまま main.tf に貼ります (24行目〜109行目)。
main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "ap-northeast-1"
}
terraform {
backend "s3" {
bucket = "stepfunction-tf-state"
key = "test.tfstate"
region = "ap-northeast-1"
}
}
resource "aws_sfn_state_machine" "sfn_state_machine" {
definition = jsonencode(
{
Comment = "A Hello World example demonstrating various state types of the Amazon States Language"
StartAt = "Pass"
States = {
"Hello World" = {
End = true
Type = "Pass"
}
"Hello World example?" = {
Choices = [
{
BooleanEquals = true
Next = "Yes"
Variable = "$.IsHelloWorldExample"
},
{
BooleanEquals = false
Next = "No"
Variable = "$.IsHelloWorldExample"
},
]
Comment = "A Choice state adds branching logic to a state machine. Choice rules can implement 16 different comparison operators, and can be combined using And, Or, and Not"
Default = "Yes"
Type = "Choice"
}
No = {
Cause = "Not Hello World"
Type = "Fail"
}
"Parallel State" = {
Branches = [
{
StartAt = "Hello"
States = {
Hello = {
End = true
Type = "Pass"
}
}
},
{
StartAt = "World"
States = {
World = {
End = true
Type = "Pass"
}
}
},
]
Comment = "A Parallel state can be used to create parallel branches of execution in your state machine."
Next = "Hello World"
Type = "Parallel"
}
Pass = {
Comment = "A Pass state passes its input to its output, without performing work. Pass states are useful when constructing and debugging state machines."
Next = "Hello World example?"
Type = "Pass"
}
"Wait 3 sec" = {
Comment = "A Wait state delays the state machine from continuing for a specified time."
Next = "Parallel State"
Seconds = 3
Type = "Wait"
}
Yes = {
Next = "Wait 3 sec"
Type = "Pass"
}
}
}
)
name = "HelloWorld"
tags = {}
tags_all = {}
type = "STANDARD"
logging_configuration {
include_execution_data = false
level = "OFF"
}
tracing_configuration {
enabled = false
}
}
これで AWS Step Functions を Terraform 管理することができました!
しかし、AWS Step Functions の定義の JSON 部分もうちょっと綺麗に書けないかなと考えました。
リファクタ編
Terraform にはいくつかの function がありますが、その中に templatefile という function があります。
公式ドキュメントはこちら
これを使って JSON 部分を別ファイルに切り出してみましょう。
JSON部分を別ファイルにします。
definition.tftpl
{
"Comment": "A Hello World example demonstrating various state types of the Amazon States Language",
"StartAt": "Pass",
"States": {
"Pass": {
"Comment": "A Pass state passes its input to its output, without performing work. Pass states are useful when constructing and debugging state machines.",
"Type": "Pass",
"Next": "Hello World example?"
},
"Hello World example?": {
"Comment": "A Choice state adds branching logic to a state machine. Choice rules can implement 16 different comparison operators, and can be combined using And, Or, and Not",
"Type": "Choice",
"Choices": [
{
"Variable": "$.IsHelloWorldExample",
"BooleanEquals": true,
"Next": "Yes"
},
{
"Variable": "$.IsHelloWorldExample",
"BooleanEquals": false,
"Next": "No"
}
],
"Default": "Yes"
},
"Yes": {
"Type": "Pass",
"Next": "Wait 3 sec"
},
"No": {
"Type": "Fail",
"Cause": "Not Hello World"
},
"Wait 3 sec": {
"Comment": "A Wait state delays the state machine from continuing for a specified time.",
"Type": "Wait",
"Seconds": 3,
"Next": "Parallel State"
},
"Parallel State": {
"Comment": "A Parallel state can be used to create parallel branches of execution in your state machine.",
"Type": "Parallel",
"Next": "Hello World",
"Branches": [
{
"StartAt": "Hello",
"States": {
"Hello": {
"Type": "Pass",
"End": true
}
}
},
{
"StartAt": "World",
"States": {
"World": {
"Type": "Pass",
"End": true
}
}
}
]
},
"Hello World": {
"Type": "Pass",
"End": true
}
}
}
main.tf で上記のファイルを読むようにします (24行目〜27行目)。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
region = "ap-northeast-1"
}
terraform {
backend "s3" {
bucket = "stepfunction-tf-state"
key = "test.tfstate"
region = "ap-northeast-1"
}
}
resource "aws_sfn_state_machine" "sfn_state_machine" {
definition = templatefile(
"definition.tftpl",
{}
)
name = "HelloWorld"
role_arn = "arn:aws:iam::XXX:role/service-role/StepFunctions-HelloWorld-role"
tags = {}
tags_all = {}
type = "STANDARD"
logging_configuration {
include_execution_data = false
level = "OFF"
}
tracing_configuration {
enabled = false
}
}
外部ファイルに変数を渡すこともできます。
main.tf(抜粋)
resource "aws_sfn_state_machine" "sfn_state_machine" {
definition = templatefile(
"definition.tftpl",
{
wait_sec = 5
}
)
name = "HelloWorld"
role_arn = "arn:aws:iam::XXX:role/service-role/StepFunctions-HelloWorld-role"
tags = {}
tags_all = {}
type = "STANDARD"
logging_configuration {
include_execution_data = false
level = "OFF"
}
tracing_configuration {
enabled = false
}
}
definition.tftpl(抜粋)
"Yes": {
"Type": "Pass",
"Next": "Wait ${wait_sec} sec"
},
上記のように templatefile を用いることにより wait_sec の値だけ変えた AWS Step Functions を複数作成するなど、同一ファイルを用いて複数のインフラを用意する保守性の高い Terraform コードが書けます!
まとめ
AWS Management Console で作成した AWS Step Functions を Terraform で管理し、種類を増やしたい要望にも耐えられるコードが書けました!
2日目は『estieの開発チームは、ビジネスメンバーと共に価値創出する』です。 お楽しみに✨✨✨