[P3] CDK App Lifecycle & Synthesizing: Hiểu sâu về quá trình hoạt động của AWS CDK

Mon, November 11, 2024 - 7 min read View Count
AWS CDK Lifecycle and Synthesis Process

Xem những bài viết cùng series

Giới thiệu

AWS CDK (Cloud Development Kit) có một vòng đời phức tạp để chuyển đổi từ code thành infrastructure thực tế. Hiểu rõ về các giai đoạn này là nền tảng quan trọng để phát triển và debug ứng dụng CDK hiệu quả.

Vòng đời của ứng dụng CDK

AWS CDK Life Cycle

1. Construction Phase (Giai đoạn Khởi tạo)

  • Mục đích : Định nghĩa và cấu hình các resource infrastructure.

  • Hoạt động chính :

    • Khởi tạo tất cả các constructs thông qua phương thức __init__.
    • Thiết lập mối quan hệ giữa các resources (tài nguyên).
    • Định nghĩa các properties (thuộc tính) và configuration (cấu hình).
  • Lưu ý: Phần lớn code CDK được thực thi ở giai đoạn này

Ví dụ về Construction Phase:

# Python
class ApiLambdaConstruct(Construct):
    def __init__(self, scope: Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
 
        # Định nghĩa Lambda Function
        self.handler = _lambda.Function(
            self, 'ApiHandler',
            runtime=_lambda.Runtime.PYTHON_3_9,
            code=_lambda.Code.from_asset('lambda'),
            handler='index.handler',
            environment={
                'ENVIRONMENT': 'dev'
            }
        )
 
        # Định nghĩa API Gateway
        self.api = apigw.RestApi(
            self, 'SampleApi',
            rest_api_name='Sample API',
            description='API for demonstrating CDK lifecycle'
        )
 
        # Tích hợp Lambda với API Gateway
        integration = apigw.LambdaIntegration(self.handler)
        self.api.root.add_method('GET', integration

Thuật ngữ:

  • Resource : Tài nguyên AWS như Lambda Function, S3 Bucket, DynamoDB Table, v.v.
  • Property : Thuộc tính của tài nguyên, như tên, cấu hình runtime, bộ nhớ, v.v.

2. Preparation Phase (Giai đoạn Chuẩn bị)

  • Mục đích : Áp dụng các sửa đổi và xác thực bổ sung trước khi triển khai.
  • Hoạt động chính :
    • Thực thi các phương thức prepare() (nếu có) trong constructs (đối với các phiên bản CDK cũ hơn, phiên bản mới đã loại bỏ prepare())
    • Áp dụng các Aspects để duyệt qua và chỉnh sửa cây constructs.
    • Thực hiện các cross-stack validations (xác thực giữa các stack).

Ví dụ về Aspects trong Preparation Phase:

# Python
class SecurityHeadersAspect(IAspect):
    def visit(self, node: IConstruct) -> None:
        if isinstance(node, apigw.RestApi):
            # Thêm security headers cho API Gateway
            node.add_gateway_response(
                "DEFAULT_4XX",
                response_parameters={
                    "gatewayresponse.header.Strict-Transport-Security": "'max-age=31536000; includeSubdomains; preload'",
                    "gatewayresponse.header.Content-Security-Policy": "'default-src https:'"
                }
            )
 
# Áp dụng Aspect
cdk.Aspects.of(self).add(SecurityHeadersAspect())

Giải thích chi tiết về Aspect:

  • Aspects trong AWS CDK là một cơ chế cho phép bạn áp dụng một hoạt động hoặc logic nào đó lên tất cả hoặc một nhóm constructs trong cây constructs của bạn.

  • Chúng hoạt động bằng cách duyệt qua toàn bộ cây construct và áp dụng phương thức visit của Aspect lên mỗi construct.

  • Sử dụng Aspects, bạn có thể:

    • Thêm tags cho tất cả các tài nguyên.
    • Kiểm tra các thiết lập bảo mật trên các tài nguyên.
    • Thực hiện các sửa đổi hoặc kiểm tra tùy chỉnh mà không cần thay đổi code của từng construct riêng lẻ.

    Ví dụ thực tế:

    Ví dụ 1: Thêm Tags cho tất cả các tài nguyên

    Giả sử bạn muốn thêm một tag chung cho tất cả các tài nguyên trong stack của bạn, ví dụ: Environment: Production.

    from aws_cdk import (
        core as cdk,
        aws_s3 as s3,
    )
     
    class TagAllResourcesAspect(cdk.IAspect):
        def __init__(self, key: str, value: str):
            self.key = key
            self.value = value
     
        def visit(self, node: cdk.IConstruct) -> None:
            # Kiểm tra nếu node là một tài nguyên CloudFormation
            if isinstance(node, cdk.CfnResource):
                cdk.Tags.of(node).add(self.key, self.value)
     
    # Sử dụng Aspect trong Stack
    class MyStack(cdk.Stack):
        def __init__(self, scope: cdk.Construct, id: str, **kwargs):
            super().__init__(scope, id, **kwargs)
     
            # Định nghĩa các tài nguyên, ví dụ: S3 Bucket
            bucket = s3.Bucket(self, "MyBucket")
     
            # Áp dụng Aspect để thêm tag
            cdk.Aspects.of(self).add(TagAllResourcesAspect("Environment", "Production"))

Ví dụ 2: Kiểm tra tính năng mã hóa trên tất cả S3 Bucket

Bạn muốn đảm bảo rằng tất cả các S3 Bucket được tạo đều có bật tính năng mã hóa.

from aws_cdk import (
    core as cdk,
    aws_s3 as s3,
)
 
class EncryptBucketAspect(cdk.IAspect):
    def visit(self, node: cdk.IConstruct) -> None:
        if isinstance(node, s3.CfnBucket):
            if node.bucket_encryption is None:
                # Thêm cấu hình mã hóa mặc định
                node.bucket_encryption = s3.CfnBucket.BucketEncryptionProperty(
                    server_side_encryption_configuration=[
                        s3.CfnBucket.ServerSideEncryptionRuleProperty(
                            server_side_encryption_by_default=s3.CfnBucket.ServerSideEncryptionByDefaultProperty(
                                sse_algorithm="AES256"
                            )
                        )
                    ]
                )
 
# Sử dụng Aspect trong Stack
class MyStack(cdk.Stack):
    def __init__(self, scope: cdk.Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)
 
        # Tạo S3 Bucket mà không chỉ định mã hóa
        bucket = s3.Bucket(self, "MyUnencryptedBucket")
 
        # Áp dụng Aspect để đảm bảo mã hóa
        cdk.Aspects.of(self).add(EncryptBucketAspect())

Lợi ích của việc sử dụng Aspects

  • Tính Nhất Quán : Áp dụng các thay đổi hoặc quy tắc trên toàn bộ hạ tầng một cách nhất quán.
  • Dễ Bảo Trì : Giảm thiểu việc lặp lại code và dễ dàng cập nhật khi có thay đổi về chính sách hoặc quy định.
  • Tách Biệt : Logic về bảo mật và tuân thủ được tách khỏi code định nghĩa hạ tầng chính.
  • Tự Động : Tự động kiểm tra và áp dụng các tiêu chuẩn trong quá trình xây dựng hạ tầng.

Một số trường hợp sử dụng Aspects

  • Áp dụng chính sách bảo mật : Đảm bảo các tài nguyên tuân thủ các yêu cầu bảo mật (ví dụ: tất cả Security Group phải có rule cụ thể).
  • Kiểm tra tuân thủ : Xác minh cấu hình hạ tầng theo các tiêu chuẩn tuân thủ như PCI DSS, HIPAA.
  • Thêm logging hoặc monitoring : Tự động thêm cấu hình logging cho các dịch vụ.

Lưu ý : Trong các phiên bản AWS CDK mới hơn, phương thức prepare() đã bị loại bỏ. Thay vào đó, bạn nên sử dụng Aspects hoặc các pattern khác để thực hiện các thao tác chuẩn bị.

3. Validation Phase (Giai đoạn Kiểm tra)

  • Mục đích :Giai đoạn này đảm bảo tính hợp lệ của configuration:

  • Hoạt động chính :

    • Thực thi các phương thức validate() trong constructs.
    • Kiểm tra các thuộc tính bắt buộc đã được thiết lập.
    • Xác nhận mối quan hệ và tính logic giữa các tài nguyên.

Ví dụ về Validation:

# Python
def validate(self) -> List[str]:
    errors = []
 
    # Kiểm tra biến môi trường
    if 'ENVIRONMENT' not in self.handler.environment:
        errors.append('Lambda function must have ENVIRONMENT variable defined')
 
    # Kiểm tra phương thức API
    if not any(method.http_method == 'GET' for method in self.api.root.methods):
        errors.append('API must have at least one GET method')
 
    return errors

4. Synthesis Phase (Giai đoạn Tổng hợp)

  • Mục đích : Giai đoạn cuối cùng, chuyển đổi code thành CloudFormation templates:
  • Hoạt động chính :
    • Kích hoạt bởi lệnh cdk synth hoặc app.synth().
    • Tạo ra các deployment artifacts cần thiết.
    • Sinh các file template trong thư mục cdk.out.

CDK Toolkit và Synthesis

Các lệnh Synthesis cơ bản

# Synthesis tất cả stacks
cdk synth
 
# Synthesis một stack cụ thể
cdk synth my-stack-name
 
# Synthesis và xuất output ra file
cdk synth --output=template.yaml

Cấu trúc thư mục cdk.out

cdk.out/
├── my-stack.template.json     # CloudFormation template
├── assets.json                # Asset metadata
├── manifest.json              # Deployment manifest
├── tree.json                  # Construct tree
└── asset.{hash}/             # Asset bundles (Lambda code, etc.)

Best Practices và Tips

1. Construction Phase

  • Tập trung logic chính vào __init__
  • Sử dụng props để truyền configuration
  • Tạo các helper methods cho logic phức tạp

2. Aspects

  • Sử dụng cho cross-cutting concerns
  • Áp dụng security policies
  • Thêm tags cho resources
  • Validate compliance requirements

3. Validation

  • Validate early và often
  • Sử dụng type hints
  • Implement custom validations cho business logic
  • Kiểm tra các dependencies giữa resources

4. Debugging

VS Code extensions hữu ích:

  • AWS Toolkit
  • Python extension
  • YAML extension

Ví dụ Hoàn chỉnh về Stack

class FullStackExample(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
      
        # Construction Phase
        api_lambda = ApiLambdaConstruct(self, 'ApiLambda')
      
        # Preparation Phase (Aspects)
        cdk.Aspects.of(self).add(SecurityHeadersAspect())
      
        # Thêm monitoring và alerting
        alarm = cloudwatch.Alarm(
            self, 'ApiErrors',
            metric=api_lambda.api.metric_4xx_error(),
            threshold=10,
            evaluation_periods=3
        )
      
        # Outputs
        CfnOutput(self, 'ApiUrl',
            value=api_lambda.api.url,
            description='API Gateway URL'
        )

Construct Tree Visualization

App
└── FullStackExample (Stack)
    ├── ApiLambda
    │   ├── ApiHandler (Lambda)
    │   └── SampleApi (API Gateway)
    └── ApiErrors (CloudWatch Alarm)

Kết luận

Hiểu rõ về vòng đời của CDK app và quá trình synthesis là nền tảng quan trọng để:

  • Debug hiệu quả
  • Tối ưu code
  • Quản lý deployment tốt hơn
  • Phát triển các ứng dụng CDK phức tạp

Trong loạt bài tiếp theo, chúng ta sẽ đi sâu vào:

  • Testing CDK applications
  • CI/CD với CDK
  • Advanced patterns và best practices

Tài liệu Tham khảo