這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護,並於 2023 年 6 月 1 日結束支援。
本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
在 中 AWS Cloud Development Kit (AWS CDK),字符是定義建構或合成堆疊時未知值的預留位置。建立實際基礎設施時,這些值將在部署時完全解析。開發 AWS CDK 應用程式時,您將使用字符來管理整個應用程式的這些值。
權杖範例
以下是定義 Amazon Simple Storage Service (Amazon S3) 儲存貯體建構的 CDK 堆疊範例。由於我們儲存貯體的名稱尚不清楚,因此 的值bucketName
會儲存為字符:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class CdkDemoAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// Store value of the S3 bucket name
const myBucketName = myBucket.bucketName;
// Print the current value for the S3 bucket name at synthesis
console.log("myBucketName: " + bucketName);
}
}
當我們執行 cdk synth
來合成堆疊時, 的值myBucketName
會以 的字符格式顯示${Token[TOKEN.
。此字符格式是 AWS CDK 編碼字符的結果。在此範例中,字符編碼為字串:1234
]}
$
cdk synth --quiet
myBucketName: ${Token[TOKEN.21
]}
由於合成時不知道儲存貯體名稱的值,因此字符會轉譯為 myBucket
。我們的 AWS CloudFormation 範本使用 <unique-hash>
Ref
內部函數來參考其值,該值將在部署時已知:
Resources:
myBucket5AF9C99B
:
# ...
Outputs:
bucketNameOutput:
Description: The name of the S3 bucket
Value:
Ref: myBucket5AF9C99B
如需如何產生唯一雜湊的詳細資訊,請參閱 範本中產生的邏輯 IDs AWS CloudFormation。
傳遞字符
權杖可以像它們所代表的實際值一樣傳遞。以下是將儲存貯體名稱的字符傳遞至 AWS Lambda 函數建構的範例:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class CdkDemoAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// ...
// Define a Lambda function
const myFunction = new lambda.Function(this, "myFunction", {
runtime: lambda.Runtime.NODEJS_20_X,
handler: "index.handler",
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
functionName: myBucketName + "Function", // Pass token for the S3 bucket name
environment: {
BUCKET_NAME: myBucketName, // Pass token for the S3 bucket name
}
});
}
}
合成範本時, Ref
和 Fn::Join
內部函數會用來指定值,這些值將在部署時得知:
Resources:
myBucket5AF9C99B
:
Type: AWS::S3::Bucket
# ...
myFunction884E1557
:
Type: AWS::Lambda::Function
Properties:
# ...
Environment:
Variables:
BUCKET_NAME:
Ref: myBucket5AF9C99B
FunctionName:
Fn::Join:
- ""
- - Ref: myBucket5AF9C99B
- Function
# ...
字符編碼的運作方式
字符是實作IResolvable
界面的物件,其中包含單一resolve
方法。在合成期間, 會 AWS CDK 呼叫此方法,為 CloudFormation 範本中的字符產生最終值。
注意
您很少會直接使用 IResolvable
界面。您很可能只會看到字符的字串編碼版本。
字符編碼類型
字符會參與合成程序,以產生任何類型的任意值。其他函數通常只接受基本類型的引數,例如 string
或 number
。若要在這些情況下使用字符,您可以使用 cdk.Token
類別上的靜態方法,將字符編碼為三種類型之一。
-
Token.asString
產生字串編碼 (或在字符物件.toString()
上呼叫)。 -
Token.asList
來產生清單編碼。 -
Token.asNumber
來產生數值編碼。
這些會採用任意值,可以是 IResolvable
,並將其編碼為指定類型的基本值。
重要
由於上述任何一種類型都可能是編碼字符,因此在剖析或嘗試讀取其內容時,請小心。例如,如果您嘗試剖析字串以從中擷取值,而字串是編碼字符,則剖析會失敗。同樣地,如果您嘗試查詢陣列的長度或使用數字執行數學操作,您必須先驗證它們不是編碼字符。
如何在應用程式中檢查字符
若要檢查值中是否有未解析的字符,請呼叫 Token.isUnresolved
(Python:is_unresolved
) 方法。以下是檢查 Amazon S3 儲存貯體名稱值是否為字符的範例。如果不是字符,我們會驗證儲存貯體名稱的長度:
// ...
export class CdkDemoAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// ...
// Check if bucket name is a token. If not, check if length is less than 10 characters
if (cdk.Token.isUnresolved(myBucketName)) {
console.log("Token identified.");
} else if (!cdk.Token.isUnresolved(myBucketName) && myBucketName.length > 10) {
throw new Error('Maximum length for name is 10 characters.');
};
// ...
當我們執行 時cdk synth
, myBucketName
會識別為字符:
$
cdk synth --quiet
Token identified.
注意
您可以使用字符編碼來逸出類型系統。例如,您可以對在合成時間產生數值的字符進行字串編碼。如果您使用這些函數,您有責任確保範本在合成後解析為可用狀態。
使用字串編碼字符
字串編碼字符如下所示。
${TOKEN[Bucket.Name.1234]}
它們可以像一般字串一樣傳遞,也可以串連,如下列範例所示。
const functionName = bucket.bucketName + 'Function';
如果您的語言支援,您也可以使用字串插補,如下列範例所示。
const functionName = `${bucket.bucketName}Function`;
避免以其他方式操作字串。例如,取得字串的子字串可能會破壞字串字符。
使用清單編碼字符
清單編碼字符如下所示:
["#{TOKEN[Stack.NotificationArns.1234]}"]
處理這些清單的唯一安全事項是直接傳遞給其他建構模組。字串清單形式的字符無法串連,也無法從字符中取得 元素。操作它們的唯一安全方法是使用 AWS CloudFormation Fn.select 之類的內部函數。
使用數字編碼字符
數字編碼字符是一組看起來如下的小型負浮點數字。
-1.8881545897087626e+289
與清單字符一樣,您無法修改數字值,因為這樣做可能會破壞數字字符。
以下是包含以數字編碼之字符的建構範例:
import { Stack, Duration, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
export class CdkDemoAppStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Define a new VPC
const vpc = new ec2.Vpc(this, 'MyVpc', {
maxAzs: 3, // Maximum number of availability zones to use
});
// Define an RDS database cluster
const dbCluster = new rds.DatabaseCluster(this, 'MyRDSCluster', {
engine: rds.DatabaseClusterEngine.AURORA,
instanceProps: {
vpc,
},
});
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// Print the value for our token at synthesis
console.log("portToken: " + portToken);
}
}
當我們執行 時cdk synth
, 的值portToken
會顯示為數字編碼字符:
$
cdk synth --quiet
portToken: -1.8881545897087968e+289
傳遞數字編碼字符
當您將數字編碼的字符傳遞給其他建構模組時,先將其轉換為字串可能很有意義。例如,如果您想要使用數字編碼字串的值作為串連字串的一部分,轉換它有助於提高可讀性。
在下列範例中, portToken
是號碼編碼的字符,做為 的一部分,我們要傳遞至 Lambda 函數connectionString
:
import { Stack, Duration, CfnOutput, StackProps } from 'aws-cdk-lib';
// ...
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class CdkDemoAppStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// ...
// Example connection string with the port token as a number
const connectionString = `jdbc:mysql://mydb.cluster.amazonaws.com:${portToken}/mydatabase`;
// Use the connection string as an environment variable in a Lambda function
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
environment: {
DATABASE_CONNECTION_STRING: connectionString, // Using the port token as part of the string
},
});
// Output the value of our connection string at synthesis
console.log("connectionString: " + connectionString);
// Output the connection string
new CfnOutput(this, 'ConnectionString', {
value: connectionString,
});
}
}
如果我們將此值傳遞給 connectionString
,則執行 時的輸出值cdk synth
可能會因為數字編碼字串而令人混淆:
$
cdk synth --quiet
connectionString: jdbc:mysql://mydb.cluster.amazonaws.com:-1.888154589708796e+289/mydatabase
若要將數字編碼字符轉換為字串,請使用 cdk.Tokenization.stringifyNumber(
。在下列範例中,我們會在定義連線字串之前,將數字編碼字符轉換為字串:token
)
import { Stack, Duration, Tokenization, CfnOutput, StackProps } from 'aws-cdk-lib';
// ...
export class CdkDemoAppStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// ...
// Convert the encoded number to an encoded string for use in the connection string
const portAsString = Tokenization.stringifyNumber(portToken);
// Example connection string with the port token as a string
const connectionString = `jdbc:mysql://mydb.cluster.amazonaws.com:${portAsString}/mydatabase`;
// Use the connection string as an environment variable in a Lambda function
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
// ...
environment: {
DATABASE_CONNECTION_STRING: connectionString, // Using the port token as part of the string
},
});
// Output the value of our connection string at synthesis
console.log("connectionString: " + connectionString);
// Output the connection string
new CfnOutput(this, 'ConnectionString', {
value: connectionString,
});
}
}
當我們執行 時cdk synth
,連線字串的值會以更簡潔且更清楚的格式表示:
$
cdk synth --quiet
connectionString: jdbc:mysql://mydb.cluster.amazonaws.com:${Token[TOKEN.242]}/mydatabase
延遲值
除了代表部署時間值,例如 AWS CloudFormation 參數,字符也常用於表示合成時間延遲值。這些值將在合成完成之前決定最終值,但不會在建構值的時間點決定。使用字符將常值字串或數值傳遞給另一個建構,而合成時間的實際值可能取決於尚未發生的一些計算。
您可以使用 Lazy
類別上的靜態方法來建構代表同步時間延遲值的字符,例如 Lazy.string
和 Lazy.number
。這些方法接受produce
屬性為函數的物件,該函數接受內容引數,並在呼叫時傳回最終值。
下列範例會建立容量在建立之後決定的 Auto Scaling 群組。
let actualValue: number;
new AutoScalingGroup(this, 'Group', {
desiredCapacity: Lazy.numberValue({
produce(context) {
return actualValue;
}
})
});
// At some later point
actualValue = 10;
轉換為 JSON
有時您想要產生任意資料的 JSON 字串,而且您可能不知道資料是否包含字符。若要正確 JSON 編碼任何資料結構,無論它是否包含字符,請使用 方法 stack.toJsonString
,如下列範例所示。
const stack = Stack.of(this);
const str = stack.toJsonString({
value: bucket.bucketName
});