這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護,並於 2023 年 6 月 1 日結束支援。
本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
識別符和 AWS CDK
建置 AWS 雲端開發套件 (AWS CDK) 應用程式時,您會使用許多類型的識別符和名稱。若要有效使用 AWS CDK 並避免錯誤,請務必了解識別符的類型。
識別符在建立它們的範圍內必須是唯一的;它們不需要在您的 AWS CDK 應用程式中全域是唯一的。
如果您嘗試在相同範圍內建立具有相同值的識別符, AWS CDK 會擲回例外狀況。
建構 IDs
最常見的識別符 id是在執行個體化建構物件時作為第二個引數傳遞的識別符。此識別符與所有識別符一樣,只需要在建立識別符的範圍內是唯一的,這是執行個體化建構物件時的第一個引數。
我們來看一個範例,其中有兩個具有識別符的建構MyBucket。第一個定義在具有識別符 的堆疊範圍內Stack1。第二個定義在具有識別符 的堆疊範圍內Stack2。由於它們是在不同的範圍內定義,這不會造成任何衝突,而且它們可以在相同的應用程式中共存而不會發生問題。
範例
- TypeScript
-
import { App, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
class MyStack extends Stack {
constructor(scope: Construct, id: string, props: StackProps = {}) {
super(scope, id, props);
new s3.Bucket(this, 'MyBucket');
}
}
const app = new App();
new MyStack(app, 'Stack1');
new MyStack(app, 'Stack2');
- JavaScript
-
const { App , Stack } = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
class MyStack extends Stack {
constructor(scope, id, props = {}) {
super(scope, id, props);
new s3.Bucket(this, 'MyBucket');
}
}
const app = new App();
new MyStack(app, 'Stack1');
new MyStack(app, 'Stack2');
- Python
-
from aws_cdk import App, Construct, Stack, StackProps
from constructs import Construct
from aws_cdk import aws_s3 as s3
class MyStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
s3.Bucket(self, "MyBucket")
app = App()
MyStack(app, 'Stack1')
MyStack(app, 'Stack2')
- Java
-
// MyStack.java
package com.myorg;
import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.constructs.Construct;
import software.amazon.awscdk.services.s3.Bucket;
public class MyStack extends Stack {
public MyStack(final Construct scope, final String id) {
this(scope, id, null);
}
public MyStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
new Bucket(this, "MyBucket");
}
}
// Main.java
package com.myorg;
import software.amazon.awscdk.App;
public class Main {
public static void main(String[] args) {
App app = new App();
new MyStack(app, "Stack1");
new MyStack(app, "Stack2");
}
}
- C#
-
using Amazon.CDK;
using constructs;
using Amazon.CDK.AWS.S3;
public class MyStack : Stack
{
public MyStack(Construct scope, string id, IStackProps props) : base(scope, id, props)
{
new Bucket(this, "MyBucket");
}
}
class Program
{
static void Main(string[] args)
{
var app = new App();
new MyStack(app, "Stack1");
new MyStack(app, "Stack2");
}
}
路徑
AWS CDK 應用程式中的建構會形成以 App類別為根的階層。我們將特定建構的 IDs 集合、其父建構、其祖父等稱為建構樹根目錄的路徑。
AWS CDK 通常會將範本中的路徑顯示為字串。來自關卡的 IDs 會以斜線分隔,從根App執行個體下的節點開始,通常是堆疊。例如,先前程式碼範例中兩個 Amazon S3 儲存貯體資源的路徑為 Stack1/MyBucket和 Stack2/MyBucket。
您可以程式設計方式存取任何建構的路徑,如下列範例所示。這會取得 myConstruct(或 my_construct,因為 Python 開發人員會寫入它) 的路徑。由於 IDs 在建立的範圍內必須是唯一的,因此其路徑在 AWS CDK 應用程式中一律是唯一的。
範例
- TypeScript
-
const path: string = myConstruct.node.path;
- JavaScript
-
const path = myConstruct.node.path;
- Python
-
path = my_construct.node.path
- Java
-
String path = myConstruct.getNode().getPath();
- C#
-
string path = myConstruct.Node.Path;
唯一 ID
AWS CloudFormation 要求範本中的所有邏輯 IDs 都是唯一的。因此, AWS CDK 必須能夠為應用程式中的每個建構產生唯一識別符。資源具有全域唯一的路徑 (從堆疊到特定資源的所有範圍名稱)。因此, AWS CDK 會透過串連路徑的元素並新增 8 位數雜湊來產生必要的唯一識別符。(雜湊是區分不同路徑的必要項目,例如 A/B/C和 A/BC,這會導致相同的 AWS CloudFormation 識別符。 AWS CloudFormation 識別符是英數字元,不能包含斜線或其他分隔符號字元。) AWS CDK 會將此字串稱為建構的唯一 ID。
一般而言,您的 AWS CDK 應用程式應該不需要知道唯一 IDs。不過,您可以透過程式設計方式存取任何建構的唯一 ID,如下列範例所示。
範例
- TypeScript
-
const uid: string = Names.uniqueId(myConstruct);
- JavaScript
-
const uid = Names.uniqueId(myConstruct);
- Python
-
uid = Names.unique_id(my_construct)
- Java
-
String uid = Names.uniqueId(myConstruct);
- C#
-
string uid = Names.Uniqueid(myConstruct);
地址是另一種唯一識別符,可唯一區分 CDK 資源。衍生自路徑的 SHA-1 雜湊,無法人類讀取。不過,其常數、相對較短的長度 (一律為 42 個十六進位字元),在「傳統」唯一 ID 可能太長的情況下很有用。有些建構可能使用合成 AWS CloudFormation 範本中的地址,而非唯一 ID。同樣地,您的應用程式通常不需要知道其建構結構的地址,但您可以擷取建構結構的地址,如下所示。
範例
- TypeScript
-
const addr: string = myConstruct.node.addr;
- JavaScript
-
const addr = myConstruct.node.addr;
- Python
-
addr = my_construct.node.addr
- Java
-
String addr = myConstruct.getNode().getAddr();
- C#
-
string addr = myConstruct.Node.Addr;
邏輯 IDs
當 AWS CDK 將您的應用程式合成到 an AWS CloudFormation 範本時,它會為每個資源產生邏輯 ID。 AWS CloudFormation 會使用邏輯 IDs來識別範本中的資源,並在部署之間追蹤這些資源。了解邏輯 IDs 的產生方式,可協助您在重構 CDK 程式碼時避免意外的資源替換。
如何產生邏輯 IDs
AWS CDK 使用下列演算法從建構路徑產生邏輯 IDs:
-
從建構樹串連路徑元件,不包括堆疊本身。
-
套用啟發式以提高可讀性 (請參閱邏輯 ID 路徑元件啟發式)。
-
附加完整路徑的 8 個字元雜湊,以確保唯一性。
產生的格式為:
<human-readable-portion><8-character-hash>
例如,VPC 私有子網路路由表可能會產生邏輯 ID VPCPrivateSubnet2RouteTable0A19E10E。
下列規則適用於邏輯 ID 產生:
-
長度上限為 255 個字元。人類可讀取的部分上限為 240 個字元。
-
8 個字元雜湊可確保與相同字串A/BC串連的 A/B/C和 等路徑產生不同的邏輯 IDs。
-
堆疊 (單一元件路徑) 的直接子項資源直接使用其名稱,無需雜湊,只要名稱為 255 個字元或更少。
邏輯 ID 路徑元件啟發式
AWS CDK 會在產生邏輯 IDs 的人類可讀取部分時,將下列啟發式套用至路徑元件。
-
Default — 已完全移除
-
如果路徑元件是 Default,CDK 會從人類可讀部分和雜湊輸入中移除它。這表示在新的建構中包裝現有的建構,並命名內部建構Default,會產生與原始未包裝建構完全相同的邏輯 ID。這是將一般程式碼安全地重構為更高層級建構的關鍵機制,而不會變更部署的資源身分。
-
Resource — 僅隱藏在人類可讀取的部分
-
如果路徑元件是 Resource,CDK 會從人類可讀部分省略它,但仍將其包含在雜湊計算中。L1 (CloudFormation) 建構會使用 Resource做為其依據慣例的建構 ID。這可縮短邏輯 IDs而不會失去唯一性。
- 重複的連續元件 — 已刪除重複項目
-
如果上述路徑元件名稱以目前的元件名稱結尾,CDK 會略過目前的元件。這可防止邏輯 IDs 中的備援重複。
當您重構時Default,使用 保留邏輯 IDs
當您將平面堆疊重構為更高層級的建構時,您可以使用 Default做為主要資源的建構 ID,以保留其邏輯 ID。這可防止 AWS CloudFormation 在部署期間取代資源。
下列範例顯示具有直接定義之資源的堆疊:
範例
- TypeScript
-
export class MyStack extends cdk.Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
new s3.Bucket(this, 'DataBucket');
new lambda.Function(this, 'ProcessFunction', { /* ... */ });
}
}
- JavaScript
-
class MyStack extends cdk.Stack {
constructor(scope, id) {
super(scope, id);
new s3.Bucket(this, 'DataBucket');
new lambda.Function(this, 'ProcessFunction', { /* ... */ });
}
}
- Python
-
from aws_cdk import (
Stack,
aws_s3 as s3,
aws_lambda as _lambda,
)
from constructs import Construct
class MyStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
s3.Bucket(self, "DataBucket")
_lambda.Function(self, "ProcessFunction", # ...
)
- Java
-
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.lambda.Function;
public class MyStack extends Stack {
public MyStack(final Construct scope, final String id) {
this(scope, id, null);
}
public MyStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
new Bucket(this, "DataBucket");
Function.Builder.create(this, "ProcessFunction")
// ...
.build();
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.Lambda;
namespace MyApp
{
public class MyStack : Stack
{
public MyStack(Construct scope, string id, StackProps props = null) : base(scope, id, props)
{
new Bucket(this, "DataBucket");
new Function(this, "ProcessFunction", new FunctionProps
{
// ...
});
}
}
}
- Go
-
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type MyStackProps struct {
awscdk.StackProps
}
func NewMyStack(scope constructs.Construct, id string, props *MyStackProps) awscdk.Stack {
stack := awscdk.NewStack(scope, &id, &props.StackProps)
awss3.NewBucket(stack, jsii.String("DataBucket"), &awss3.BucketProps{})
awslambda.NewFunction(stack, jsii.String("ProcessFunction"), &awslambda.FunctionProps{
// ...
})
return stack
}
儲存貯體的路徑為 MyStack/DataBucket/Resource,會產生 的邏輯 IDDataBucket<hash>。
您可以透過命名內部建構 ,將儲存貯體擷取到更高層級的建構中,並保留相同的邏輯 IDDefault:
範例
- TypeScript
-
class DataPipeline extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
new s3.Bucket(this, 'Default'); // 'Default' is hidden from logical ID
new lambda.Function(this, 'ProcessFunction', { /* ... */ });
}
}
export class MyStack extends cdk.Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
new DataPipeline(this, 'DataBucket');
}
}
- JavaScript
-
class DataPipeline extends Construct {
constructor(scope, id) {
super(scope, id);
new s3.Bucket(this, 'Default'); // 'Default' is hidden from logical ID
new lambda.Function(this, 'ProcessFunction', { /* ... */ });
}
}
class MyStack extends cdk.Stack {
constructor(scope, id) {
super(scope, id);
new DataPipeline(this, 'DataBucket');
}
}
- Python
-
from aws_cdk import (
Stack,
aws_s3 as s3,
aws_lambda as _lambda,
)
from constructs import Construct
class DataPipeline(Construct):
def __init__(self, scope: Construct, id: str) -> None:
super().__init__(scope, id)
s3.Bucket(self, "Default") # 'Default' is hidden from logical ID
_lambda.Function(self, "ProcessFunction", # ...
)
class MyStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
DataPipeline(self, "DataBucket")
- Java
-
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.lambda.Function;
public class DataPipeline extends Construct {
public DataPipeline(final Construct scope, final String id) {
super(scope, id);
new Bucket(this, "Default"); // 'Default' is hidden from logical ID
Function.Builder.create(this, "ProcessFunction")
// ...
.build();
}
}
public class MyStack extends Stack {
public MyStack(final Construct scope, final String id) {
this(scope, id, null);
}
public MyStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
new DataPipeline(this, "DataBucket");
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.Lambda;
namespace MyApp
{
public class DataPipeline : Construct
{
public DataPipeline(Construct scope, string id) : base(scope, id)
{
new Bucket(this, "Default"); // 'Default' is hidden from logical ID
new Function(this, "ProcessFunction", new FunctionProps
{
// ...
});
}
}
public class MyStack : Stack
{
public MyStack(Construct scope, string id, StackProps props = null) : base(scope, id, props)
{
new DataPipeline(this, "DataBucket");
}
}
}
- Go
-
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type DataPipeline struct {
constructs.Construct
}
func NewDataPipeline(scope constructs.Construct, id string) constructs.Construct {
this := constructs.NewConstruct(scope, &id)
// 'Default' is hidden from logical ID
awss3.NewBucket(this, jsii.String("Default"), &awss3.BucketProps{})
awslambda.NewFunction(this, jsii.String("ProcessFunction"), &awslambda.FunctionProps{
// ...
})
return this
}
type MyStackProps struct {
awscdk.StackProps
}
func NewMyStack(scope constructs.Construct, id string, props *MyStackProps) awscdk.Stack {
stack := awscdk.NewStack(scope, &id, &props.StackProps)
NewDataPipeline(stack, "DataBucket")
return stack
}
儲存貯體的路徑現在為 MyStack/DataBucket/Default/Resource。由於 從人類可讀取部分和雜湊輸入Default中移除 ,因此邏輯 ID 會保持DataBucket<hash>與原始相同。
Default 每個建構範圍只能有一個 ID 為 的子系。如果您需要相同層級的多個資源,請提供描述 IDs。模式Default最適合具有一個主要資源的單一責任建構。
限制及考量
當您使用邏輯 IDs 時,請記住下列事項:
邏輯 ID 穩定性
建立資源之後,請避免變更資源的邏輯 ID。 AWS CloudFormation 會依資源的邏輯 ID 來識別資源。因此,如果您變更資源的邏輯 ID, AWS CloudFormation 會使用新的邏輯 ID 建立新的資源,然後刪除現有的資源。根據資源的類型,這可能會導致服務中斷、資料遺失或兩者。