View a markdown version of this page

識別符和 AWS CDK - AWS 雲端開發套件 (AWS CDK) v2

這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護,並於 2023 年 6 月 1 日結束支援。

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

識別符和 AWS CDK

建置 AWS 雲端開發套件 (AWS CDK) 應用程式時,您會使用許多類型的識別符和名稱。若要有效使用 AWS CDK 並避免錯誤,請務必了解識別符的類型。

識別符在建立它們的範圍內必須是唯一的;它們不需要在您的 AWS CDK 應用程式中全域是唯一的。

如果您嘗試在相同範圍內建立具有相同值的識別符, AWS CDK 會擲回例外狀況。

建構 IDs

最常見的識別符 id是在執行個體化建構物件時作為第二個引數傳遞的識別符。此識別符與所有識別符一樣,只需要在建立識別符的範圍內是唯一的,這是執行個體化建構物件時的第一個引數。

注意

堆疊id的 也是您在 AWS CDK CLI 參考中用來參考它的識別符。

我們來看一個範例,其中有兩個具有識別符的建構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/MyBucketStack2/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/CA/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:

  1. 從建構樹串連路徑元件,不包括堆疊本身。

  2. 套用啟發式以提高可讀性 (請參閱邏輯 ID 路徑元件啟發式)。

  3. 附加完整路徑的 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 Default 範圍只能指派一個子項。

  • 如果您在部署後變更建構 ID,邏輯 ID 會變更,這會導致 AWS CloudFormation 取代資源。使用 在部署之前cdk diff驗證變更。

  • 對於邏輯 IDs 已變更的情況,您可以使用 cdk refactor命令將舊邏輯 IDs 映射至新的 ID。如需詳細資訊,請參閱在重構 CDK 程式碼時保留部署的資源

  • 如需有關邏輯 IDs 如何在合成範本中顯示的詳細資訊,請參閱《 AWS CloudFormation 範本》中的產生邏輯 IDs

邏輯 ID 穩定性

建立資源之後,請避免變更資源的邏輯 ID。 AWS CloudFormation 會依資源的邏輯 ID 來識別資源。因此,如果您變更資源的邏輯 ID, AWS CloudFormation 會使用新的邏輯 ID 建立新的資源,然後刪除現有的資源。根據資源的類型,這可能會導致服務中斷、資料遺失或兩者。