CloudFormation이 람다 함수, API Gateway, DynamoDB를 배포한다.
CLI Debugging
AWS SAM 템플릿을 사용하여 정의된 서버리스 애플리케이션을 로컬에서 구축, 테스트 및 디버깅할 수 있다.
로컬에서 람다 함수 실행 환경을 제공한다.
SAM CLI + AWS Toolkits를 통해서 코드 단계별 실행 및 디버깅을 할 수 있다.
AWS Cloud9, VS Code, JetBrains, PyCharm, IntelliJ 등을 지원한다.
AWS Toolkits: AWS SAM을 사용하여 구축된 람다 함수를 구축, 테스트, 디버깅, 배포 및 호출할 수 있는 IDE 플러그인이다.
CodeDeploy 연동
SAM 프레임워크는 기본적으로 CodeDeploy를 사용하여 람다 함수를 업데이트한다.
트래픽 시프트를 지원한다.
배포를 검증하기 위한 사전 및 사후 트래픽 후크를 사용할 수 있다.
트래픽 이동 시작 전과 종료 후에 검증한다.
CloudWatch 경보를 사용한 쉽고 자동화된 롤백을 지원한다.
람다 별칭에 v1 람다 함수가 있다.
CodeDeploy 배포를 트리거해 별칭을 v2로 업데이트해야 한다.
CodeDeploy에서 선택 사항인 사전 트래픽 후크 테스트로 다른 람다 함수를 사용한다.
별칭으로 트래픽 시프트를 수행한다.
선택적으로 CloudWatch 알람을 모니터링해 배포 과정에 문제가 없는지 확인한다.
선택적으로 배포가 완료되면 사후 트래픽 후크 람다 함수를 실행할 수 있다.
배포가 완료되면 별칭에서 v1 람다 함수는 제거된다.
YAML
AutoPublishAlias
새 코드가 배포되는 시기를 감지한다.
최신 코드로 해당 함수의 업데이트된 버전을 생성하고 게시한다.
별칭이 업데이트된 버전의 람다 함수를 가리킨다.
DeploymentPreference
Canary, Linear, AllAtOnce 중에 선택할 수 있다.
Alarms
롤백을 실행할 수 있는 경보다.
Hooks
배포 테스트를 위한 사전 및 사후 트래픽 시프트 람다 함수를 지정한다.
AWS Cloud Development Kit (CDK)
친숙한 언어를 사용하여 클라우드 인프라를 정의한다.
Javascript, Typescript, Python, Java, .NET
코드는 CloudFormation 템플릿(JSON/YAML)으로 컴파일된다.
인프라와 애플리케이션 런타임 코드를 함께 배포할 수 있다.
람다 함수에 적합하다.
ECS/EKS의 도커 컨테이너에 적합하다.
Example
예시에서는 Javascript가 사용되고 있다.
정의된 VPC와 ECS 클러스터와 Fargate 서비스와 함께 ALB가 정의되어 있다.
세 가지 서비스는 CDK CLI에 의해 컴파일되어 CloudFormation 템플릿에 사용되고 업로드 및 배포할 수 있다.
CDK vs SAM
SAM
서버리스 중심이다.
JSON 또는 YAML로 템플릿을 선언적으로 작성한다.
람다를 빠르게 시작하는데 적합하다.
CloudFormation을 사용한다.
CDK
모든 AWS 서비스를 지원한다.
프로그래밍 언어 JavaScript/TypeScript, Python, Java 및 .NET으로 인프라를 구축한다.
CloudFormation을 활용할 수 있다.
CDK + SAM
SAM CLI를 사용하여 CDK 앱을 로컬에서 테스트할 수 있다.
먼저 cdk synth를 실행해야 한다.
CDK 애플리케이션의 람다 함수에 cdk synth 명령어를 실행하면 CDK에 통합된 CloudFormation 템플릿이 생성된다.
CloudFormation 템플릿으로 SAM 프레임워크를 사용해 SAM을 로컬에서 호출해 CloudFormation 템플릿으로 함수를 호출할 수 있다.
실습
CDK로 S3 버킷을 생성하고 람다 함수로 Rekognition을 호출하고 DynamoDB 테이블에 작업의 결과를 저장하는데 전부 CDK를 사용할 수 있다.
CloudTrail을 준비하여 CDK에서 step.sh를 실행하여 명령어를 실행할 준비를 한다.
step.sh 파일은 아래와 같다.
# 1. install the CDK
sudo npm install -g aws-cdk
# directory name must be cdk-app/ to go with the rest of the tutorial, changing it will cause an error
mkdir cdk-app
cd cdk-app/
# initialize the application
cdk init --language javascript
# verify it works correctly
cdk ls
# install the necessary packages
npm install @aws-cdk/aws-s3 @aws-cdk/aws-iam @aws-cdk/aws-lambda @aws-cdk/aws-lambda-event-sources @aws-cdk/aws-dynamodb
# 2. copy the content of cdk-app-stack.js into lib/cdk-app-stack.js
# 3. setup the Lambda function
mkdir lambda && touch index.py
# 4. bootstrap the CDK application
cdk bootstrap
# 5. (optional) synthesize as a CloudFormation template
cdk synth
# 6. deploy the CDK stack
cdk deploy
# 7. empty the s3 bucket
# 8. destroy the stack
cdk destroy
sudo npm install -g aws-cdk 명령을 통해서 aws-cdk-lib를 설치한다.
mkdir cdk-app 명령을 통해서 cdk-app 디렉토리를 생성할 수 있다.
javascript를 사용하기 위해 cdk init --language javascript 명령을 실행한다.
정상적으로 초기화가 완료되었다면 cdk ls 명령어가 CdkAppStack을 반환해야 한다.
cdk-app-stack.js 파일은 아래와 같다.
const cdk = require("@aws-cdk/core");
const s3 = require("@aws-cdk/aws-s3");
const iam = require("@aws-cdk/aws-iam");
const lambda = require("@aws-cdk/aws-lambda");
const lambdaEventSource = require("@aws-cdk/aws-lambda-event-sources");
const dynamodb = require("@aws-cdk/aws-dynamodb");
const imageBucket = "cdk-rekn-imagebucket";
class CdkAppStack extends cdk.Stack {
/**
*
* @param {cdk.Construct} scope
* @param {string} id
* @param {cdk.StackProps=} props
*/
constructor(scope, id, props) {
super(scope, id, props);
// The code that defines your stack goes here
// ========================================
// Bucket for storing images
// ========================================
const bucket = new s3.Bucket(this, imageBucket, {
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
new cdk.CfnOutput(this, "Bucket", { value: bucket.bucketName });
// ========================================
// Role for AWS Lambda
// ========================================
const role = new iam.Role(this, "cdk-rekn-lambdarole", {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
});
role.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
"rekognition:*",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
],
resources: ["*"],
})
);
// ========================================
// DynamoDB table for storing image labels
// ========================================
const table = new dynamodb.Table(this, "cdk-rekn-imagetable", {
partitionKey: { name: "Image", type: dynamodb.AttributeType.STRING },
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
new cdk.CfnOutput(this, "Table", { value: table.tableName });
// ========================================
// AWS Lambda function
// ========================================
const lambdaFn = new lambda.Function(this, "cdk-rekn-function", {
code: lambda.AssetCode.fromAsset("lambda"),
runtime: lambda.Runtime.PYTHON_3_8,
handler: "index.handler",
role: role,
environment: {
TABLE: table.tableName,
BUCKET: bucket.bucketName,
},
});
lambdaFn.addEventSource(
new lambdaEventSource.S3EventSource(bucket, {
events: [s3.EventType.OBJECT_CREATED],
})
);
bucket.grantReadWrite(lambdaFn);
table.grantFullAccess(lambdaFn);
}
}
module.exports = { CdkAppStack };
S3 버킷, 람다를 위한 역할, DynamoDB, 람다 함수를 생성하고 있다.
아래는 index.py 파일이다.
#
# Lambda function detect labels in image using Amazon Rekognition
#
from __future__ import print_function
import boto3
import json
import os
from boto3.dynamodb.conditions import Key, Attr
minCofidence = 60
def handler(event, context):
for record in event['Records']:
bucket = record['s3']['bucket']['name']
key = record['s3']['object']['key']
rekFunction(bucket, key)
def rekFunction(bucket, key):
print("Detected the following image in S3")
print("Bucket: " + bucket + " key name: " + key)
client = boto3.client("rekognition")
response = client.detect_labels(Image={"S3Object": {"Bucket": bucket, "Name": key}},
MaxLabels=10, MinConfidence=minCofidence)
# Get the service resource
dynamodb = boto3.resource("dynamodb")
# Instantiate a table resource object
imageLabelsTable = os.environ["TABLE"]
table = dynamodb.Table(imageLabelsTable)
# Put item into table
table.put_item(
Item={"Image": key}
)
objectsDetected = []
for label in response["Labels"]:
newItem = label["Name"]
objectsDetected.append(newItem)
objectNum = len(objectsDetected)
itemAtt = f"object{objectNum}"
response = table.update_item(
Key={"Image": key},
UpdateExpression=f"set {itemAtt} = :r",
ExpressionAttributeValues={":r": f"{newItem}"},
ReturnValues="UPDATED_NEW"
)
AWS Step Functions
워크플로를 "State Machine"으로 모델링한다.
워크플로 하나당 "State Machine"을 생성해야 한다.
주문 이행, 데이터 처리 등에 사용된다.
웹 애플리케이션 등 모든 워크플로를 지원한다.
JSON으로 작성된다.
워크플로 시각화 및 워크플로 실행, 이력을 제공한다.
SDK 호출, API 게이트웨이, EventBridge(CloudWatch 이벤트)로 워크플로를 시작할 수 있다.