這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護,並於 2023 年 6 月 1 日結束支援。
本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用 AWS Construct Library 中的 CDK 管道模組來設定 AWS CDK 應用程式的持續交付。當您將 CDK 應用程式的原始碼遞交至 AWS CodeCommitGitHub、 或 AWS CodeStar時,CDK 管道可以自動建置、測試和部署您的新版本。
CDK 管道正在自我更新。如果您新增應用程式階段或堆疊,管道會自動自行重新設定,以部署這些新的階段或堆疊。
注意
CDK 管道支援兩個 APIs。一個是 CDK 管道開發人員預覽版中提供的原始 API。另一個是現代 API,其中包含預覽階段期間從 CDK 客戶收到的意見回饋。本主題中的範例使用現代 API。如需兩個支援 APIs之間的差異詳細資訊,請參閱 aws-cdk GitHub儲存庫中的 CDK Pipelines 原始 API
引導您的 AWS 環境
您必須先引導要部署堆疊 AWS 的環境,才能使用 CDK 管道。
CDK 管道至少涉及兩個環境。第一個環境是佈建管道的位置。第二個環境是您要將應用程式堆疊或階段部署到其中的位置 (階段是相關堆疊的群組)。這些環境可以相同,但最佳實務建議是在不同的環境中彼此隔離階段。
注意
AWS CDK 引導 如需引導建立的資源類型以及如何自訂引導堆疊的詳細資訊,請參閱 。
使用 CDK 管道的持續部署需要將下列項目包含在 CDK Toolkit 堆疊中:
-
Amazon Simple Storage Service (Amazon S3) 儲存貯體。
-
Amazon ECR 儲存庫。
-
IAM 角色,為管道的各個部分提供所需的許可。
CDK Toolkit 將升級現有的引導堆疊,或視需要建立新的引導堆疊。
若要引導可佈建 AWS CDK 管道的環境,請叫用 cdk bootstrap
,如下列範例所示。如有需要,透過 npx
命令叫用 AWS CDK Toolkit 會暫時安裝它。如果存在 Toolkit,它也會使用目前專案中安裝的 Toolkit 版本。
--cloudformation-execution-policies
指定未來 CDK 管道部署將在其中執行的政策 ARN。預設AdministratorAccess
政策可確保您的管道可以部署每種類型的 AWS 資源。如果您使用此政策,請確定您信任組成 AWS CDK 應用程式的所有程式碼和相依性。
大多數組織要求對自動化可以部署的資源類型進行更嚴格的控制。請洽詢組織內適當的部門,以判斷管道應使用的政策。
如果您的預設 AWS 設定檔包含必要的身分驗證組態和,您可以省略 --profile
選項 AWS 區域。
npx cdk bootstrap aws://
ACCOUNT-NUMBER
/REGION
--profileADMIN-PROFILE
\ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
若要引導由管道部署 AWS CDK 應用程式的其他環境,請改用下列命令。--trust
選項指出哪些其他帳戶應具有將 AWS CDK 應用程式部署到此環境的許可。針對此選項,指定管道 AWS 的帳戶 ID。
同樣地,如果您的預設 AWS 設定檔包含必要的身分驗證組態和 ,您可以省略 --profile
選項 AWS 區域。
npx cdk bootstrap aws://
ACCOUNT-NUMBER
/REGION
--profileADMIN-PROFILE
\ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \ --trustPIPELINE-ACCOUNT-NUMBER
提示
僅使用管理登入資料來引導和佈建初始管道。之後,請使用管道本身,而非本機機器來部署變更。
如果您正在升級舊式引導環境,則在建立新儲存貯體時,先前的 Amazon S3 儲存貯體會處於孤立狀態。使用 Amazon S3 主控台手動刪除它。
保護您的引導堆疊免於刪除
如果刪除引導堆疊,則最初佈建在環境中以支援 CDK 部署 AWS 的資源也會遭到刪除。這會導致管道停止運作。如果發生這種情況,就沒有一般的復原解決方案。
環境開機後,請勿刪除並重新建立環境的開機堆疊。反之,請嘗試再次執行 cdk bootstrap
命令,將引導堆疊更新為新版本。
為了防止意外刪除您的引導堆疊,我們建議您提供 --termination-protection
選項與 cdk bootstrap
命令,以啟用終止保護。您可以在新的或現有的引導堆疊上啟用終止保護。若要進一步了解此選項,請參閱 --termination-protection
。
啟用終止保護後,您可以使用 AWS CLI 或 CloudFormation 主控台進行驗證。
啟用終止保護
-
執行下列命令,在新的或現有的引導堆疊上啟用終止保護:
$
cdk bootstrap --termination-protection
-
使用 AWS CLI 或 CloudFormation 主控台進行驗證。以下是使用 AWS CLI的範例。如果您修改了引導堆疊名稱,請將 取代
CDKToolkit
為您的堆疊名稱:$
aws cloudformation describe-stacks --stack-name
" trueCDKToolkit
--query "Stacks[0].EnableTerminationProtection
初始化專案
建立新的空白GitHub專案,並將其複製到 my-pipeline
目錄中的工作站。(本主題中的程式碼範例使用 GitHub。 您也可以使用 AWS CodeStar 或 AWS CodeCommit。)
git clone
GITHUB-CLONE-URL
my-pipeline cd my-pipeline
注意
您可以使用 my-pipeline
應用程式主目錄以外的名稱。不過,如果您這麼做,您稍後必須調整本主題中的檔案和類別名稱。這是因為 AWS CDK Toolkit 會根據主目錄的名稱來建立一些檔案和類別名稱。
複製後,照常初始化專案。
$
cdk init app --language typescript
重要
請務必將您的 cdk.json
和 cdk.context.json
檔案遞交至來源控制。內容資訊 (例如從 AWS 您的帳戶擷取的功能旗標和快取值) 是專案狀態的一部分。在其他環境中,這些值可能不同,這可能會導致結果發生意外變更。如需詳細資訊,請參閱內容值和 AWS CDK。
定義管道
您的 CDK Pipelines 應用程式將包含至少兩個堆疊:一個代表管道本身,以及一或多個代表透過它部署之應用程式的堆疊。堆疊也可以分組為階段,您可以使用這些階段將基礎設施堆疊的副本部署到不同的環境。現在,我們將考慮管道,並在稍後深入探索其將部署的應用程式。
建構CodePipeline
是代表使用 AWS CodePipeline 做為其部署引擎之 CDK 管道的建構。當您在堆疊CodePipeline
中執行個體化時,您可以定義管道的來源位置 (例如 GitHub 儲存庫)。您也可以定義建置應用程式的命令。
例如,以下定義管道,其來源存放在 GitHub 儲存庫中。它也包含 TypeScript CDK 應用程式的建置步驟。填寫 GitHub 儲存庫的相關資訊,如所示。
注意
根據預設,管道會使用存放在 Secrets Manager 中的個人存取字符,以名稱 對 GitHub 進行身分驗證github-token
。
您也需要更新管道堆疊的執行個體化,以指定 AWS 帳戶和區域。
在 lib/my-pipeline-stack.ts
(如果您的專案資料夾未命名為 ,則可能會有所差異my-pipeline
):
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
export class MyPipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const pipeline = new CodePipeline(this, 'Pipeline', {
pipelineName: 'MyPipeline',
synth: new ShellStep('Synth', {
input: CodePipelineSource.gitHub('OWNER
/REPO
', 'main'),
commands: ['npm ci', 'npm run build', 'npx cdk synth']
})
});
}
}
在 bin/my-pipeline.ts
(如果您的專案資料夾未命名為 ,則可能會有所差異my-pipeline
):
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { MyPipelineStack } from '../lib/my-pipeline-stack';
const app = new cdk.App();
new MyPipelineStack(app, 'MyPipelineStack', {
env: {
account: '111111111111
',
region: 'eu-west-1
',
}
});
app.synth();
您必須手動部署管道一次。之後,管道會讓原始程式碼儲存庫保持最新狀態。因此,請確定儲存庫中的程式碼是您想要部署的程式碼。檢查您的變更並推送至 GitHub,然後部署:
git add --all git commit -m "initial commit" git push cdk deploy
提示
現在您已完成初始部署,您的本機 AWS 帳戶不再需要管理存取權。這是因為應用程式的所有變更都會透過管道部署。您只需將 推送至 GitHub 即可。
應用程式階段
若要定義可一次新增到管道的多堆疊 AWS 應用程式,請定義 的子類別Stage
。(這與 CDK 管道模組CdkStage
中的不同。)
階段包含組成您應用程式的堆疊。如果堆疊之間存在相依性,堆疊會自動以正確的順序新增至管道。不依賴彼此的堆疊會平行部署。您可以呼叫 ,在堆疊之間新增相依關係stack1.addDependency(stack2)
。
Stages 接受預設env
引數,這會成為其中堆疊的預設環境。(堆疊仍可指定自己的環境。)
addStage()
使用 執行個體呼叫 ,將應用程式新增至管道Stage
。階段可以執行個體化並多次新增至管道,以定義 DTAP 或多區域應用程式管道的不同階段。
我們將建立包含簡單 Lambda 函數的堆疊,並將該堆疊放置在階段中。然後,我們會將階段新增至管道,以便進行部署。
建立新的檔案lib/my-pipeline-lambda-stack.ts
,以保留包含 Lambda 函數的應用程式堆疊。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Function, InlineCode, Runtime } from 'aws-cdk-lib/aws-lambda';
export class MyLambdaStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new Function(this, 'LambdaFunction', {
runtime: Runtime.NODEJS_18_X,
handler: 'index.handler',
code: new InlineCode('exports.handler = _ => "Hello, CDK";')
});
}
}
建立新的檔案lib/my-pipeline-app-stage.ts
以保留我們的階段。
import * as cdk from 'aws-cdk-lib';
import { Construct } from "constructs";
import { MyLambdaStack } from './my-pipeline-lambda-stack';
export class MyPipelineAppStage extends cdk.Stage {
constructor(scope: Construct, id: string, props?: cdk.StageProps) {
super(scope, id, props);
const lambdaStack = new MyLambdaStack(this, 'LambdaStack');
}
}
編輯 lib/my-pipeline-stack.ts
以將階段新增至我們的管道。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { MyPipelineAppStage } from './my-pipeline-app-stage';
export class MyPipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const pipeline = new CodePipeline(this, 'Pipeline', {
pipelineName: 'MyPipeline',
synth: new ShellStep('Synth', {
input: CodePipelineSource.gitHub('OWNER
/REPO
', 'main'),
commands: ['npm ci', 'npm run build', 'npx cdk synth']
})
});
pipeline.addStage(new MyPipelineAppStage(this, "test", {
env: { account: "111111111111
", region: "eu-west-1
" }
}));
}
}
由 所新增的每個應用程式階段addStage()
都會新增對應的管道階段,由addStage()
呼叫傳回的 StageDeployment 執行個體表示。您可以呼叫 或 addPost()
方法,將部署前addPre()
或部署後動作新增至階段。
// import { ManualApprovalStep } from 'aws-cdk-lib/pipelines';
const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', {
env: { account: '111111111111
', region: 'eu-west-1
' }
}));
testingStage.addPost(new ManualApprovalStep('approval'));
您可以將階段新增至 Wave 以平行部署,例如在將階段部署到多個帳戶或區域時。
const wave = pipeline.addWave('wave');
wave.addStage(new MyApplicationStage(this, 'MyAppEU', {
env: { account: '111111111111
', region: 'eu-west-1
' }
}));
wave.addStage(new MyApplicationStage(this, 'MyAppUS', {
env: { account: '111111111111
', region: 'us-west-1
' }
}));
測試部署
您可以將步驟新增至 CDK 管道,以驗證您正在執行的部署。例如,您可以使用 CDK Pipeline 程式庫的 ShellStep
來執行如下任務:
-
嘗試存取由 Lambda 函數支援的新部署 Amazon API Gateway
-
透過發出 AWS CLI 命令來檢查已部署資源的設定
在最簡單的形式中,新增驗證動作如下所示:
// stage was returned by pipeline.addStage
stage.addPost(new ShellStep("validate", {
commands: ['../tests/validate.sh'],
}));
許多 AWS CloudFormation 部署會導致產生具有不可預測名稱的資源。因此,CDK 管道提供在部署之後讀取 AWS CloudFormation 輸出的方法。這可讓您將負載平衡器產生的 URL 傳遞 (例如) 至測試動作。
若要使用輸出,請公開您感興趣的CfnOutput
物件。然後,將其傳遞到步驟的 envFromCfnOutputs
屬性中,使其在該步驟中做為環境變數使用。
// given a stack lbStack that exposes a load balancer construct as loadBalancer
this.loadBalancerAddress = new cdk.CfnOutput(lbStack, 'LbAddress', {
value: `https://${lbStack.loadBalancer.loadBalancerDnsName}/`
});
// pass the load balancer address to a shell step
stage.addPost(new ShellStep("lbaddr", {
envFromCfnOutputs: {lb_addr: lbStack.loadBalancerAddress},
commands: ['echo $lb_addr']
}));
您可以在 中直接撰寫簡單的驗證測試ShellStep
,但當測試超過幾行時,這種方法變得不明確。對於更複雜的測試,您可以透過 inputs
屬性ShellStep
將其他檔案 (例如完整的 shell 指令碼或其他語言的程式) 帶入 。輸入可以是具有輸出的任何步驟,包括來源 (例如 GitHub 儲存庫) 或其他 ShellStep
。
如果檔案可直接用於測試 (例如,如果它們本身可執行),則從來源儲存庫引入檔案是適當的。在此範例中,我們將 GitHub 儲存庫宣告為 source
(而不是將其內嵌化為 的一部分CodePipeline
)。然後,我們會將此檔案集傳遞給管道和驗證測試。
const source = CodePipelineSource.gitHub('OWNER
/REPO
', 'main');
const pipeline = new CodePipeline(this, 'Pipeline', {
pipelineName: 'MyPipeline',
synth: new ShellStep('Synth', {
input: source,
commands: ['npm ci', 'npm run build', 'npx cdk synth']
})
});
const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
env: { account: '111111111111
', region: 'eu-west-1
' }
}));
stage.addPost(new ShellStep('validate', {
input: source,
commands: ['sh ../tests/validate.sh']
}));
如果您的測試需要編譯,則從合成步驟取得其他檔案是適當的,這是合成的一部分。
const synthStep = new ShellStep('Synth', {
input: CodePipelineSource.gitHub('OWNER
/REPO
', 'main'),
commands: ['npm ci', 'npm run build', 'npx cdk synth'],
});
const pipeline = new CodePipeline(this, 'Pipeline', {
pipelineName: 'MyPipeline',
synth: synthStep
});
const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
env: { account: '111111111111
', region: 'eu-west-1
' }
}));
// run a script that was transpiled from TypeScript during synthesis
stage.addPost(new ShellStep('validate', {
input: synthStep,
commands: ['node tests/validate.js']
}));
安全注意事項
任何形式的持續交付都有固有的安全風險。在 AWS 共同責任模型
不過,就其本質而言,需要高度存取權才能實現其預期目的的程式庫無法保證完全安全。 AWS 和您的組織外有許多攻擊媒介。
尤其請記住下列事項:
-
請注意您依賴的軟體。審核您在管道中執行的所有第三方軟體,因為它可以變更要部署的基礎設施。
-
使用相依性鎖定來防止意外升級。CDK Pipelines 會尊重
package-lock.json
,yarn.lock
並確保您的相依性是您所預期的相依性。 -
CDK Pipelines 會在您自己的帳戶中建立的資源上執行,而這些資源的組態是由透過管道提交程式碼的開發人員所控制。因此,CDK 管道本身無法防範惡意開發人員嘗試略過合規檢查。如果您的威脅模型包含編寫 CDK 程式碼的開發人員,您應該具備外部合規機制,例如 AWS CloudFormation 執行角色沒有停用許可AWS CloudFormation 的勾點
(預防) 或 AWS Config (被動)。 -
生產環境的登入資料應該是短期的。在引導和初始佈建之後,開發人員完全不需要擁有帳戶登入資料。變更可以透過管道部署。一開始就不需要登入資料,以減少登入資料洩漏的可能性。
故障診斷
開始使用 CDK 管道時,通常會遇到下列問題。
- 管道:內部故障
-
CREATE_FAILED | AWS::CodePipeline::Pipeline | Pipeline/Pipeline Internal Failure
檢查您的 GitHub 存取權杖。它可能遺失,或可能沒有存取儲存庫的許可。
- 金鑰:政策包含具有一或多個無效主體的陳述式
-
CREATE_FAILED | AWS::KMS::Key | Pipeline/Pipeline/ArtifactsBucketEncryptionKey Policy contains a statement with one or more invalid principals.
其中一個目標環境尚未使用新的引導堆疊進行引導。確定您的所有目標環境都已引導。
- 堆疊處於 ROLLBACK_COMPLETE 狀態,無法更新。
-
Stack
STACK_NAME
is in ROLLBACK_COMPLETE state and can not be updated. (Service: AmazonCloudFormation; Status Code: 400; Error Code: ValidationError; Request ID: ...)堆疊失敗其先前的部署,且處於無法重試的狀態。從 AWS CloudFormation 主控台刪除堆疊,然後重試部署。