はじめに
フューチャーの棚井龍之介です。TIGグループのDXユニットに所属しています。
TerraformはLocalstackに対してもapplyできます。便利な方法なのに日本語のサイトが見当たらないので、技術ブログ化しました。
この記事を読むとできるようになること
- ローカル環境に立ち上げた localstack に向けて、terraform plan/apply/destroy を実行できる
LocalStackとTerraform
みなさんは、Localstack や Terraform を使っていますか?
アプリのローカル環境テストとしてLocalstackを、インフラ構築にTerraformを用いる開発スタイルは、今やそう珍しいものではないと思います。
しかしながら、「ローカル環境のLocalStackに向けて、Terraformを打ち込むことができる」というのは、あまり知られていないようです。Googleで「localstack terraform」で検索しても、この方法を説明する日本語の入門記事は見つかりませんでした。docker-composeで立ち上げたlocalstackに向けて terraform apply を実行する方法が分かったら、開発環境の作り方や、E2Eテストの方法が広がると思いませんか?
以降の内容では、localstackの立ち上げ → terraform plan/apply実行 までを説明します。
Localstackに向けて、Terraformを打つ
以下の流れで説明します。
- 今回のディレクトリ構造
- docker-composeでlocalstack立ち上げ
- terraformファイルを編集
- localstackにterraform plan/apply
また、作業では docker-compose
と terraform
と awscli
を利用しますが、これらのコマンドは各自で用意済みの前提とします。
ローカル完結の作業であるため、各コマンドの実行環境が揃っていれば、AWSアカウントの準備はもちろん不要です。
参考までに、私が本ブログの執筆時に利用したバージョンはこちらです。
$ docker-compose --version |
1. 今回のディレクトリ構造
本記事は以下のディレクトリ構成での作業とします。
sandbox/ |
各ファイルは $ touch <filename>
などを利用して生成してください、Lambdaの中身にまでは踏み込まないので、lambda.zip は 以下の hello.go を build & zip化して生成お願いします
package main |
build, zipコマンド
GOOS=linux GOARCH=amd64 go build -o hello |
以上で、作業前の準備は完了です。
2. docker-composeでLocalstack立ち上げ
docker-compose.ymlを編集して、Localstackの定義を追加します。
Localstackの定義は、本家サイトの記述を参照しています。
https://github.com/localstack/localstack/blob/master/docker-compose.yml
version: '2.1' |
yamlファイルに追記完了したら、localstackを立ち上げます。$ docker-compose ps
で起動が確認できたら、localstack側の準備は完了です。
$ docker-compose -f docker-compose.yml up -d localstack |
3. Terraformファイルを編集
Terraform定義に、Localstackへplan,applyを打ち込むための設定を記入します。
# backend terraform { backend "local" {} } # provider provider "aws" { region = "us-east-1" access_key = "mock_access_key" secret_key = "mock_secret_key" s3_force_path_style = true skip_credentials_validation = true skip_metadata_api_check = true skip_requesting_account_id = true endpoints { iam = "http://localhost:4566" kinesis = "http://localhost:4566" lambda = "http://localhost:4566" s3 = "http://localhost:4566" } } |
providerは aws
ですが、以下4つの引数をtrueに設定することで、terraformの向き先をローカル環境のMockに設定できます。
- s3_force_path_style
- skip_credentials_validation
- skip_metadata_api_check
- skip_requesting_account_id
また、ローカル完結作業のため、以下の引数は自由な値を入力して問題ありません。
- region(実在するregionに限る)
- access_key
- secret_key
endpointsについて
providerがawsの場合、各awsサービスのendpointsをカスタマイズ可能です。endpointsの向き先を調整することにより、ローカル完結のterraform環境が実現可能という訳です。
localstackは 2020-09-15リリース から
all services are now exposed via the edge service (port 4566) only
なので、endpointsのURLは全て http://localhost:4566
になります。
各自でカスタマイズする場合は、terraform で apply 予定のリソース全てをendpoints定義に追加してください。利用可能なサービス一覧は、こちら に掲載されています。
本記事でLocalstackに構築するもの
backendとproviderの定義は完了したので、次は各種リソースを追加しましょう。本記事では、サーバレス構成でよくある「Kinesisでデータを受けて、Lambdaで取得し、S3に永続化」のインフラ環境を、Terraformを使ってLocalstack内に構築します。

上記構成をterraform定義するのに必要なresourceはこちらです
- aws_kinesis_stream
- aws_lambda_event_source_mapping
- aws_lambda_function
- aws_iam_role
- aws_iam_policy
- aws_iam_role_policy_attachment
- aws_s3_bucket
Terraform自体の説明は本記事の目的ではないので、一気に追加します
resource "aws_kinesis_stream" "local_stream" { name = "local-stream" shard_count = 1 retention_period = 168 } resource "aws_lambda_event_source_mapping" "local_mapping" { event_source_arn = aws_kinesis_stream.local_stream.arn function_name = aws_lambda_function.local_lambda.arn starting_position = "LATEST" maximum_retry_attempts = 1 batch_size = 100 maximum_batching_window_in_seconds = 5 } resource "aws_lambda_function" "local_lambda" { filename = "lambda.zip" function_name = "local-lambda" role = aws_iam_role.local_role.arn handler = "lambda" runtime = "go1.x" } resource "aws_iam_role" "local_role" { name = "local-role" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "lambda.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] } EOF } resource "aws_iam_policy" "local_policy" { name = "local-iam-policy" policy = data.aws_iam_policy_document.local_policy_document.json } data "aws_iam_policy_document" "local_policy_document" { statement { effect = "Allow" actions = [ "s3:GetObject", "s3:ListBucket", "s3:PutBucketNotification", "s3:PutObject", "s3:DeleteObject", ] resources = ["*"] } statement { effect = "Allow" actions = [ "kinesis:DescribeStream", "kinesis:GetShardIterator", "kinesis:GetRecords" ] resources = ["*"] } } resource "aws_iam_role_policy_attachment" "local_poilcy_attachment" { role = aws_iam_role.local_role.name policy_arn = aws_iam_policy.local_policy.arn } resource "aws_s3_bucket" "local_archive" { bucket = "local-archive" versioning { enabled = true } } |
以上により、plan/apply の準備は完了です
3. Localstackにterraform plan/apply
まずは terraform init から
新しいディレクトリでterraformを使う場合は、まずは $ terraform init
して、backend と provider を設定します
$ terraform init |
terraform init が完了しました。
Localstackに向けて、terraform plan を実行
Terraformの実行準備が完了したので、$ terraform plan
を実行します。
$ terraform plan |
planも正しく実行できました。
Localstackに向けて、terraform apply を実行
$ terraform apply
(なるべく短いログでapply状況を載せたかったので、–auto-approve を利用しています)
$ terraform apply --auto-approve |
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
apply成功です!
awscliを用いて、各リソースの追加を確認することもできます。
# S3 |
これで、ローカルに閉じた環境で、Terraformを好き放題使えますね!
まとめ
本記事では、Localstackに向けてTerraformを実行する方法をご紹介しました。
この手法は何より AWSアカウントなしで実行可能 なので、例えば…
- インフラ新規参入者向けのterraformコマンド練習環境として
- 社内規約でcredentialが発行できず、インフラタスクを振れないアルバイトさん向けの環境として
- 他人と絶対にconflictせず、好き勝手にdestroyできる自分だけの無料の環境として
も利用可能です。
ここまで読んでいただいた皆様も、色々なリソースをterraformコマンドでLocalstackに構築してみてください!