AWS Lambda & API gateway
使用說明
透過 terraform 檔案來建立 AWS 無伺服器服務 Lambda,並建立 API gateway 來作為終端用戶呼叫 Lambda 函數的方式。在建立 Lambda 服務之前,需要先有欲執行的執行檔,並進一步編譯與包含所需的函式庫。之後執行 terraform 指令來建立 Lambda 與 API gateway 服務。
建置架構
目錄結構
labmda
├── lamda.tf
├── gateway.tf
├── output.tf
├── main.go
├── Makefile
└── bin
└── main
程式碼與組態檔內容
main.go
package main
import (
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
// Response of APItype Response struct {
Message string `json:"message"`
At string `json:"at"`
}
func handleRequest(req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
resp := Response{
Message: "Hello World!",
At: time.Now().Format(time.RFC3339),
}
name, ok := req.QueryStringParameters["name"]
if ok {
resp.Message = fmt.Sprintf("Hello, %s!\n", name)
}
body, _ := json.Marshal(resp)
res := events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
Headers: map[string]string{"Content-Type": "text/json; charset=utf-8"},
Body: string(body),
}
return res, nil
}
func main() {
lambda.Start(handleRequest)
}
Makefile
build:
GOOS=linux go build -ldflags="-s -w" -o bin/main main.go
lambda.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
provider "aws" {
profile = "default"
region = "ap-northeast-1"
}
provider "archive" {}
data "archive_file" "zip" {
type = "zip"
source_file = "bin/main"
output_path = "hello_lambda.zip"
}
data "aws_iam_policy_document" "policy" {
statement {
sid = ""
effect = "Allow"
principals {
identifiers = ["lambda.amazonaws.com"]
type = "Service"
}
actions = ["sts:AssumeRole"]
}
}
resource "aws_iam_role" "lambda_exec" {
name = "lambda_exec"
assume_role_policy = data.aws_iam_policy_document.policy.json
}
resource "aws_lambda_function" "hello" {
function_name = "hello_lambda"
filename = data.archive_file.zip.output_path
source_code_hash = data.archive_file.zip.output_base64sha256
role = aws_iam_role.lambda_exec.arn
handler = "main"
runtime = "go1.x"
}
gateway.tf
resource "aws_api_gateway_rest_api" "hello" {
name = "hello"
description = "Serverless hello world"
}
resource "aws_api_gateway_resource" "hello" {
path_part = "hello"
parent_id = aws_api_gateway_rest_api.hello.root_resource_id
rest_api_id = aws_api_gateway_rest_api.hello.id
}
resource "aws_api_gateway_method" "hello" {
rest_api_id = aws_api_gateway_rest_api.hello.id
resource_id = aws_api_gateway_resource.hello.id
http_method = "GET"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "hello" {
rest_api_id = aws_api_gateway_rest_api.hello.id
resource_id = aws_api_gateway_resource.hello.id
http_method = aws_api_gateway_method.hello.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = aws_lambda_function.hello.invoke_arn
}
resource "aws_api_gateway_deployment" "hello_v1" {
depends_on = [
aws_api_gateway_integration.hello
]
rest_api_id = aws_api_gateway_rest_api.hello.id
stage_name = "v1"
}
resource "aws_lambda_permission" "hello" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.hello.arn
principal = "apigateway.amazonaws.com"
}
output.tf
output "url" {
value = "${aws_api_gateway_deployment.hello_v1.invoke_url}${aws_api_gateway_resource.hello.path}"
}
開始建置
-
先建立資料夾 labmda 並依據程式碼與組態檔內容創建五個文件
-
準備編譯 main.go
-
執行 terraform init 初始化 Terraform
-
執行 terraform apply 建立 Lambda 與 API Gateway
labmda.tf
- 使用 archive_file 打包編譯好的執行檔
- 使用 aws_iam_policy_document 跟 aws_iam_role 建立 IAM 角色
- 使用 aws_lambda_function 建立 Lambda 函數
gateway.tf
- 使用 aws_api_gateway_rest_api 建立 API 閘道物件
- 使用 aws_api_gateway_resource 建立 API 閘道資源,設定路徑為 hello
- 使用 aws_api_gateway_method 建立 API 閘道資源的方法,設定方法為 GET
- 使用 aws_api_gateway_integration 整合 API 閘道跟 Lambda 函數
- integration_http_method 設定成 POST
- type 設定成 AWS_PROXY
- uri 填入 Lambda 函數的 invoke arn
- 使用 aws_api_gateway_deployment 部署 API 閘道,要設定 depends_on 確保 aws_api_gateway_integration 完成之後才能部署 API
- 使用 aws_lambda_permission 允許 API 閘道使用 Lambda 函數
output.tf
- API 的完整網址被輸出到此文件
- (example) Outputs:測試 url = https://k09e1wi32e.execute-api.ap-northeast-1.amazonaws.com/v1/hello
-
測試
測試 Lambda
aws lambda invoke --region=ap-northeast-1 --function-name=hello_lambda output.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}檢查輸出資料
cat output.json
{"statusCode":200,"headers":{"Content-Type":"text/json; charset=utf-8"},"multiValueHeaders":null,"body":"{\"message\":\"Hello World!\",\"at\":\"2020-09-26T09:35:12Z\"}"}%測試 API Gateway ( 使用前面 output 的 url )
curl 'https://k09e1wi32e.execute-api.ap-northeast-1.amazonaws.com/v1/hello'
{"message":"Hello World!","at":"2024-01-02T09:44:37Z"}% -
terraform destroy 刪除所有基礎架構