本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
第 3 層建構
如果 L1 建構模組將 CloudFormation 資源轉譯為程式設計程式碼,而 L2 建構模組將大部分詳細 CloudFormation 語法取代為協助程式方法和自訂邏輯,L3 建構模組會做什麼? 的答案僅受限於您的想像。您可以建立第 3 層,以符合任何特定使用案例。如果您的專案需要具有特定屬性子集的資源,您可以建立可重複使用的 L3 建構以滿足該需求。
L3 建構稱為 內的模式 AWS CDK。模式是延伸 Construct類別的任何物件 AWS CDK (或延伸延伸 Construct 類別的類別),以執行第 2 層以外的任何抽象邏輯。當您使用 AWS CDK CLI 執行 cdk init 來啟動新 AWS CDK 專案時,您必須從三種 AWS CDK 應用程式類型中選擇:app、 lib和 sample-app。
app 和 sample-app都代表您在 AWS 環境中建置和部署 CloudFormation 堆疊的傳統 AWS CDK 應用程式。當您選擇 時lib,您選擇建置全新的 L3 建構。 app 並sample-app允許您選擇 AWS CDK 支援的任何語言,但您只能選擇 TypeScript 搭配 lib。這是因為 AWS CDK 以 TypeScript 原生寫入,並使用名為 JSiilib啟動專案時,您會選擇建置 的延伸 AWS CDK。
擴展類別的任何Construct類別都可以是 L3 建構,但第 3 層最常見的使用案例是資源互動、資源延伸和自訂資源。大多數 L3 建構會使用這三個案例的一或多個,以擴展 AWS CDK 功能。
資源互動
解決方案通常會採用數個可一起運作的 AWS 服務。例如,Amazon CloudFront 分佈通常會使用 S3 儲存貯體做為原始伺服器,並 AWS WAF 防止常見的入侵。 AWS AppSync 而 Amazon API Gateway 通常會使用 Amazon DynamoDB 資料表做為其 APIs的資料來源。中的管道 AWS CodePipeline 通常會使用 Amazon S3 做為其來源,並 AWS CodeBuild 用於其建置階段。在這些情況下,建立處理兩個或多個互連 L2 建構的單一 L3 建構通常很有用。 L2
以下是 L3 建構範例,其會佈建 CloudFront 分佈及其 S3 原始伺服器、 AWS WAF 要放在其前面的 、Amazon Route 53 記錄和 AWS Certificate Manager (ACM) 憑證,以新增具有傳輸中加密的自訂端點,全都在一個可重複使用的建構中:
// Define the properties passed to the L3 construct export interface CloudFrontWebsiteProps { distributionProps: DistributionProps bucketProps: BucketProps wafProps: CfnWebAclProps zone: IHostedZone } // Define the L3 construct export class CloudFrontWebsite extends Construct { public distribution: Distribution constructor( scope: Construct, id: string, props: CloudFrontWebsiteProps ) { super(scope, id); const certificate = new Certificate(this, "Certificate", { domainName: props.zone.zoneName, validation: CertificateValidation.fromDns(props.zone) }); const defaultBehavior = { origin: new S3Origin(new Bucket(this, "bucket", props.bucketProps)) } const waf = new CfnWebACL(this, "waf", props.wafProps); this.distribution = new Distribution(this, id, { ...props.distributionProps, defaultBehavior, certificate, domainNames: [this.domainName], webAclId: waf.attrArn, }); } }
請注意,CloudFront、Amazon S3、Route 53 和 ACM 都使用 L2 建構,但 Web ACL (定義處理 Web 請求的規則) 使用 L1 建構。這是因為 AWS CDK 是不斷發展的開放原始碼套件,尚未完全完成,而且WebAcl尚無 L2 建構。不過,任何人都可以 AWS CDK 透過建立新的 L2 建構來為 做出貢獻。因此,在 為 AWS CDK 提供 L2 建構之前WebAcl,您必須使用 L1 建構。若要使用 L3 建構 建立新的網站CloudFrontWebsite,請使用下列程式碼:
const siteADotCom = new CloudFrontWebsite(stack, "siteA", siteAProps); const siteBDotCom = new CloudFrontWebsite(stack, "siteB", siteBProps); const siteCDotCom = new CloudFrontWebsite(stack, "siteC", siteCProps);
在此範例中,CloudFront Distribution L2 建構會公開為 L3 建構的公有屬性。在某些情況下,您仍然需要公開這類 L3 屬性。事實上,我們將在稍後的自訂資源區段中Distribution再次看到 。
AWS CDK 包含一些資源互動模式的範例,例如此模式。除了包含 Amazon Elastic Container Service (Amazon ECS) L2 建構的aws-ecs套件之外, AWS CDK 還具有名為 aws-ecs-patterns 的套件。此套件包含數個 L3 建構模組,結合 Amazon ECS 與 Application Load Balancer、Network Load Balancer 和目標群組,同時提供 Amazon Elastic Compute Cloud (Amazon EC2) 和 的預設不同版本 AWS Fargate。由於許多無伺服器應用程式只搭配 Fargate 使用 Amazon ECS,因此這些 L3 建構提供便利性,可節省開發人員和客戶的時間。
資源擴充功能
有些使用案例需要資源具有非 L2 建構的原生特定預設設定。在堆疊層級,這可以透過使用 層面來處理,但另一個提供 L2 建構新預設值的便利方法是延伸第 2 層。由於建構是繼承 類別的任何Construct類別,而 L2 建構延伸該類別,您也可以直接延伸 L2 建構來建立 L2L3 建構。
這對於支援客戶單一需求的自訂商業邏輯特別有用。假設公司有一個儲存庫,將所有 AWS Lambda 函數程式碼存放在名為 的單一目錄中,src/lambda而且大多數 Lambda 函數每次都會重複使用相同的執行時間和處理常式名稱。您可以建立新的 L3 建構,而不是在每次設定新的 Lambda 函數時設定程式碼路徑:
export class MyCompanyLambdaFunction extends Function { constructor( scope: Construct, id: string, props: Partial<FunctionProps> = {} ) { super(scope, id, { handler: 'index.handler', runtime: Runtime.NODEJS_LATEST, code: Code.fromAsset(`src/lambda/${props.functionName || id}`), ...props }); }
然後,您可以在儲存庫中的任何位置取代 L2 Function 建構,如下所示:
new MyCompanyLambdaFunction(this, "MyFunction"); new MyCompanyLambdaFunction(this, "MyOtherFunction"); new MyCompanyLambdaFunction(this, "MyThirdFunction", { runtime: Runtime.PYTHON_3_11 });
預設值可讓您在單行上建立新的 Lambda 函數,並設定 L3 建構,因此您仍然可以視需要覆寫預設屬性。
當您只想將新的預設值新增至現有的 L2 建構時,擴充 L2 建構會直接運作最佳。如果您也需要其他自訂邏輯,最好擴展 Construct類別。原因來自 super方法,在建構函數中稱為 。在擴展其他類別的類別中, super方法用於呼叫父類別的建構函式,這必須是建構函式中發生的第一件事。這表示只有在建立原始 L2 建構模組之後,才能處理傳遞的引數或其他自訂邏輯。如果您需要在執行個體化 L2 建構之前執行任何此自訂邏輯,最好遵循先前在資源互動區段中概述的模式。
自訂資源
自訂資源是 CloudFormation 中的強大功能,可讓您從在堆疊部署期間啟用的 Lambda 函數執行自訂邏輯。每當您在部署期間需要 CloudFormation 未直接支援的任何程序時,您可以使用自訂資源來實現。 AWS CDK 提供的類別也可讓您以程式設計方式建立自訂資源。透過在 L3 建構函數中使用自訂資源,您可以讓建構幾乎沒有任何效果。
使用 Amazon CloudFront 的優點之一是其強大的全域快取功能。如果您想要手動重設該快取,讓您的網站立即反映對原始伺服器所做的新變更,您可以使用 CloudFront 無效。不過,失效是在 CloudFront 分佈上執行的程序,而不是 CloudFront 分佈的屬性。它們可以隨時建立並套用到現有的 分佈,因此它們本質上不是佈建和部署程序的一部分。
在此案例中,您可能想要在每次更新分佈的原始伺服器後建立並執行失效。由於自訂資源,您可以建立看起來像這樣的 L3 建構:
export interface CloudFrontInvalidationProps { distribution: Distribution region?: string paths?: string[] } export class CloudFrontInvalidation extends Construct { constructor( scope: Construct, id: string, props: CloudFrontInvalidationProps ) { super(scope, id); const policy = AwsCustomResourcePolicy.fromSdkCalls({ resources:AwsCustomResourcePolicy.ANY_RESOURCE }); new AwsCustomResource(scope, `${id}Invalidation`, { policy, onUpdate: { service: 'CloudFront', action: 'createInvalidation', region: props.region || 'us-east-1', physicalResourceId: PhysicalResourceId.fromResponse('Invalidation.Id'), parameters: { DistributionId: props.distribution.distributionId, InvalidationBatch: { Paths: { Quantity: props.paths?.length || 1, Items: props.paths || ['/*'] }, CallerReference: crypto.randomBytes(5).toString('hex') } } } } } }
使用先前在 CloudFrontWebsite L3 建構中建立的分佈,您可以非常輕鬆地執行此操作:
new CloudFrontInvalidation(this, 'MyInvalidation', { distribution: siteADotCom.distribution });
此 L3 建構模組使用稱為 AwsCustomResource 的 an AWS CDK L3 建構模組來建立執行自訂邏輯的自訂資源。當您需要只進行一次 AWS 開發套件呼叫時, AwsCustomResource 非常方便,因為它可讓您執行此操作,而無需撰寫任何 Lambda 程式碼。如果您有更複雜的需求,並想要實作自己的邏輯,您可以直接使用基本的 CustomResource 類別。
AWS CDK 另一個使用自訂資源 L3 建構的良好範例是 S3 儲存貯體部署。此 L3 建構的建構函數中的自訂資源所建立的 Lambda 函數會新增 CloudFormation 無法以其他方式處理的功能:它會新增和更新 S3 儲存貯體中的物件。如果沒有 S3 儲存貯體部署,您將無法將內容放入剛在堆疊中建立的 S3 儲存貯體,這會非常不方便。
AWS CDK 消除需要寫入 CloudFormation 語法範圍的最佳範例是此基本 S3BucketDeployment:
new BucketDeployment(this, 'BucketObjects', { sources: [Source.asset('./path/to/amzn-s3-demo-bucket')], destinationBucket: amzn-s3-demo-bucket });
將 與您必須寫入才能完成相同操作的 CloudFormation 程式碼進行比較:
"lambdapolicyA5E98E09": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { "Statement": [ { "Action": "lambda:UpdateFunctionCode", "Effect": "Allow", "Resource": "arn:aws:lambda:us-east-1:123456789012:function:my-function" } ], "Version": "2012-10-17" }, "PolicyName": "lambdaPolicy", "Roles": [ { "Ref": "myiamroleF09C7974" } ] }, "Metadata": { "aws:cdk:path": "CdkScratchStack/lambda-policy/Resource" } }, "BucketObjectsAwsCliLayer8C081206": { "Type": "AWS::Lambda::LayerVersion", "Properties": { "Content": { "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, "S3Key": "e2277687077a2abf9ae1af1cc9565e6715e2ebb62f79ec53aa75a1af9298f642.zip" }, "Description": "/opt/awscli/aws" }, "Metadata": { "aws:cdk:path": "CdkScratchStack/BucketObjects/AwsCliLayer/Resource", "aws:asset:path": "asset.e2277687077a2abf9ae1af1cc9565e6715e2ebb62f79ec53aa75a1af9298f642.zip", "aws:asset:is-bundled": false, "aws:asset:property": "Content" } }, "BucketObjectsCustomResourceB12E6837": { "Type": "Custom::CDKBucketDeployment", "Properties": { "ServiceToken": { "Fn::GetAtt": [ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536", "Arn" ] }, "SourceBucketNames": [ { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" } ], "SourceObjectKeys": [ "f888a9d977f0b5bdbc04a1f8f07520ede6e00d4051b9a6a250860a1700924f26.zip" ], "DestinationBucketName": { "Ref": "amzn-s3-demo-bucket77F80CC0" }, "Prune": true }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete", "Metadata": { "aws:cdk:path": "CdkScratchStack/BucketObjects/CustomResource/Default" } }, "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" } } ], "Version": "2012-10-17" }, "ManagedPolicyArns": [ { "Fn::Join": [ "", [ "arn:", { "Ref": "AWS::Partition" }, ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" ] ] } ] }, "Metadata": { "aws:cdk:path": "CdkScratchStack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource" } }, "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF": { "Type": "AWS::IAM::Policy", "Properties": { "PolicyDocument": { "Statement": [ { "Action": [ "s3:GetBucket*", "s3:GetObject*", "s3:List*" ], "Effect": "Allow", "Resource": [ { "Fn::Join": [ "", [ "arn:", { "Ref": "AWS::Partition" }, ":s3:::", { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, "/*" ] ] }, { "Fn::Join": [ "", [ "arn:", { "Ref": "AWS::Partition" }, ":s3:::", { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" } ] ] } ] }, { "Action": [ "s3:Abort*", "s3:DeleteObject*", "s3:GetBucket*", "s3:GetObject*", "s3:List*", "s3:PutObject", "s3:PutObjectLegalHold", "s3:PutObjectRetention", "s3:PutObjectTagging", "s3:PutObjectVersionTagging" ], "Effect": "Allow", "Resource": [ { "Fn::GetAtt": [ "amzns3demobucket77F80CC0", "Arn" ] }, { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "amzns3demobucket77F80CC0", "Arn" ] }, "/*" ] ] } ] } ], "Version": "2012-10-17" }, "PolicyName": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", "Roles": [ { "Ref": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" } ] }, "Metadata": { "aws:cdk:path": "CdkScratchStack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource" } }, "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, "S3Key": "9eb41a5505d37607ac419321497a4f8c21cf0ee1f9b4a6b29aa04301aea5c7fd.zip" }, "Role": { "Fn::GetAtt": [ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265", "Arn" ] }, "Environment": { "Variables": { "AWS_CA_BUNDLE": "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" } }, "Handler": "index.handler", "Layers": [ { "Ref": "BucketObjectsAwsCliLayer8C081206" } ], "Runtime": "python3.9", "Timeout": 900 }, "DependsOn": [ "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF", "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265" ], "Metadata": { "aws:cdk:path": "CdkScratchStack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource", "aws:asset:path": "asset.9eb41a5505d37607ac419321497a4f8c21cf0ee1f9b4a6b29aa04301aea5c7fd", "aws:asset:is-bundled": false, "aws:asset:property": "Code" } }
4 行與 241 行是很大的差異!這只是您利用第 3 層自訂堆疊時可能的範例之一。