[P7] Xây Dựng Ứng Dụng Serverless với AWS CDK: DynamoDB và Lambda Function
Trong bài hướng dẫn này, chúng ta sẽ tìm hiểu cách sử dụng AWS CDK để xây dựng một ứng dụng serverless đơn giản. Ứng dụng này bao gồm một DynamoDB table để lưu trữ thông tin sản phẩm và một Lambda function để truy xuất dữ liệu thông qua Function URL.
Ứng dụng của chúng ta sẽ có các thành phần sau:
mkdir serverless_app
cd serverless_app
cdk init app --language python
python3 -m pip install --upgrade pip
pip install -r requirements.txt
from aws_cdk import (
aws_dynamodb as dynamodb,
RemovalPolicy
)
products_table = dynamodb.Table(
self, 'ProductsTable',
partition_key=dynamodb.Attribute(
name='id',
type=dynamodb.AttributeType.STRING
),
billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
removal_policy=RemovalPolicy.DESTROY
)
Giải thích các thành phần:
partition_key
: Định nghĩa khóa chính của table là trường ‘id’ kiểu STRINGbilling_mode
: Sử dụng PAY_PER_REQUEST để chỉ trả phí khi có requestremoval_policy
: Cấu hình xóa table khi destroy stackserverless_app/
├── lambda_src/
│ └── product_list_function.py
└── serverless_app/
└── serverless_app_stack.py
# lambda_src/product_list_function.py
import json
import os
import logging
import boto3 # AWS Python SDK
# Configure logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# Initialize the DynamoDB client
dynamodb_client = boto3.client('dynamodb')
def lambda_handler(event, context):
'''
Returns all products from the DynamoDB table provided.
Environment variables:
- TABLE_NAME: The name of the DynamoDB table scanned.
'''
logger.info(f"Received event: {json.dumps(event, indent=2)}")
# Scan the DynamoDB table to get all products
products = dynamodb_client.scan(
TableName=os.environ['TABLE_NAME']
)
return {
"statusCode": 200,
"body": json.dumps(products['Items'])
}
product_list_function = lambda_.Function(
self, 'ProductListFunction',
code=lambda_.Code.from_asset('lambda_src'),
handler='product_list_function.lambda_handler',
runtime=lambda_.Runtime.PYTHON_3_10,
environment={
'TABLE_NAME': products_table.table_name
}
)
# Thêm Function URL
product_list_url = product_list_function.add_function_url(
auth_type=lambda_.FunctionUrlAuthType.NONE
)
Giải thích các tham số:
code
: Trỏ đến thư mục chứa code Lambdahandler
: Định nghĩa entry point của functionruntime
: Chọn môi trường runtime Python 3.10environment
: Truyền tên table qua biến môi trườngauth_type
: Cấu hình Function URL không yêu cầu xác thựccdk deploy
Sau khi deploy, bạn có thể:
Truy cập Lambda Url trả về lỗi:
Vì chưa cấp quyền cho lambda đọc dữ liệu từ dynamoDB (xem ở cloudwwatch):
L2 Constructs trong AWS CDK cung cấp các methods bắt đầu bằng “grant” để đơn giản hóa việc cấp quyền. Đây là cách hiệu quả để quản lý IAM permissions mà không cần phải định nghĩa chi tiết các IAM roles và policies.
# Ví dụ cấp quyền tùy chỉnh
table.grant(function.role, ['dynamodb:PutItem', 'dynamodb:GetItem'])
# Cấp quyền đọc (scan, query, getItem)
table.grant_read_data(function.role)
# Cấp quyền đọc và ghi
table.grant_read_write_data(function.role)
# Cấp toàn bộ quyền (thận trọng khi sử dụng)
table.grant_full_access(function.role)
Để cho phép Lambda function scan DynamoDB table, chúng ta chỉ cần thêm một dòng code:
# Cấp quyền đọc data từ DynamoDB cho Lambda function
products_table.grant_read_data(product_list_function.role)
Giải thích:
products_table
: DynamoDB table constructgrant_read_data()
: Method cấp quyền đọc dữ liệuproduct_list_function.role
: IAM role của Lambda functionLambda Url Đã truy cập được
Stack Outputs là một tính năng của CloudFormation cho phép bạn:
from aws_cdk import CfnOutput
CfnOutput(self,# scope: stack hiện tại
"ProductListUrl",# id: tên của output
value=product_list_url.url # giá trị của output
)
Các Parameters Quan Trọng của CfnOutput
scope
: Stack mà output thuộc vềid
: Định danh của output (cũng là tên hiển thị trên CloudFormation)value
: Giá trị của outputdescription
: Mô tả về output (tùy chọn)export_name
: Tên export cho cross-stack references (tùy chọn)condition
: Điều kiện để tạo output (khuyến nghị dùng if statement thay thế)Ví Dụ
# Thêm Stack Output cho Function URL
CfnOutput(self,
"ProductListUrl",
value=product_list_url.url,
description="URL endpoint for the product list function"
)
Sau khi deploy, bạn có thể truy cập output theo nhiều cách:
Trong quá trình phát triển serverless application, việc monitoring các Lambda function là một phần không thể thiếu để đảm bảo ứng dụng hoạt động ổn định. Phần này sẽ hướng dẫn bạn cách sử dụng AWS CDK để setup monitoring cho Lambda function thông qua CloudWatch metrics và alarms.
AWS CDK cung cấp nhiều methods để truy cập CloudWatch metrics của Lambda function:
metric()
: Method tổng quát để truy cập bất kỳ metric nàometric_duration()
: Đo thời gian thực thi của functionmetric_errors()
: Đếm số lần function thực thi thất bạimetric_invocations()
: Đếm số lần function được gọimetric_throttles()
: Đếm số lần function bị throttlefrom aws_cdk import aws_cloudwatch as cloudwatch
from aws_cdk import Duration
# Lấy metric về errors của Lambda function
errors_metric = lambda_function.metric_errors(
label="ProductListFunction Errors",
period=Duration.minutes(5),
statistic=cloudwatch.Stats.SUM
)
errors_metric.create_alarm(
self,
"ProductListErrorsAlarm",
evaluation_periods=1,
threshold=1,
comparison_operator=cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
treat_missing_data=cloudwatch.TreatMissingData.IGNORE
)
evaluation_periods
: Số khoảng thời gian để đánh giá điều kiện alarmthreshold
: Ngưỡng để kích hoạt alarmcomparison_operator
: Cách so sánh giá trị metric với thresholdtreat_missing_data
: Cách xử lý khi không có dữ liệutreat_missing_data=cloudwatch.TreatMissingData.IGNORE
nếu function không được gọi thường xuyênVí Dụ
from aws_cdk import (
Stack,
aws_dynamodb as dynamodb,
aws_lambda as lambda_,
CfnOutput,
RemovalPolicy,
Duration,
aws_cloudwatch as cloudwatch,
)
from constructs import Construct
class ServerlessAppStack(Stack):
#...
# Configure metrics to monitor the lambda function
errors_metric = product_list_function.metric_errors(
label="ProductListFunctionErrors",
period=Duration.minutes(5),
statistic=cloudwatch.Stats.SUM,
)
# Create an alarm to monitor the errors metric
errors_metric.create_alarm(
self,
"ProductListErrorsAlarm",
evaluation_periods=1,
threshold=1,
comparison_operator=cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
treat_missing_data=cloudwatch.TreatMissingData.IGNORE,
)
SUM
thay vì AVERAGE
Property Types trong CDK:
Attribute
, BillingMode
)Instance Methods:
add_function_url()
)Permissions:
AWS CDK giúp đơn giản hóa việc tạo và quản lý infrastructure bằng code. Thông qua ví dụ này, chúng ta đã học được: