はじめに フューチャーの棚井龍之介です。TIGグループのDXユニットに所属しています。
TerraformはLocalstackに対してもapplyできます。便利な方法なのに日本語のサイトが見当たらないので、技術ブログ化しました。
この記事を読むとできるようになること
ローカル環境に立ち上げた localstack に向けて、terraform plan/apply/destroy を実行できる
みなさんは、Localstack や Terraform を使っていますか?
アプリのローカル環境テストとしてLocalstackを、インフラ構築にTerraformを用いる開発スタイルは、今やそう珍しいものではないと思います。
しかしながら、「ローカル環境のLocalStackに向けて、Terraformを打ち込むことができる」というのは、あまり知られていないようです。Googleで「localstack terraform」で検索しても、この方法を説明する日本語の入門記事は見つかりませんでした。docker-composeで立ち上げたlocalstackに向けて terraform apply を実行する方法が分かったら、開発環境の作り方や、E2Eテストの方法が広がると思いませんか?
以降の内容では、localstackの立ち上げ → terraform plan/apply実行 までを説明します。
以下の流れで説明します。
今回のディレクトリ構造
docker-composeでlocalstack立ち上げ
terraformファイルを編集
localstackにterraform plan/apply
また、作業では docker-compose
と terraform
と awscli
を利用しますが、これらのコマンドは各自で用意済みの前提とします。
ローカル完結の作業であるため、各コマンドの実行環境が揃っていれば、AWSアカウントの準備はもちろん不要 です。
参考までに、私が本ブログの執筆時に利用したバージョンはこちらです。
$ docker-compose --version docker-compose version 1.27.4, build 40524192 $ terraform --version Terraform v0.13.5 $ aws --version aws-cli/1.18.166 Python/3.7.4 Darwin/19.6.0 botocore/1.19.6 $ sw_vers -productName ProductName: Mac OS X
1. 今回のディレクトリ構造 本記事は以下のディレクトリ構成での作業とします。
sandbox/ ├ docker-compose.yml ├ main.tf ├ resources.tf ├ hello.go └ lambda.zip
各ファイルは $ touch <filename>
などを利用して生成してください、Lambdaの中身にまでは踏み込まないので、lambda.zip は 以下の hello.go を build & zip化して生成お願いします
hello.go package mainimport ( "fmt" ) func main () { fmt.Println("hello, world" ) }
build, zipコマンド
GOOS=linux GOARCH=amd64 go build -o hello zip lambda.zip hello
以上で、作業前の準備は完了です。
2. docker-composeでLocalstack立ち上げ docker-compose.ymlを編集して、Localstackの定義を追加します。
Localstackの定義は、本家サイトの記述を参照しています。https://github.com/localstack/localstack/blob/master/docker-compose.yml
docker-compose.yml version: '2.1' services: localstack: container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}" image: localstack/localstack:0.12.1 network_mode: bridge ports: - 127.0 .0 .1 :4566:4566/tcp environment: - SERVICES=${SERVICES- } - DEBUG=${DEBUG- } - DATA_DIR=${DATA_DIR- } - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- } - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- } - DOCKER_HOST=unix:///var/run/docker.sock - HOST_TMP_FOLDER=${TMPDIR} volumes: - "${TMPDIR:-/tmp/localstack}:/tmp/localstack" - "/var/run/docker.sock:/var/run/docker.sock"
yamlファイルに追記完了したら、localstackを立ち上げます。$ docker-compose ps
で起動が確認できたら、localstack側の準備は完了です。
$ docker-compose -f docker-compose.yml up -d localstack Creating localstack_main ... done $ docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------------------------------------------------------------------------------------- localstack_main docker-entrypoint.sh Up 127.0.0.1:4566->4566/tcp, 4567/tcp, 4568/tcp, 4569/tcp, 4570/tcp, 4571/tcp, 4572/tcp, 4573/tcp, 4574/tcp, 4575/tcp, 4576/tcp, 4577/tcp, 4578/tcp, 4579/tcp, 4580/tcp, 4581/tcp, 4582/tcp, 4583/tcp, 4584/tcp, 4585/tcp, 4586/tcp, 4587/tcp, 4588/tcp, 4589/tcp, 4590/tcp, 4591/tcp, 4592/tcp, 4593/tcp, 4594/tcp, 4595/tcp, 4596/tcp, 4597/tcp, 8080/tcp
Terraform定義に、Localstackへplan,applyを打ち込むための設定を記入します。
terraform main.tf terraform { backend "local" {} } 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自体の説明は本記事の目的ではないので、一気に追加します
terraform resources.tf 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 の準備は完了です
新しいディレクトリでterraformを使う場合は、まずは $ terraform init
して、backend と provider を設定します
$ terraform init Initializing the backend... Successfully configured the backend "local" ! Terraform will automatically use this backend unless the backend configuration changes. Initializing provider plugins... (略) Terraform has been successfully initialized! (略)
terraform init が完了しました。
Terraformの実行準備が完了したので、$ 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. data.aws_iam_policy_document.local_policy_document: Refreshing state... ------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: (略) Plan: 7 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can' t guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
planも正しく実行できました。
$ terraform apply
(なるべく短いログでapply状況を載せたかったので、–auto-approve を利用しています)
$ terraform apply --auto-approve data.aws_iam_policy_document.local_policy_document: Refreshing state... aws_iam_policy.local_policy: Creating... aws_kinesis_stream.local_stream: Creating... aws_iam_role.local_role: Creating... aws_s3_bucket.local_archive: Creating... aws_iam_role.local_role: Creation complete after 0s [id =local-role] aws_lambda_function.local_lambda: Creating... aws_iam_policy.local_policy: Creation complete after 0s [id =arn:aws:iam::000000000000:policy/local-iam-policy] aws_iam_role_policy_attachment.local_poilcy_attachment: Creating... aws_iam_role_policy_attachment.local_poilcy_attachment: Creation complete after 0s [id =local-role-20201029145646394900000001] aws_s3_bucket.local_archive: Creation complete after 1s [id =local-archive] aws_lambda_function.local_lambda: Creation complete after 6s [id =local-lambda] aws_kinesis_stream.local_stream: Still creating... [10s elapsed] aws_kinesis_stream.local_stream: Still creating... [20s elapsed] aws_kinesis_stream.local_stream: Still creating... [30s elapsed] aws_kinesis_stream.local_stream: Creation complete after 30s [id =arn:aws:kinesis:us-east-1:000000000000:stream/local-stream] aws_lambda_event_source_mapping.local_mapping: Creating... aws_lambda_event_source_mapping.local_mapping: Creation complete after 0s [id =7029d656-c97d-4256-90bf-a3eb38c50e93] Apply complete! Resources: 7 added, 0 changed, 0 destroyed. The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the `terraform show` command . State path: terraform.tfstate
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
apply成功です!
awscliを用いて、各リソースの追加を確認することもできます。
$ aws --endpoint-url http://localhost:4566 s3 ls 2020-10-29 14:51:17 local-archive $ aws --endpoint-url http://localhost:4566 kinesis list-streams { "StreamNames" : [ "local-stream" ] } $ aws --endpoint-url http://localhost:4566 lambda list-functions { "Functions" : [ { "FunctionName" : "local-lambda" , "FunctionArn" : "arn:aws:lambda:us-east-1:000000000000:function:local-lambda" , "Runtime" : "go1.x" , "Role" : "arn:aws:iam::000000000000:role/local-role" , "Handler" : "lambda" , "CodeSize" : 1035298, "Description" : "" , "Timeout" : 3, "MemorySize" : 128, "LastModified" : "2020-10-29T14:56:46.405+0000" , "CodeSha256" : "0rECD6MUpCBF7jIrzT53RTSjH0D1iTBTUd6t+FfP7is=" , "Version" : "$LATEST " , "VpcConfig" : {}, "TracingConfig" : { "Mode" : "PassThrough" }, "RevisionId" : "3fc0da3d-eb5e-471a-9d26-c0a7b3f98d90" , "State" : "Active" , "LastUpdateStatus" : "Successful" } ] }
これで、ローカルに閉じた環境で、Terraformを好き放題使えますね!
まとめ 本記事では、Localstackに向けてTerraformを実行する方法をご紹介しました。
この手法は何より AWSアカウントなしで実行可能 なので、例えば…
インフラ新規参入者向けのterraformコマンド練習環境として
社内規約でcredentialが発行できず、インフラタスクを振れないアルバイトさん向けの環境として
他人と絶対にconflictせず、好き勝手にdestroyできる自分だけの無料の環境 として
も利用可能です。
ここまで読んでいただいた皆様も、色々なリソースをterraformコマンドでLocalstackに構築してみてください!
参照サイト