LoginSignup
0
0

terraform で作成した api gateway + lambda をローカル環境で動かす手法

Posted at

api gateway + lambda の構成を作成したらローカルで動かして動作確認をしたいですよね。
今回は、terraform で作成した上記リソースをローカルで動かす方法をまとめました。
意外と癖が強くて、動くようになるまで苦戦しました。そのあたりについても書いていこうと思います。

はじめに

AWS は公式で AWS SAM というサーバレス環境構築ツールを提供しています。

こちらは宣言した内容をそのままAWSにデプロイできる上、dockerを使えばローカルで動作させることも可能な優れものです。ただ、リソースを作成するために書くSAMテンプレートはなかなか癖があり、学習コストも少し高めです。
公式もそれを意識しているのか、2年ほど前に terraform で作成したコードからSAMテンプレートを作成してくれるツールが発表されました。

今回は、このツールを使用して API gateway + lambda の構成をローカルで動作させてみようと思います。

今回できるもの

今回の構成は以下のようになります。

ちなみに以前同じ構成をServeless Frameworkを利用して作成しています。

しかしながら、Serverless Framework は v.4 からある程度の規模を超えると有償になってしまいました。

今後は複数クラウドに対応していて無料で使えるterraformがIaCの最有力候補になると思います。(AWS CDK や CloudFront, bicep, Pulumi, CDM などなど…。IaCの世は大戦国時代ですね。)
前置きが長くなってしまいましたが、ここからは実際に動かしてみようと思います。

動かし方

コード全文はこちらです。

以下のインストトールとセットアップはできているものとするので、ここでの説明は割愛します。

  • aws cli
  • aws sam
  • terraform

今回はlambdaをビルドするコードをshell scriptで書いているので、bashやzshでの実行を前提としています。

git clone https://github.com/Nalagami/terraform-lambda-local-sample
cd terraform-lambda-local-sample
sam build --hook-name terraform --beta-features --terraform-project-root-path ./../
## sam template の作成が始まる ##
sam local start-api --hook-name terraform
## sam template を使用して仮想環境が起動する ##

ここまで実行できれば、local環境にapiが作成されるはずです。
以下のようなコメントが出ていれば成功です。

sam local start-api --hook-name terraform                                          
Skipped prepare hook. Current application is already prepared.                             
Mounting hello-terraform at http://127.0.0.1:3000/example [GET]                            
You can now browse to the above endpoints to invoke your functions. You do not need to     
restart/reload SAM CLI while working on your functions, changes will be reflected          
instantly/automatically. If you used sam build before running local commands, you will need
to re-run sam build for the changes to be picked up. You only need to restart SAM CLI if   
you update your AWS SAM template                                                           
2024-06-08 20:46:53 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:3000
2024-06-08 20:46:53 Press CTRL+C to quit

試しに叩いてみます。

curl -v "http://127.0.0.1:3000/example"
*   Trying 127.0.0.1:3000...
* Connected to 127.0.0.1 (127.0.0.1) port 3000
> GET /example HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/8.6.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.3 Python/3.12.3
< Date: Sat, 08 Jun 2024 13:44:11 GMT
< Content-Type: application/json
< Access-Control-Allow-Origin: *
< Content-Length: 17
< Connection: close
< 
* Closing connection
Request Received!% 

きちんとレスポンスが返ってきてますね。

コード解説

ここからはコード内のどの部分でローカル実行を宣言しているか解説していきます。

terraform/lambda.tf
~~~省略~~~

resource "null_resource" "sam_metadata_aws_lambda_function_hello_terraform" {
  triggers = {
    resource_name        = "aws_lambda_function.hello_lambda"
    resource_type        = "ZIP_LAMBDA_FUNCTION"
    original_source_code = "${local.lambda_src_path}"
    built_output_path    = "${local.building_path}/${local.lambda_code_filename}"
  }
  depends_on = [
    null_resource.build_lambda_function
  ]
}

~~~省略~~~

AWS SAMがLambda関数を識別するために書かれている設定です。
ここで使われているnull_resourceはterraformの構文でサポートされていないリソースを管理する際に宣言します。AWS SAMはsam_metadata_aws_lambda_function_hello_terraformが宣言されていた場合、ここの設定を読み取ってSAMテンプレートを作成します。
また、depends_onにはLambdaのzipファイル作成用のnull_resourceが宣言されています。

terraform/lambda.tf
~~~省略~~~
resource "null_resource" "build_lambda_function" {
  triggers = {
    build_number = "${timestamp()}" # TODO: calculate hash of lambda function. Mo will have a look at this part
  }
  provisioner "local-exec" {
    command = substr(pathexpand("~"), 0, 1) == "/" ? "./py_build.sh \"${local.lambda_src_path}\" \"${local.building_path}\" \"${local.lambda_code_filename}\" Function" : "powershell.exe -File .\\PyBuild.ps1 ${local.lambda_src_path} ${local.building_path} ${local.lambda_code_filename} Function"
  }
}
~~~省略~~~

lambdaのファイルをzipファイルにするためのnull_resourceです。
triggers が timestampになっているため、terraform planterraform applyの際は必ず実行されます。

terraform/py_build.sh
#!/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

src_code=$1
build_path=$2
output_name=$3
resource_type=$4

[[ -z "$src_code" ]]      && echo "ERROR: src_code is not defined"      && exit 1
[[ -z "$build_path" ]]    && echo "ERROR: build_path is not defined"    && exit 1
[[ -z "$output_name" ]]   && echo "ERROR: output_name is not defined"   && exit 1
[[ -z "$resource_type" ]] && echo "ERROR: resource_type is not defined" && exit 1

echo "building ${resource_type} ${src_code} into ${build_path}"

temp_path=${build_path}/tmp_building
if [[ "${resource_type}" == "Layer" ]]; then
  temp_path=${build_path}/tmp_building/python
  echo "new path ${temp_path}"
fi

pwd
mkdir -p ${build_path}
rm -rf ${build_path}/*
mkdir -p ${build_path}/tmp_building
mkdir -p ${temp_path}
cp -r $src_code/* ${temp_path}
pip install -r ${temp_path}/requirements.txt -t ${temp_path}/.
pushd ${build_path}/tmp_building/ && zip -r $output_name . && popd
mv "${build_path}/tmp_building/${output_name}" "${build_path}/$output_name"
rm -rf ${build_path}/tmp_building˜

Lambdaでにアップロードするpythonのzipファイルを作成するためのshellscriptです。
やっていることは、requirements.txtに書かれているパッケージをダウンロードして、ソースコードと一緒にzipファイルへ圧縮しているだけです。
公式のリポジトリにpowershell版もあるので、windowsを利用している方は参考にしてください。

まとめ

terraformで作成したリソースをローカルで動作させる方法をまとめました。ちなみにLambda→DynamoDBの通信もできるみたいですが、その際はAWS環境のDynamoDBを見に行く挙動となりました。そのため、DynamoDB local でローカルDBを作成しつつ、コードでboto3のエンドポイントを切り替えれば、ローカルだけで動かすこともできそうでした。
ただ、ここまでやるならAWS SAMを勉強した方が早い気もするので、使い所が難しいと感じました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0