Lambda에서 메시 서비스 호출하기
Lambda에서 메시 서비스 호출하기 (Mesh services with Lambda)
이 문서는 Consul에 등록된 Lambda 함수에서 메시 안의 서비스를 호출하는 방법을 설명해요. 람다 익스텐션 계층, 람다 레지스트레이터를 배포하고 mTLS로 업그레이드된 트래픽을 메시 게이트웨이로 프록시하는 과정을 단계별로 다룰게요.
출처: 문서
본문
이 문서는 Consul에 등록된 Lambda 함수에서 메시 안의 서비스를 호출하는 방법을 설명합니다.
람다-메시 기능은 현재 베타(Beta)입니다: 베타 기능과 관련된 기능은 변경될 수 있습니다. 베타 릴리즈는 보안 환경이나 프로덕션 시나리오에서 절대 사용하면 안 됩니다. 베타의 기능은 성능 문제, 확장 문제, 제한된 지원이 있을 수 있습니다.
소개 (Introduction)
다음 단계들이 이 과정을 설명합니다:
- 대상 서비스와 메시 게이트웨이를 배포합니다.
- Lambda 익스텐션 계층을 배포합니다.
- Lambda 레지스트레이터를 배포합니다.
- Lambda 함수 코드를 작성합니다.
- Lambda 함수를 배포합니다.
- Lambda 함수를 호출합니다.
Lambda 함수가 메시 서비스에 요청을 보낼 수 있게 하려면 consul-lambda-extension 익스텐션을 Lambda 계층으로 추가해야 합니다. Lambda 함수에 계층을 추가하는 방법은 AWS Lambda 문서를 참조하세요.
이 계층은 사이드카 프록시를 시작하는 외부 Lambda 익스텐션을 실행합니다. 프록시는 각 업스트림 서비스에 대해 하나의 포트에서 수신하고, 나가는 연결을 mTLS로 업그레이드합니다. 그런 다음 요청을 메시 게이트웨이로 프록시합니다.
선행 요구 사항 (Prerequisites)
consul-lambda-extension 계층으로 Lambda 서비스를 배포하기 전에 대상 서비스와 메시 게이트웨이를 먼저 배포해야 합니다.
대상 서비스 배포 (Deploy the destination service)
Consul 서비스 메시에 서비스를 배포하는 방법은 여러 가지가 있습니다. 다음 예제 구성은 Kubernetes의 Consul로 static-server라는 서비스를 배포합니다.
kind: Service
apiVersion: v1
metadata:
# Specifies the service name in Consul.
name: static-server
spec:
selector:
app: static-server
ports:
- protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: static-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: static-server
spec:
replicas: 1
selector:
matchLabels:
app: static-server
template:
metadata:
name: static-server
labels:
app: static-server
annotations:
'consul.hashicorp.com/connect-inject': 'true'
spec:
containers:
- name: static-server
image: hashicorp/http-echo:latest
args:
- -text="hello world"
- -listen=:8080
ports:
- containerPort: 8080
name: http
serviceAccountName: static-server
메시 게이트웨이 배포 (Deploy the mesh gateway)
메시 게이트웨이는 실행 중이어야 하며 Lambda 함수의 Consul 데이터센터에 등록되어 있어야 합니다. 다음 문서와 튜토리얼을 참조하세요:
Lambda 익스텐션 계층 배포 (Deploy the Lambda extension layer)
consul-lambda-extension 익스텐션은 Lambda 함수 실행의 Init 단계 동안 실행됩니다. 익스텐션은 Lambda 레지스트레이터가 AWS Parameter Store에 저장하도록 구성된 데이터를 가져와서 가벼운 TCP 프록시를 만듭니다. 프록시는 CONSUL_SERVICE_UPSTREAMS 환경 변수에 정의된 각 업스트림에 대해 로컬 리스너를 생성합니다.
익스텐션은 함수가 요청을 처리할 수 있도록 주기적으로 AWS Parameter Store에서 데이터를 가져옵니다. Lambda 함수가 종료(shutdown) 이벤트를 받으면 익스텐션도 중지됩니다.
-
releases.hashicorp.com에서
consul-lambda-extension익스텐션을 다운로드하세요:curl -o consul-lambda-extension_<version>_linux_amd64.zip https://releases.hashicorp.com/consul-lambda/<version>/consul-lambda-extension_<version>_linux_amd64.zip -
Lambda 함수와 같은 AWS 리전에 AWS Lambda 계층을 생성합니다. AWS CLI나 AWS Console로 수동으로 만들 수도 있지만 Terraform 사용을 권장합니다.
consul-lambda-extension.tf:resource "aws_lambda_layer_version" "consul_lambda_extension" { layer_name = "consul-lambda-extension" filename = "consul-lambda-extension_<version>_linux_amd64.zip" source_code_hash = filebase64sha256("consul-lambda-extension_<version>_linux_amd64.zip") description = "Consul service mesh extension for AWS Lambda" }
Lambda 레지스트레이터 배포 (Deploy the Lambda registrator)
Lambda 레지스트레이터를 구성하고 배포합니다. 레지스트레이터 구성 문서와 레지스트레이터 배포 문서를 참조하세요.
Lambda 함수 코드 작성 (Write the Lambda function code)
Lambda 함수를 작성하는 방법은 AWS Lambda 문서를 참조하세요. 다음 예제에서 함수는 포트 2345의 업스트림 서비스를 호출합니다:
package main
import (
"context"
"io"
"fmt"
"net/http"
"github.com/aws/aws-lambda-go/lambda"
)
type Response struct {
StatusCode int `json:"statusCode"`
Body string `json:"body"`
}
func HandleRequest(ctx context.Context, _ interface{}) (Response, error) {
resp, err := http.Get("http://localhost:2345")
fmt.Println("Got response", resp)
if err != nil {
return Response{StatusCode: 500, Body: "Something bad happened"}, err
}
if resp.StatusCode != 200 {
return Response{StatusCode: resp.StatusCode, Body: resp.Status}, err
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
return Response{StatusCode: 500, Body: "Error decoding body"}, err
}
return Response{StatusCode: 200, Body: string(b)}, nil
}
func main() {
lambda.Start(HandleRequest)
}
Lambda 함수 배포 (Deploy the Lambda function)
-
Lambda 함수의 역할이 Lambda 익스텐션의 데이터를 AWS Parameter Store에서 가져올 수 있게 하는 IAM 정책을 생성하고 적용합니다. 다음 예제는 Lambda 함수용 IAM 역할을 만들고, 필요한 권한이 있는 IAM 정책을 만든 다음, 정책을 역할에 연결합니다:
lambda-iam-policy.tf:resource "aws_iam_role" "lambda" { name = "lambda-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" "lambda" { name = "lambda-policy" path = "/" description = "IAM policy lambda" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ssm:GetParameter" ], "Resource": "arn:aws:ssm:*:*:parameter${local.this_lambdas_extension_data_path}" } ] } EOF } resource "aws_iam_role_policy_attachment" "lambda" { role = aws_iam_role.lambda.name policy_arn = aws_iam_policy.lambda.arn } -
Lambda 함수를 구성하고 배포합니다. 사용 가능한 모든 옵션에 대한 정보는 Lambda 익스텐션 구성 참조를 확인하세요. Lambda 함수를 배포하는 방법은 여러 가지가 있습니다. 다음 예제는
/lambda_extension_data접두사 아래 저장된 mTLS 데이터를 사용해static-server업스트림 서비스를 호출할 수 있는 함수를 Terraform으로 배포합니다:lambda-function.tf:resource "aws_lambda_function" "example" { … function_name = "lambda" role = aws_iam_role.lambda.arn tags = { "serverless.consul.hashicorp.com/v1alpha1/lambda/enabled" = "true" } variables = { environment = { CONSUL_MESH_GATEWAY_URI = var.mesh_gateway_http_addr CONSUL_SERVICE_UPSTREAMS = "static-server:2345:dc1" CONSUL_EXTENSION_DATA_PREFIX = "/lambda_extension_data" } } layers = [aws_lambda_layer_version.consul_lambda_extension.arn] -
terraform apply명령을 실행하면 Consul이 Lambda 함수에 대한 서비스를 자동으로 구성합니다.
Lambda 익스텐션 구성 (Lambda extension configuration)
Lambda 함수에 다음 환경 변수를 정의해 Lambda 익스텐션을 구성합니다. 변수는 환경의 각 Lambda 함수에 적용됩니다:
| 변수 (Variable) | 설명 (Description) | 기본값 (Default) |
| CONSUL_MESH_GATEWAY_URI | 플러그인이 요청하는 메시 게이트웨이가 실행 중인 URI를 지정합니다. 메시 게이트웨이는 서비스가 실행 중인 것과 같은 Consul 데이터센터·파티션에 등록되어 있어야 합니다. 최적의 성능을 위해 이 메시 게이트웨이는 같은 AWS 리전에서 실행되어야 합니다. | 없음 (none) |
| CONSUL_EXTENSION_DATA_PREFIX | 플러그인이 구성 데이터를 가져오는 접두사를 지정합니다. 데이터는 다음 디렉터리에 있어야 합니다: "${CONSUL_EXTENSION_DATA_PREFIX}/${CONSUL_SERVICE_PARTITION}/${CONSUL_SERVICE_NAMESPACE}/<lambda-function-name>" | 없음 (none) |
| CONSUL_SERVICE_NAMESPACE | 서비스가 등록되는 Consul 네임스페이스를 지정합니다. | default |
| CONSUL_SERVICE_PARTITION | 서비스가 등록되는 Consul 파티션을 지정합니다. | default |
| CONSUL_REFRESH_FREQUENCY | 익스텐션이 Parameter Store에서 데이터를 다시 가져오기 전에 기다리는 시간을 지정합니다. Go time.Duration 문자열 값(예: "30s")을 사용하세요. 이 시간은 Lambda 레지스트레이터 sync_frequency_in_minutes 구성에 설정된 지속 시간에 더해집니다. Lambda 레지스트레이터 구성 옵션을 참조하세요. 두 구성의 조합이 데이터가 얼마나 오래될 수 있는지 결정합니다. Lambda 함수는 최대 14시간 실행될 수 있으므로 인증서에 대해 허용 가능한 오래됨(staleness)을 가져오는 값을 구성하는 것을 권장합니다. | "5m" |
| CONSUL_SERVICE_UPSTREAMS | Lambda 함수가 호출할 수 있는 쉼표로 구분된 업스트림 서비스 목록을 지정합니다. Kubernetes의 Consul에서 consul.hashicorp.com/connect-service-upstreams 어노테이션 형식에 따라 라벨이 없는 어노테이션으로 값(예: "[service-name]:[port]:[optional-datacenter]")을 지정하세요. | 없음 (none) |
Lambda 함수 호출 (Invoke the Lambda function)
Consul 서비스 메시에서 의도(intentions) 가 활성화되어 있다면, Lambda 함수를 호출하기 전에 Lambda 함수의 Consul 서비스가 모든 업스트림 서비스를 호출할 수 있게 하는 의도를 만들어야 합니다. 추가 정보는 서비스 메시 의도를 참조하세요.
Lambda 함수를 호출하는 방법은 여러 가지가 있습니다. 다음 예제는 aws lambda invoke CLI 명령으로 함수를 호출합니다:
$ aws lambda invoke --function-name lambda /dev/stdout | cat