티스토리 뷰

2020년 말, AWS Lambda의 새로운 기능으로 컨테이너 이미지 지원이 발표되었다. 기존 lambda 의 프로비저닝에 비해 얻을 수 있는 이점을 요약하자면 다음과 같다.

 

- 최대 10GB 크기의 컨테이너 이미지로 패키징 및 배포할 수 있는 기능 제공

- Dependencies 관리 및 설치의 용이성

- 다른 linux distro 의 이미지에서도 사용 가능함. (다만, 좀 까다로움. aws lambdaric 를 설치해야함.)

 

나는 Dependencies 설치가 쉽다는 점 하나만으로 docker 이미지를 사용할만한 가치가 있다고 생각한다. 

Boilerplate

 

byunjuneseok/container-image-lambda-boilerplate

Deploy python lambda functions with container images easily with pre-written IaC script. - byunjuneseok/container-image-lambda-boilerplate

github.com

한줄요약 : 🪄 작성된 스크립트만 잘 실행시켜주면 컨테이너 이미지 빌드부터, ECR 등록, Lambda 및 API GW 배포까지 다 해줘요.

(커스터마이징도 쉬울걸요..?)

 

지금까지 lambda의 프로비저닝 자동화 경험으로는 amazon-linux2 이미지의 VM을 띄워놓고, 그 VM 안에서 빌드 및 프로비저닝을 해왔다. (golang이라면 이럴 필요까지야 없겠지만.) M1 Macbook의 업무 개발 환경으로 넘어오면서 OS에 의존적이지 않은 Lambda 의 프로비저닝이 필요했는데, 이를 해결하기 위해서 위와 같은 보일러플레이트를 만들었다.

PoC 의 개념으로 시작한 보일러플레이트인데, 생각보다 쓸만한 것 같다. 로컬에서 의존성 설치하고 압축해서 프로비저닝하는 것 보다 좋은 것 같다. 로컬머신과 독립된 도커 이미지에서 빌드하기 때문에 완벽히 멱등성(Idempotent)을 확보할 수 있다.

 

00-login-ecr.sh

aws ecr get-login-password --region "$AWS_REGION" \
  | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID".dkr.ecr."$AWS_REGION".amazonaws.com

AWS ECR 에 로그인하여, 토큰을 받아와 docker 로그인하는 쉘스크립트다. 여기서 토큰은 12시간동안만 유효함을 참고한다.

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html

 

01-create-ecr-repository.sh

aws ecr create-repository --repository-name "$SERVICE_NAME"

AWS ECR repository를 만드는 쉘 스크립트다.

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html

 

02-create-ecr-repository.sh

docker build -t "$SERVICE_NAME".
docker tag "$SERVICE_NAME":latest "$AWS_ACCOUNT_ID".dkr.ecr."$AWS_REGION".amazonaws.com/"$SERVICE_NAME":latest
docker push "$AWS_ACCOUNT_ID".dkr.ecr."$AWS_REGION".amazonaws.com/"$SERVICE_NAME":latest

Docker 빌드를 하여 tag 후 ECR 에 Push 하는 스크립트다.

 

03-create-iam-for-lambda.sh

람다를 위한 iam role 을 만든다.

aws iam create-role --role-name "$LAMBDA_ROLE_NAME" --assume-role-policy-document file://iam/role.json
aws iam put-role-policy --role-name "$LAMBDA_ROLE_NAME" --policy-name "$LAMBDA_ROLE_NAME"-policy --policy-document file://iam/policy.json

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-role.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/put-role-policy.html

 

 

04-deploy-to-lambda.py

람다 함수를 만드는 스크립트다. `--code ImageUri` 플래그를 볼 수 있는데, ECR 이미지를 이용하여 람다를 프로비저닝한다. 람다를 만드는데 드는 시간이 거의 들지 않아 깜짝 놀랬다.

aws lambda create-function \
    --role arn:aws:iam::"$AWS_ACCOUNT_ID":role/"$LAMBDA_ROLE_NAME" \
    --function-name "$SERVICE_NAME" \
    --package-type Image \
    --code ImageUri="$AWS_ACCOUNT_ID".dkr.ecr."$AWS_REGION".amazonaws.com/"$SERVICE_NAME":latest

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html

 

 

05-create-api-gateway.py

이 스크립트는 꽤 길다. API Gateway 를 프로비저닝하고 이 API에 리소스를 추가한 뒤, 이 리소스에 메소드를 추가하고, API 스테이지를 만든 후 배포시키는 최종 스크립트다. 스크립트는 길지만 읽기는 어렵지 않을 것이다. 늘상 써오던 방식이지만, python 의 subprocess를 열어 실행시킨다. aws cli 를 여러번 호출하고 있다. python을 쓰는 이유는 여러 리소스들의 id같은 것들을 가지고 있다가 계속 사용해야하기 때문이다.

