Apex+Terraform으로 서버리스 아키텍처 전체 코드화
16745 단어 람다APIGatewayTerraformApexAWS
다만, 최근에는 성능이 그다지 요구되지 않는 배치 처리나 API등은 서버리스 아키텍쳐를 채용하는 것이 많아져 왔습니다.
하지만 람다 함수 코드 자체의 배포를 Terraform에 맡기는 것이 힘들기 때문에,
Lambda의 배포는 개발 팀이 사용했던 Serverless Framework로 나뉩니다.
이것에는 큰 과제가 있었고,
Terraformで作ったS3のイベントをトリガーにするLambdaファンクションを作りたい
, 같은, 나중에 Lambda를 추가하는 요건에 대응하지 못하고 고민하고 있었습니다.그럴 때
Apex
는 Terraform을 Wrap 할 수 있다고 하늘에서 목소리가 내려 왔기 때문에 시도해보기로했습니다.검증에 이용한 환경
※ 당 엔트리는 Apex 나 Terraform 도입에 대해서는 언급하지 않습니다
만드는 환경
Lambda에서 사용하는 IAM Role과 API Gateway는 Terraform에 관리를 맡기고 Lambda 자체는 Apex에 관리합니다.
파일 구성
./project.json # プロジェクト全体の定義(たぶんfunction.jsonで設定を上書きできる気がする)
./functions/hello/function.json # 関数の定義
./functions/hello/hello.py # Lambdaで実行するコード(別にPythonじゃなくてもOK)
./infrastructure/main.tf # Terraformで管理するAWSリソースの定義
. /p 로지ぇct. j 그런
어쩌면 프로젝트 전체의 공통 설정을 기재하는 느낌이라고 생각합니다.
죄송합니다, 제대로 조사하지 않았습니다. . .
{
"name": "apex-sample",
"description": "apex test 20190405",
"memory": 128,
"timeout": 5,
"role": "arn:aws:iam::{各自のAWS Account ID}:role/apex_sample",
"environment": {}
}
. / 훙 c 치온 s / 헵 / 훙 c 치온. j 그런
사용할 runtime과 함수 이름을 정의합니다.runtime
와 handler
만약 제대로 하면 최소한은 괜찮다고 생각합니다.
{
"description": "hello",
"runtime": "python3.6",
"handler": "hello.lambda_handler",
"environment":
{
"ENV": "dev"
}
}
. / 훙 c 치온 s / 헵 / 헉. py
hello world
를 응답 본문으로 반환하기만 하면 됩니다.
최저한 API Gateway의 사양에 준거한 응답을 돌려주면 괜찮습니다.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def lambda_handler(event, context):
json = {"statusCode": 200, "body": "hello world"}
return json
. / 인 f 들 st 하는 c 얽힌 / 마인. tf
완전히 Terraform 코드입니다.
귀찮은 느낌에 1 파일로 정리 버렸습니다만, module화하거나 하는 편이 관리는 하기 쉽다고 생각합니다.variable "apex_function_hello" {}
에서 apex에서 변수를 받는 것이 포인트입니다.
정의한 리소스는 IAM Role과 API Gateway뿐입니다.
provider "aws" {
region = "ap-northeast-1"
}
terraform {
backend "s3" {
bucket = "apex-test-bucket"
key = "apex/test20190404/terraform.tfstate"
region = "ap-northeast-1"
}
}
variable "apex_function_hello" {}
data "aws_region" "current" {}
data "aws_iam_policy_document" "lambda" {
version = "2012-10-17"
statement {
actions = [
"logs:*"
]
resources = [
"*"
]
effect = "Allow"
}
}
resource "aws_iam_policy" "policy" {
name = "apex_sample"
path = "/"
policy = "${data.aws_iam_policy_document.lambda.json}"
}
resource "aws_iam_role" "lambda" {
name = "apex_sample"
description = ""
assume_role_policy = <<EOF
{
"Version":"2012-10-17",
"Statement":
[
{
"Effect":"Allow",
"Principal":
{
"Service":"lambda.amazonaws.com"
},
"Action":"sts:AssumeRole"
}
]
}
EOF
force_detach_policies = false
path = "/"
max_session_duration = 3600
}
resource "aws_iam_role_policy_attachment" "lambda" {
role = "${aws_iam_role.lambda.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
resource "aws_api_gateway_rest_api" "rest_api" {
name = "apex_sample"
description = "Created by AWS Lambda"
endpoint_configuration {
types = ["REGIONAL"]
}
minimum_compression_size = -1
api_key_source = "HEADER"
}
resource "aws_api_gateway_resource" "proxy" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
parent_id = "${aws_api_gateway_rest_api.rest_api.root_resource_id}"
path_part = "{proxy+}"
}
resource "aws_api_gateway_method" "proxy" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.proxy.id}"
http_method = "ANY"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "lambda" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_method.proxy.resource_id}"
http_method = "${aws_api_gateway_method.proxy.http_method}"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "arn:aws:apigateway:${data.aws_region.current.name}:lambda:path/2015-03-31/functions/${var.apex_function_hello}/invocations"
}
resource "aws_api_gateway_deployment" "apigw" {
depends_on = [
"aws_api_gateway_integration.lambda",
]
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
stage_name = "default"
}
resource "aws_lambda_permission" "apigw" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = "${var.apex_function_hello}"
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_deployment.apigw.execution_arn}/*/*"
}
output "base_url" {
value = "${aws_api_gateway_deployment.apigw.invoke_url}"
}
배포
환경 변수 설정
$ export AWS_ACCESS_KEY_ID=hogehoge
$ export AWS_SECRET_ACCESS_KEY=piyopiyo
$ export AWS_DEFAULT_REGION=ap-northeast-1
$ export AWS_REGION=ap-northeast-1
Terraform 백엔드 초기화
$ apex infra init
※ apex infra
커멘드가 terraform 커멘드를 wrap 해 주는 것 같습니다.
IAM Role 배포
API Gateway를 배포하려면 Lambda가 필요하며 Lambda를 배포하려면 IAM Role이 필요합니다.
그래서 먼저 IAM Role만 배포합니다.
$ apex infra apply -target aws_iam_policy.policy -target aws_iam_role.lambda -target aws_iam_role_policy_attachment.lambda
즉시 var.apex_function_hello
값을 입력하라는 메시지가 표시되지만 IAM Role에서는 특별히 사용하지 않으므로 적절하게 입력하여 Enter합니다.
Lambda 배포
$ apex deploy
• creating function env= function=hello
• created alias current env= function=hello version=1
• function created env= function=hello name=apex-sample_hello version=1
나머지 AWS 리소스 배포
$ apex infra apply
여기에서는 Lambda 함수가 배포되었으므로 var.apex_function_hello
의 값을 듣지 못합니다.
동작 확인
이제 모든 리소스를 배포할 수 있었기 때문에 동작을 확인해 보겠습니다.
$ curl https://budfnr6xp6.execute-api.ap-northeast-1.amazonaws.com/default/apex-sample_hello
hello world
제대로 응답이 돌아왔습니다.
이것이라면 Terraform의 코드를 만들어 내면 VPC에 의존하는 리소스 등과의 공존도 가능하게 될 것 같네요.
후 정리 (환경 파기)
$ apex infra destroy
$ apex delete
각각 프롬프트에서는 yes
라고 대답하면 OK.
참고로 한 사이트
./project.json # プロジェクト全体の定義(たぶんfunction.jsonで設定を上書きできる気がする)
./functions/hello/function.json # 関数の定義
./functions/hello/hello.py # Lambdaで実行するコード(別にPythonじゃなくてもOK)
./infrastructure/main.tf # Terraformで管理するAWSリソースの定義
. /p 로지ぇct. j 그런
어쩌면 프로젝트 전체의 공통 설정을 기재하는 느낌이라고 생각합니다.
죄송합니다, 제대로 조사하지 않았습니다. . .
{
"name": "apex-sample",
"description": "apex test 20190405",
"memory": 128,
"timeout": 5,
"role": "arn:aws:iam::{各自のAWS Account ID}:role/apex_sample",
"environment": {}
}
. / 훙 c 치온 s / 헵 / 훙 c 치온. j 그런
사용할 runtime과 함수 이름을 정의합니다.
runtime
와 handler
만약 제대로 하면 최소한은 괜찮다고 생각합니다.{
"description": "hello",
"runtime": "python3.6",
"handler": "hello.lambda_handler",
"environment":
{
"ENV": "dev"
}
}
. / 훙 c 치온 s / 헵 / 헉. py
hello world
를 응답 본문으로 반환하기만 하면 됩니다.최저한 API Gateway의 사양에 준거한 응답을 돌려주면 괜찮습니다.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def lambda_handler(event, context):
json = {"statusCode": 200, "body": "hello world"}
return json
. / 인 f 들 st 하는 c 얽힌 / 마인. tf
완전히 Terraform 코드입니다.
귀찮은 느낌에 1 파일로 정리 버렸습니다만, module화하거나 하는 편이 관리는 하기 쉽다고 생각합니다.
variable "apex_function_hello" {}
에서 apex에서 변수를 받는 것이 포인트입니다.정의한 리소스는 IAM Role과 API Gateway뿐입니다.
provider "aws" {
region = "ap-northeast-1"
}
terraform {
backend "s3" {
bucket = "apex-test-bucket"
key = "apex/test20190404/terraform.tfstate"
region = "ap-northeast-1"
}
}
variable "apex_function_hello" {}
data "aws_region" "current" {}
data "aws_iam_policy_document" "lambda" {
version = "2012-10-17"
statement {
actions = [
"logs:*"
]
resources = [
"*"
]
effect = "Allow"
}
}
resource "aws_iam_policy" "policy" {
name = "apex_sample"
path = "/"
policy = "${data.aws_iam_policy_document.lambda.json}"
}
resource "aws_iam_role" "lambda" {
name = "apex_sample"
description = ""
assume_role_policy = <<EOF
{
"Version":"2012-10-17",
"Statement":
[
{
"Effect":"Allow",
"Principal":
{
"Service":"lambda.amazonaws.com"
},
"Action":"sts:AssumeRole"
}
]
}
EOF
force_detach_policies = false
path = "/"
max_session_duration = 3600
}
resource "aws_iam_role_policy_attachment" "lambda" {
role = "${aws_iam_role.lambda.name}"
policy_arn = "${aws_iam_policy.policy.arn}"
}
resource "aws_api_gateway_rest_api" "rest_api" {
name = "apex_sample"
description = "Created by AWS Lambda"
endpoint_configuration {
types = ["REGIONAL"]
}
minimum_compression_size = -1
api_key_source = "HEADER"
}
resource "aws_api_gateway_resource" "proxy" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
parent_id = "${aws_api_gateway_rest_api.rest_api.root_resource_id}"
path_part = "{proxy+}"
}
resource "aws_api_gateway_method" "proxy" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.proxy.id}"
http_method = "ANY"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "lambda" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_method.proxy.resource_id}"
http_method = "${aws_api_gateway_method.proxy.http_method}"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "arn:aws:apigateway:${data.aws_region.current.name}:lambda:path/2015-03-31/functions/${var.apex_function_hello}/invocations"
}
resource "aws_api_gateway_deployment" "apigw" {
depends_on = [
"aws_api_gateway_integration.lambda",
]
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
stage_name = "default"
}
resource "aws_lambda_permission" "apigw" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = "${var.apex_function_hello}"
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_deployment.apigw.execution_arn}/*/*"
}
output "base_url" {
value = "${aws_api_gateway_deployment.apigw.invoke_url}"
}
배포
환경 변수 설정
$ export AWS_ACCESS_KEY_ID=hogehoge
$ export AWS_SECRET_ACCESS_KEY=piyopiyo
$ export AWS_DEFAULT_REGION=ap-northeast-1
$ export AWS_REGION=ap-northeast-1
Terraform 백엔드 초기화
$ apex infra init
※ apex infra
커멘드가 terraform 커멘드를 wrap 해 주는 것 같습니다.
IAM Role 배포
API Gateway를 배포하려면 Lambda가 필요하며 Lambda를 배포하려면 IAM Role이 필요합니다.
그래서 먼저 IAM Role만 배포합니다.
$ apex infra apply -target aws_iam_policy.policy -target aws_iam_role.lambda -target aws_iam_role_policy_attachment.lambda
즉시 var.apex_function_hello
값을 입력하라는 메시지가 표시되지만 IAM Role에서는 특별히 사용하지 않으므로 적절하게 입력하여 Enter합니다.
Lambda 배포
$ apex deploy
• creating function env= function=hello
• created alias current env= function=hello version=1
• function created env= function=hello name=apex-sample_hello version=1
나머지 AWS 리소스 배포
$ apex infra apply
여기에서는 Lambda 함수가 배포되었으므로 var.apex_function_hello
의 값을 듣지 못합니다.
동작 확인
이제 모든 리소스를 배포할 수 있었기 때문에 동작을 확인해 보겠습니다.
$ curl https://budfnr6xp6.execute-api.ap-northeast-1.amazonaws.com/default/apex-sample_hello
hello world
제대로 응답이 돌아왔습니다.
이것이라면 Terraform의 코드를 만들어 내면 VPC에 의존하는 리소스 등과의 공존도 가능하게 될 것 같네요.
후 정리 (환경 파기)
$ apex infra destroy
$ apex delete
각각 프롬프트에서는 yes
라고 대답하면 OK.
참고로 한 사이트
$ export AWS_ACCESS_KEY_ID=hogehoge
$ export AWS_SECRET_ACCESS_KEY=piyopiyo
$ export AWS_DEFAULT_REGION=ap-northeast-1
$ export AWS_REGION=ap-northeast-1
$ apex infra init
$ apex infra apply -target aws_iam_policy.policy -target aws_iam_role.lambda -target aws_iam_role_policy_attachment.lambda
$ apex deploy
• creating function env= function=hello
• created alias current env= function=hello version=1
• function created env= function=hello name=apex-sample_hello version=1
$ apex infra apply
이제 모든 리소스를 배포할 수 있었기 때문에 동작을 확인해 보겠습니다.
$ curl https://budfnr6xp6.execute-api.ap-northeast-1.amazonaws.com/default/apex-sample_hello
hello world
제대로 응답이 돌아왔습니다.
이것이라면 Terraform의 코드를 만들어 내면 VPC에 의존하는 리소스 등과의 공존도 가능하게 될 것 같네요.
후 정리 (환경 파기)
$ apex infra destroy
$ apex delete
각각 프롬프트에서는 yes
라고 대답하면 OK.
참고로 한 사이트
$ apex infra destroy
$ apex delete
Reference
이 문제에 관하여(Apex+Terraform으로 서버리스 아키텍처 전체 코드화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/tsukapah/items/8e0cf03aff49a3c565f8텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)