#! /usr/bin/python3
import common

import os

stage_name = os.getenv('STAGE')
service_name = os.getenv('SERVICE_NAME')
aws_account_id = os.getenv('AWS_ACCOUNT_ID')
aws_region = os.getenv('AWS_REGION')
apigateway_http_method = os.getenv('APIGATEWAY_HTTP_METHOD')
apigateway_authorization_type = os.getenv('APIGATEWAY_AUTHORIZATION_TYPE')

cmd = [
    'aws', 'apigateway', 'create-rest-api', '--name', service_name, '--region', aws_region
]
result = common.run_cli(cmd)
apigateway_id = result.get('id')

cmd = [
    'aws', 'apigateway', 'get-resources', '--rest-api-id', apigateway_id, '--region', aws_region
]
result = common.run_cli(cmd)
resources = result.get('items')
root_resource_id = resources[0]['id']

cmd = [
    'aws', 'apigateway', 'create-resource', '--rest-api-id', apigateway_id, '--region', aws_region,
    '--parent-id', root_resource_id, '--path-part', '{proxy+}'
]
result = common.run_cli(cmd)
resource_id = result.get('id')

cmd = [
    'aws', 'apigateway', 'put-method', '--rest-api-id', apigateway_id, '--region', aws_region,
    '--resource-id', resource_id, '--http-method', apigateway_http_method, 
    '--authorization-type', apigateway_authorization_type
]
result = common.run_cli(cmd)

cmd = [
    'aws', 'apigateway', 'put-method-response', '--rest-api-id', apigateway_id, '--region', aws_region,
    '--resource-id', resource_id, '--http-method', apigateway_http_method, 
    '--status-code', '200'
]
result = common.run_cli(cmd)

lambda_arn = f'arn:aws:lambda:{aws_region}:{aws_account_id}:function:{service_name}'

cmd = [
    'aws', 'apigateway', 'put-integration', '--rest-api-id', apigateway_id, '--region', aws_region, 
    '--resource-id', resource_id, '--http-method', apigateway_http_method, '--type', 'AWS', '--integration-http-method', apigateway_http_method,
    '--uri', f'arn:aws:apigateway:{aws_region}:lambda:path/2015-03-31/functions/{lambda_arn}/invocations'
]
result = common.run_cli(cmd)

cmd = [
    'aws', 'apigateway', 'put-integration-response', '--rest-api-id', apigateway_id, '--region', aws_region, 
    '--resource-id', resource_id, '--http-method', apigateway_http_method, '--selection-pattern',  '', '--status-code', '200'
]
result = common.run_cli(cmd)

cmd = [
    'aws', 'lambda', 'add-permission', '--function-name', service_name, '--source-arn', f'arn:aws:execute-api:{aws_region}:{aws_account_id}:{apigateway_id}/*/{apigateway_http_method}/*',
    '--principal', 'apigateway.amazonaws.com', '--action', 'lambda:InvokeFunction', '--statement-id', f'invoke{apigateway_id}'
]
result = common.run_cli(cmd)

cmd = [
    'aws', 'apigateway', 'create-deployment', '--rest-api-id', apigateway_id, '--stage-name', stage_name
]
result = common.run_cli(cmd)


print('#' * 80)
print(f'https://{apigateway_id}.execute-api.ap-northeast-2.amazonaws.com/{stage_name}')
print('#' * 80)

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/create-rest-api.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/get-resources.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/create-resource.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/put-method.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/put-method-response.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/put-integration.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/put-integration-response.html

- https://awscli.amazonaws.com/v2/documentation/api/latest/reference/apigateway/create-deployment.html

 

10-update-function.sh

코드와 이미지를 수정하고나서 람다에 반영시키기 위한 스크립트다. 위에서 했던 설명의 반복정도다.

docker build -t "$SERVICE_NAME" .
docker tag "$SERVICE_NAME":latest "$AWS_ACCOUNT_ID".dkr.ecr."$AWS_REGION".amazonaws.com/"$SERVICE_NAME":latest
docker push "$AWS_ACCOUNT_ID".dkr.ecr."$AWS_REGION".amazonaws.com/"$SERVICE_NAME":latest

aws lambda update-function-code \
    --function-name "$SERVICE_NAME" \
    --image-uri "$AWS_ACCOUNT_ID".dkr.ecr."$AWS_REGION".amazonaws.com/"$SERVICE_NAME":latest

 

번외편; 삽질 - 완전 다른 Linux distro 이미지로 해보려다가...

https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html

 

Lambda Extensions API - AWS Lambda

Lambda Extensions API Lambda function authors use extensions to integrate Lambda with their preferred tools for monitoring, observability, security, and governance. Function authors can use extensions from AWS, AWS Partners, and open-source projects. For m

docs.aws.amazon.com

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함