Integrazione e distribuzione continue (CI/CD) con CDK Pipelines - AWS Cloud Development Kit (AWS CDK) v2

Questa è la guida per sviluppatori AWS CDK v2. Il vecchio CDK v1 è entrato in manutenzione il 1° giugno 2022 e ha terminato il supporto il 1° giugno 2023.

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Integrazione e distribuzione continue (CI/CD) con CDK Pipelines

Utilizzate il modulo CDK Pipelines AWS della Construct Library per configurare la distribuzione continua delle applicazioni. AWS CDK Quando esegui il commit del codice sorgente della tua app CDK in AWS CodeCommit, o GitHub AWS CodeStar, CDK Pipelines può creare, testare e distribuire automaticamente la tua nuova versione.

Le CDK Pipelines si aggiornano automaticamente. Se aggiungi stadi o stack di applicazioni, la pipeline si riconfigura automaticamente per distribuire quei nuovi stadi o stack.

Nota

CDK Pipelines supporta due API. Una è l'API originale resa disponibile nella CDK Pipelines Developer Preview. L'altra è un'API moderna che incorpora il feedback dei clienti CDK ricevuto durante la fase di anteprima. Gli esempi in questo argomento utilizzano l'API moderna. Per i dettagli sulle differenze tra le due API supportate, consulta l'API originale di CDK Pipelines nel repository aws-cdk. GitHub

AWS Avvia i tuoi ambienti

Prima di poter utilizzare CDK Pipelines, è necessario avviare AWS l'ambiente in cui verranno distribuiti gli stack.

Una CDK Pipeline coinvolge almeno due ambienti. Il primo ambiente è quello in cui viene effettuato il provisioning della pipeline. Il secondo ambiente è quello in cui si desidera distribuire gli stack o le fasi dell'applicazione (le fasi sono gruppi di stack correlati). Questi ambienti possono essere uguali, ma una buona pratica è quella di isolare le fasi l'una dall'altra in ambienti diversi.

Nota

Bootstrapping (Processo di bootstrap)Per ulteriori informazioni sui tipi di risorse create dal bootstrap e su come personalizzare lo stack di bootstrap, vedi.

L'implementazione continua con CDK Pipelines richiede l'inclusione di quanto segue nello stack CDK Toolkit:

  • Un bucket Amazon Simple Storage Service (Amazon S3).

  • Un repository Amazon ECR.

  • Ruoli IAM per fornire alle varie parti di una pipeline le autorizzazioni necessarie.

Il CDK Toolkit aggiornerà lo stack di bootstrap esistente o ne creerà uno nuovo, se necessario.

Per avviare un ambiente in grado di effettuare il provisioning di una AWS CDK pipeline, cdk bootstrap richiamate come mostrato nell'esempio seguente. Se necessario, richiamando il AWS CDK Toolkit tramite il npx comando, lo si installa temporaneamente. Utilizzerà anche la versione del Toolkit installata nel progetto corrente, se ne esiste una.

--cloudformation-execution-policiesspecifica l'ARN di una policy in base alla quale verranno eseguite le future implementazioni di CDK Pipelines. La AdministratorAccess politica predefinita assicura che la pipeline possa distribuire ogni tipo di risorsa. AWS Se utilizzi questa politica, assicurati di considerare attendibile tutto il codice e le dipendenze che compongono la tua app. AWS CDK

La maggior parte delle organizzazioni impone controlli più rigorosi sui tipi di risorse che possono essere distribuite mediante l'automazione. Rivolgiti al reparto competente all'interno dell'organizzazione per determinare la politica da utilizzare nella tua pipeline.

È possibile omettere l'--profileopzione se il AWS profilo predefinito contiene la configurazione di autenticazione necessaria e. Regione AWS

macOS/Linux
npx cdk bootstrap aws://ACCOUNT-NUMBER/REGION --profile ADMIN-PROFILE \ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
Windows
npx cdk bootstrap aws://ACCOUNT-NUMBER/REGION --profile ADMIN-PROFILE ^ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess

Per avviare ambienti aggiuntivi in cui AWS CDK le applicazioni verranno distribuite dalla pipeline, utilizzate invece i seguenti comandi. L'--trustopzione indica quale altro account deve disporre delle autorizzazioni per distribuire applicazioni in questo ambiente. AWS CDK Per questa opzione, specifica l'ID dell'account della pipeline. AWS

Ancora una volta, puoi omettere l'--profileopzione se il tuo AWS profilo predefinito contiene la configurazione di autenticazione necessaria e. Regione AWS

macOS/Linux
npx cdk bootstrap aws://ACCOUNT-NUMBER/REGION --profile ADMIN-PROFILE \ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \ --trust PIPELINE-ACCOUNT-NUMBER
Windows
npx cdk bootstrap aws://ACCOUNT-NUMBER/REGION --profile ADMIN-PROFILE ^ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess ^ --trust PIPELINE-ACCOUNT-NUMBER
Suggerimento

Utilizzate le credenziali amministrative solo per il bootstrap e per il provisioning della pipeline iniziale. In seguito, utilizzate la pipeline stessa, non il computer locale, per distribuire le modifiche.

Se stai aggiornando un ambiente con bootstrap legacy, il bucket Amazon S3 precedente rimane orfano quando viene creato il nuovo bucket. Eliminalo manualmente utilizzando la console Amazon S3.

Proteggere lo stack di bootstrap dall'eliminazione

Se uno stack di bootstrap viene eliminato, verranno eliminate anche le AWS risorse originariamente fornite nell'ambiente per supportare le distribuzioni CDK. Ciò causerà l'interruzione del funzionamento della pipeline. Se ciò accade, non esiste una soluzione generale per il ripristino.

Dopo aver avviato l'ambiente, non eliminate e ricreate lo stack di bootstrap dell'ambiente. Prova invece ad aggiornare lo stack di bootstrap a una nuova versione eseguendo nuovamente il comando. cdk bootstrap

Per evitare l'eliminazione accidentale dello stack di bootstrap, ti consigliamo di fornire l'--termination-protectionopzione con il cdk bootstrap comando per abilitare la protezione dalla terminazione. È possibile abilitare la protezione dalla terminazione su stack di bootstrap nuovi o esistenti. Per ulteriori informazioni su questa opzione, consulta. --termination-protection

Dopo aver abilitato la protezione dalla terminazione, puoi utilizzare la CloudFormation console AWS CLI o per la verifica.

Per abilitare la protezione dalla terminazione
  1. Esegui il comando seguente per abilitare la protezione dalla terminazione su uno stack di bootstrap nuovo o esistente:

    $ cdk bootstrap --termination-protection
  2. Usa la CloudFormation console AWS CLI o per verificare. L'esempio seguente utilizza la AWS CLI. Se hai modificato il nome dello stack di bootstrap, sostituiscilo CDKToolkit con il nome dello stack:

    $ aws cloudformation describe-stacks --stack-name CDKToolkit --query "Stacks[0].EnableTerminationProtection" true

Inizializza un progetto

Crea un nuovo GitHub progetto vuoto e clonalo sulla tua workstation nella directory. my-pipeline (I nostri esempi di codice in questo argomento utilizzano. GitHub Puoi anche usare AWS CodeStar o AWS CodeCommit.)

git clone GITHUB-CLONE-URL my-pipeline cd my-pipeline
Nota

Puoi usare un nome diverso my-pipeline da quello della directory principale dell'app. Tuttavia, in tal caso, sarà necessario modificare i nomi dei file e delle classi più avanti in questo argomento. Questo perché il AWS CDK Toolkit basa alcuni nomi di file e classi sul nome della directory principale.

Dopo la clonazione, inizializza il progetto come al solito.

TypeScript
$ cdk init app --language typescript
JavaScript
$ cdk init app --language javascript
Python
$ cdk init app --language python

Dopo aver creato l'app, inserisci anche i due comandi seguenti. Questi attivano l'ambiente virtuale Python dell'app e installano le dipendenze AWS CDK principali.

$ source .venv/bin/activate # On Windows, run `.\venv\Scripts\activate` instead $ python -m pip install -r requirements.txt
Java
$ cdk init app --language java

Se utilizzi un IDE, ora puoi aprire o importare il progetto. In Eclipse, ad esempio, scegli File > Importa > Maven > Progetti Maven esistenti. Assicuratevi che le impostazioni del progetto siano impostate per utilizzare Java 8 (1.8).

C#
$ cdk init app --language csharp

Se utilizzi Visual Studio, apri il file della soluzione nella src directory.

Go
$ cdk init app --language go

Dopo aver creato l'app, inserisci anche il seguente comando per installare i moduli AWS Construct Library richiesti dall'app.

$ go get
Importante

Assicurati di affidare i tuoi cdk.context.json file cdk.json e i tuoi file al controllo del codice sorgente. Le informazioni di contesto (come i flag delle funzionalità e i valori memorizzati nella cache recuperati dal tuo AWS account) fanno parte dello stato del progetto. I valori possono essere diversi in un altro ambiente, il che può causare cambiamenti imprevisti nei risultati. Per ulteriori informazioni, consulta Contesto di runtime.

Definire una pipeline

L'applicazione CDK Pipelines includerà almeno due stack: uno che rappresenta la pipeline stessa e uno o più stack che rappresentano l'applicazione distribuita attraverso di essa. Gli stack possono anche essere raggruppati in fasi, che è possibile utilizzare per distribuire copie degli stack di infrastruttura in ambienti diversi. Per ora, prenderemo in considerazione la pipeline e in seguito approfondiremo l'applicazione che verrà implementata.

Il costrutto CodePipelineè il costrutto che rappresenta una CDK Pipeline che utilizza come motore di distribuzione. AWS CodePipeline Quando si crea un'istanza CodePipeline in uno stack, si definisce la posizione di origine della pipeline (ad esempio un repository). GitHub Definisci anche i comandi per creare l'app.

Ad esempio, quanto segue definisce una pipeline la cui origine è archiviata in un GitHub repository. Include anche una fase di compilazione per un'applicazione TypeScript CDK. Inserisci le informazioni sul tuo GitHub repo dove indicato.

Nota

Per impostazione predefinita, la pipeline si autentica GitHub utilizzando un token di accesso personale memorizzato in Secrets Manager sotto il nome. github-token

Dovrai anche aggiornare l'istanza dello stack di pipeline per specificare l'account e la regione. AWS

TypeScript

In lib/my-pipeline-stack.ts (può variare se la cartella del progetto non ha un nome): 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'] }) }); } }

In bin/my-pipeline.ts (può variare se la cartella del progetto non ha un nomemy-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();
JavaScript

In lib/my-pipeline-stack.js (può variare se la cartella del progetto non ha un nomemy-pipeline):

const cdk = require('aws-cdk-lib'); const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines'); class MyPipelineStack extends cdk.Stack { constructor(scope, id, props) { 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'] }) }); } } module.exports = { MyPipelineStack }

In bin/my-pipeline.js (può variare se la cartella del progetto non ha un nomemy-pipeline):

#!/usr/bin/env node const cdk = require('aws-cdk-lib'); const { MyPipelineStack } = require('../lib/my-pipeline-stack'); const app = new cdk.App(); new MyPipelineStack(app, 'MyPipelineStack', { env: { account: '111111111111', region: 'eu-west-1', } }); app.synth();
Python

In my-pipeline/my-pipeline-stack.py (può variare se la cartella del progetto non ha un nomemy-pipeline):

import aws_cdk as cdk from constructs import Construct from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep class MyPipelineStack(cdk.Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) pipeline = CodePipeline(self, "Pipeline", pipeline_name="MyPipeline", synth=ShellStep("Synth", input=CodePipelineSource.git_hub("OWNER/REPO", "main"), commands=["npm install -g aws-cdk", "python -m pip install -r requirements.txt", "cdk synth"] ) )

In app.py:

#!/usr/bin/env python3 import aws_cdk as cdk from my_pipeline.my_pipeline_stack import MyPipelineStack app = cdk.App() MyPipelineStack(app, "MyPipelineStack", env=cdk.Environment(account="111111111111", region="eu-west-1") ) app.synth()
Java

In src/main/java/com/myorg/MyPipelineStack.java (può variare se la cartella del progetto non ha un nomemy-pipeline):

package com.myorg; import java.util.Arrays; import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import software.amazon.awscdk.pipelines.CodePipeline; import software.amazon.awscdk.pipelines.CodePipelineSource; import software.amazon.awscdk.pipelines.ShellStep; public class MyPipelineStack extends Stack { public MyPipelineStack(final Construct scope, final String id) { this(scope, id, null); } public MyPipelineStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline") .pipelineName("MyPipeline") .synth(ShellStep.Builder.create("Synth") .input(CodePipelineSource.gitHub("OWNER/REPO", "main")) .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth")) .build()) .build(); } }

In src/main/java/com/myorg/MyPipelineApp.java (può variare se la cartella del progetto non ha un nomemy-pipeline):

package com.myorg; import software.amazon.awscdk.App; import software.amazon.awscdk.Environment; import software.amazon.awscdk.StackProps; public class MyPipelineApp { public static void main(final String[] args) { App app = new App(); new MyPipelineStack(app, "PipelineStack", StackProps.builder() .env(Environment.builder() .account("111111111111") .region("eu-west-1") .build()) .build()); app.synth(); } }
C#

In src/MyPipeline/MyPipelineStack.cs (può variare se la cartella del progetto non ha un nomemy-pipeline):

using Amazon.CDK; using Amazon.CDK.Pipelines; namespace MyPipeline { public class MyPipelineStack : Stack { internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps { PipelineName = "MyPipeline", Synth = new ShellStep("Synth", new ShellStepProps { Input = CodePipelineSource.GitHub("OWNER/REPO", "main"), Commands = new string[] { "npm install -g aws-cdk", "cdk synth" } }) }); } } }

In src/MyPipeline/Program.cs (può variare se la cartella del progetto non ha un nomemy-pipeline):

using Amazon.CDK; namespace MyPipeline { sealed class Program { public static void Main(string[] args) { var app = new App(); new MyPipelineStack(app, "MyPipelineStack", new StackProps { Env = new Amazon.CDK.Environment { Account = "111111111111", Region = "eu-west-1" } }); app.Synth(); } } }
Go
package main import ( "github.com/aws/aws-cdk-go/awscdk/v2" codebuild "github.com/aws/aws-cdk-go/awscdk/v2/awscodebuild" ssm "github.com/aws/aws-cdk-go/awscdk/v2/awsssm" pipeline "github.com/aws/aws-cdk-go/awscdk/v2/pipelines" "github.com/aws/constructs-go/constructs/v10" "github.com/aws/jsii-runtime-go" "os" ) // my CDK Stack with resources func NewCdkStack(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack { stack := awscdk.NewStack(scope, id, props) // create an example ssm parameter _ = ssm.NewStringParameter(stack, jsii.String("ssm-test-param"), &ssm.StringParameterProps{ ParameterName: jsii.String("/testparam"), Description: jsii.String("ssm parameter for demo"), StringValue: jsii.String("my test param"), }) return stack } // my CDK Application func NewCdkApplication(scope constructs.Construct, id *string, props *awscdk.StageProps) awscdk.Stage { stage := awscdk.NewStage(scope, id, props) _ = NewCdkStack(stage, jsii.String("cdk-stack"), &awscdk.StackProps{Env: props.Env}) return stage } // my CDK Pipeline func NewCdkPipeline(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack { stack := awscdk.NewStack(scope, id, props) // GitHub repo with owner and repository name githubRepo := pipeline.CodePipelineSource_GitHub(jsii.String("owner/repo"), jsii.String("main"), &pipeline.GitHubSourceOptions{ Authentication: awscdk.SecretValue_SecretsManager(jsii.String("my-github-token"), nil), }) // self mutating pipeline myPipeline := pipeline.NewCodePipeline(stack, jsii.String("cdkPipeline"), &pipeline.CodePipelineProps{ PipelineName: jsii.String("CdkPipeline"), // self mutation true - pipeline changes itself before application deployment SelfMutation: jsii.Bool(true), CodeBuildDefaults: &pipeline.CodeBuildOptions{ BuildEnvironment: &codebuild.BuildEnvironment{ // image version 6.0 recommended for newer go version BuildImage: codebuild.LinuxBuildImage_FromCodeBuildImageId(jsii.String("aws/codebuild/standard:6.0")), }, }, Synth: pipeline.NewCodeBuildStep(jsii.String("Synth"), &pipeline.CodeBuildStepProps{ Input: githubRepo, Commands: &[]*string{ jsii.String("npm install -g aws-cdk"), jsii.String("cdk synth"), }, }), }) // deployment of actual CDK application myPipeline.AddStage(NewCdkApplication(stack, jsii.String("MyApplication"), &awscdk.StageProps{ Env: targetAccountEnv(), }), &pipeline.AddStageOpts{ Post: &[]pipeline.Step{ pipeline.NewCodeBuildStep(jsii.String("Manual Steps"), &pipeline.CodeBuildStepProps{ Commands: &[]*string{ jsii.String("echo \"My CDK App deployed, manual steps go here ... \""), }, }), }, }) return stack } // main app func main() { defer jsii.Close() app := awscdk.NewApp(nil) // call CDK Pipeline NewCdkPipeline(app, jsii.String("CdkPipelineStack"), &awscdk.StackProps{ Env: pipelineEnv(), }) app.Synth(nil) } // env determines the AWS environment (account+region) in which our stack is to // be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html func pipelineEnv() *awscdk.Environment { return &awscdk.Environment{ Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")), Region: jsii.String(os.Getenv("CDK_DEFAULT_REGION")), } } func targetAccountEnv() *awscdk.Environment { return &awscdk.Environment{ Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")), Region: jsii.String(os.Getenv("CDK_DEFAULT_REGION")), } }

È necessario distribuire una pipeline manualmente una volta. Dopodiché, la pipeline si aggiorna dal repository del codice sorgente. Quindi assicurati che il codice nel repository sia il codice che desideri distribuire. Controlla le modifiche e invia a GitHub, quindi distribuisci:

git add --all git commit -m "initial commit" git push cdk deploy
Suggerimento

Ora che hai completato la distribuzione iniziale, il tuo AWS account locale non necessita più dell'accesso amministrativo. Questo perché tutte le modifiche all'app verranno distribuite tramite la pipeline. Tutto quello che devi fare è premere su. GitHub

Fasi dell'applicazione

Per definire un' AWS applicazione multi-stack che può essere aggiunta alla pipeline tutta in una volta, definite una sottoclasse di. Stage (Questo è diverso dal modulo CdkStage CDK Pipelines.)

Lo stage contiene gli stack che compongono l'applicazione. Se esistono dipendenze tra gli stack, gli stack vengono aggiunti automaticamente alla pipeline nell'ordine corretto. Gli stack che non dipendono l'uno dall'altro vengono distribuiti in parallelo. Puoi aggiungere una relazione di dipendenza tra gli stack chiamando. stack1.addDependency(stack2)

Gli stadi accettano un env argomento predefinito, che diventa l'ambiente predefinito per gli stack al suo interno. (Gli stack possono comunque avere il proprio ambiente specificato.).

Un'applicazione viene aggiunta alla pipeline chiamando addStage() con istanze di. Stage Una fase può essere istanziata e aggiunta alla pipeline più volte per definire fasi diverse della pipeline di applicazioni DTAP o multiregione.

Creeremo uno stack contenente una semplice funzione Lambda e lo posizioneremo in uno stage. Quindi aggiungeremo lo stage alla pipeline in modo che possa essere distribuito.

TypeScript

Crea il nuovo file lib/my-pipeline-lambda-stack.ts per contenere il nostro stack di applicazioni contenente una funzione 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";') }); } }

Crea il nuovo file lib/my-pipeline-app-stage.ts per ospitare il nostro palco.

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'); } }

Modifica lib/my-pipeline-stack.ts per aggiungere lo stage alla nostra pipeline.

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" } })); } }
JavaScript

Crea il nuovo file lib/my-pipeline-lambda-stack.js per contenere il nostro stack di applicazioni contenente una funzione Lambda.

const cdk = require('aws-cdk-lib'); const { Function, InlineCode, Runtime } = require('aws-cdk-lib/aws-lambda'); class MyLambdaStack extends cdk.Stack { constructor(scope, id, props) { super(scope, id, props); new Function(this, 'LambdaFunction', { runtime: Runtime.NODEJS_18_X, handler: 'index.handler', code: new InlineCode('exports.handler = _ => "Hello, CDK";') }); } } module.exports = { MyLambdaStack }

Crea il nuovo file lib/my-pipeline-app-stage.js per ospitare il nostro palco.

const cdk = require('aws-cdk-lib'); const { MyLambdaStack } = require('./my-pipeline-lambda-stack'); class MyPipelineAppStage extends cdk.Stage { constructor(scope, id, props) { super(scope, id, props); const lambdaStack = new MyLambdaStack(this, 'LambdaStack'); } } module.exports = { MyPipelineAppStage };

Modifica lib/my-pipeline-stack.ts per aggiungere lo stage alla nostra pipeline.

const cdk = require('aws-cdk-lib'); const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines'); const { MyPipelineAppStage } = require('./my-pipeline-app-stage'); class MyPipelineStack extends cdk.Stack { constructor(scope, id, props) { 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" } })); } } module.exports = { MyPipelineStack }
Python

Crea il nuovo file my_pipeline/my_pipeline_lambda_stack.py per contenere il nostro stack di applicazioni contenente una funzione Lambda.

import aws_cdk as cdk from constructs import Construct from aws_cdk.aws_lambda import Function, InlineCode, Runtime class MyLambdaStack(cdk.Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) Function(self, "LambdaFunction", runtime=Runtime.NODEJS_18_X, handler="index.handler", code=InlineCode("exports.handler = _ => 'Hello, CDK';") )

Crea il nuovo file my_pipeline/my_pipeline_app_stage.py per ospitare il nostro palco.

import aws_cdk as cdk from constructs import Construct from my_pipeline.my_pipeline_lambda_stack import MyLambdaStack class MyPipelineAppStage(cdk.Stage): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) lambdaStack = MyLambdaStack(self, "LambdaStack")

Modifica my_pipeline/my-pipeline-stack.py per aggiungere lo stage alla nostra pipeline.

import aws_cdk as cdk from constructs import Construct from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep from my_pipeline.my_pipeline_app_stage import MyPipelineAppStage class MyPipelineStack(cdk.Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) pipeline = CodePipeline(self, "Pipeline", pipeline_name="MyPipeline", synth=ShellStep("Synth", input=CodePipelineSource.git_hub("OWNER/REPO", "main"), commands=["npm install -g aws-cdk", "python -m pip install -r requirements.txt", "cdk synth"])) pipeline.add_stage(MyPipelineAppStage(self, "test", env=cdk.Environment(account="111111111111", region="eu-west-1")))
Java

Crea il nuovo file src/main/java/com.myorg/MyPipelineLambdaStack.java per contenere il nostro stack di applicazioni contenente una funzione Lambda.

package com.myorg; import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import software.amazon.awscdk.services.lambda.Function; import software.amazon.awscdk.services.lambda.Runtime; import software.amazon.awscdk.services.lambda.InlineCode; public class MyPipelineLambdaStack extends Stack { public MyPipelineLambdaStack(final Construct scope, final String id) { this(scope, id, null); } public MyPipelineLambdaStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); Function.Builder.create(this, "LambdaFunction") .runtime(Runtime.NODEJS_18_X) .handler("index.handler") .code(new InlineCode("exports.handler = _ => 'Hello, CDK';")) .build(); } }

Crea il nuovo file src/main/java/com.myorg/MyPipelineAppStage.java per ospitare il nostro palco.

package com.myorg; import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.Stage; import software.amazon.awscdk.StageProps; public class MyPipelineAppStage extends Stage { public MyPipelineAppStage(final Construct scope, final String id) { this(scope, id, null); } public MyPipelineAppStage(final Construct scope, final String id, final StageProps props) { super(scope, id, props); Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack"); } }

Modifica src/main/java/com.myorg/MyPipelineStack.java per aggiungere lo stage alla nostra pipeline.

package com.myorg; import java.util.Arrays; import software.constructs.Construct; import software.amazon.awscdk.Environment; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import software.amazon.awscdk.StageProps; import software.amazon.awscdk.pipelines.CodePipeline; import software.amazon.awscdk.pipelines.CodePipelineSource; import software.amazon.awscdk.pipelines.ShellStep; public class MyPipelineStack extends Stack { public MyPipelineStack(final Construct scope, final String id) { this(scope, id, null); } public MyPipelineStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline") .pipelineName("MyPipeline") .synth(ShellStep.Builder.create("Synth") .input(CodePipelineSource.gitHub("OWNER/REPO", "main")) .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth")) .build()) .build(); pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder() .env(Environment.builder() .account("111111111111") .region("eu-west-1") .build()) .build())); } }
C#

Crea il nuovo file src/MyPipeline/MyPipelineLambdaStack.cs per contenere il nostro stack di applicazioni contenente una funzione Lambda.

using Amazon.CDK; using Constructs; using Amazon.CDK.AWS.Lambda; namespace MyPipeline { class MyPipelineLambdaStack : Stack { public MyPipelineLambdaStack(Construct scope, string id, StackProps props=null) : base(scope, id, props) { new Function(this, "LambdaFunction", new FunctionProps { Runtime = Runtime.NODEJS_18_X, Handler = "index.handler", Code = new InlineCode("exports.handler = _ => 'Hello, CDK';") }); } } }

Crea il nuovo file src/MyPipeline/MyPipelineAppStage.cs per ospitare il nostro palco.

using Amazon.CDK; using Constructs; namespace MyPipeline { class MyPipelineAppStage : Stage { public MyPipelineAppStage(Construct scope, string id, StageProps props=null) : base(scope, id, props) { Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack"); } } }

Modifica src/MyPipeline/MyPipelineStack.cs per aggiungere lo stage alla nostra pipeline.

using Amazon.CDK; using Constructs; using Amazon.CDK.Pipelines; namespace MyPipeline { public class MyPipelineStack : Stack { internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps { PipelineName = "MyPipeline", Synth = new ShellStep("Synth", new ShellStepProps { Input = CodePipelineSource.GitHub("OWNER/REPO", "main"), Commands = new string[] { "npm install -g aws-cdk", "cdk synth" } }) }); pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps { Env = new Environment { Account = "111111111111", Region = "eu-west-1" } })); } } }

Ogni fase dell'applicazione aggiunta da addStage() comporta l'aggiunta di una fase della pipeline corrispondente, rappresentata da un'StageDeploymentistanza restituita dalla addStage() chiamata. È possibile aggiungere azioni di pre-distribuzione o post-distribuzione alla fase chiamandone addPre() il metodo or. addPost()

TypeScript
// 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'));
JavaScript
// const { ManualApprovalStep } = require('aws-cdk-lib/pipelines'); const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', { env: { account: '111111111111', region: 'eu-west-1' } })); testingStage.addPost(new ManualApprovalStep('approval'));
Python
# from aws_cdk.pipelines import ManualApprovalStep testing_stage = pipeline.add_stage(MyPipelineAppStage(self, "testing", env=cdk.Environment(account="111111111111", region="eu-west-1"))) testing_stage.add_post(ManualApprovalStep('approval'))
Java
// import software.amazon.awscdk.pipelines.StageDeployment; // import software.amazon.awscdk.pipelines.ManualApprovalStep; StageDeployment testingStage = pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder() .env(Environment.builder() .account("111111111111") .region("eu-west-1") .build()) .build())); testingStage.addPost(new ManualApprovalStep("approval"));
C#
var testingStage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps { Env = new Environment { Account = "111111111111", Region = "eu-west-1" } })); testingStage.AddPost(new ManualApprovalStep("approval"));

Puoi aggiungere fasi a un Wave per distribuirle in parallelo, ad esempio quando distribuisci una fase su più account o regioni.

TypeScript
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' } }));
JavaScript
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' } }));
Python
wave = pipeline.add_wave("wave") wave.add_stage(MyApplicationStage(self, "MyAppEU", env=cdk.Environment(account="111111111111", region="eu-west-1"))) wave.add_stage(MyApplicationStage(self, "MyAppUS", env=cdk.Environment(account="111111111111", region="us-west-1")))
Java
// import software.amazon.awscdk.pipelines.Wave; final Wave wave = pipeline.addWave("wave"); wave.addStage(new MyPipelineAppStage(this, "MyAppEU", StageProps.builder() .env(Environment.builder() .account("111111111111") .region("eu-west-1") .build()) .build())); wave.addStage(new MyPipelineAppStage(this, "MyAppUS", StageProps.builder() .env(Environment.builder() .account("111111111111") .region("us-west-1") .build()) .build()));
C#
var wave = pipeline.AddWave("wave"); wave.AddStage(new MyPipelineAppStage(this, "MyAppEU", new StageProps { Env = new Environment { Account = "111111111111", Region = "eu-west-1" } })); wave.AddStage(new MyPipelineAppStage(this, "MyAppUS", new StageProps { Env = new Environment { Account = "111111111111", Region = "us-west-1" } }));

Test delle implementazioni

Puoi aggiungere passaggi a una pipeline CDK per convalidare le distribuzioni che stai eseguendo. Ad esempio, puoi utilizzare le librerie CDK Pipeline per eseguire attività come ShellStep le seguenti:

  • Tentativo di accesso a un Amazon API Gateway appena distribuito supportato da una funzione Lambda

  • Verifica dell'impostazione di una risorsa distribuita mediante l'emissione di un comando AWS CLI

Nella sua forma più semplice, l'aggiunta di azioni di convalida è la seguente:

TypeScript
// stage was returned by pipeline.addStage stage.addPost(new ShellStep("validate", { commands: ['../tests/validate.sh'], }));
JavaScript
// stage was returned by pipeline.addStage stage.addPost(new ShellStep("validate", { commands: ['../tests/validate.sh'], }));
Python
# stage was returned by pipeline.add_stage stage.add_post(ShellStep("validate", commands=[''../tests/validate.sh''] ))
Java
// stage was returned by pipeline.addStage stage.addPost(ShellStep.Builder.create("validate") .commands(Arrays.asList("'../tests/validate.sh'")) .build());
C#
// stage was returned by pipeline.addStage stage.AddPost(new ShellStep("validate", new ShellStepProps { Commands = new string[] { "'../tests/validate.sh'" } }));

Molte AWS CloudFormation implementazioni comportano la generazione di risorse con nomi imprevedibili. Per questo motivo, CDK Pipelines fornisce un modo per AWS CloudFormation leggere gli output dopo una distribuzione. In questo modo è possibile passare (ad esempio) l'URL generato di un sistema di bilanciamento del carico a un'azione di test.

Per utilizzare gli output, esponi l'CfnOutputoggetto che ti interessa. Quindi, passalo nella envFromCfnOutputs proprietà di un passaggio per renderlo disponibile come variabile di ambiente all'interno di quel passaggio.

TypeScript
// 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'] }));
JavaScript
// 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'] }));
Python
# given a stack lb_stack that exposes a load balancer construct as load_balancer self.load_balancer_address = cdk.CfnOutput(lb_stack, "LbAddress", value=f"https://{lb_stack.load_balancer.load_balancer_dns_name}/") # pass the load balancer address to a shell step stage.add_post(ShellStep("lbaddr", env_from_cfn_outputs={"lb_addr": lb_stack.load_balancer_address} commands=["echo $lb_addr"]))
Java
// given a stack lbStack that exposes a load balancer construct as loadBalancer loadBalancerAddress = CfnOutput.Builder.create(lbStack, "LbAddress") .value(String.format("https://%s/", lbStack.loadBalancer.loadBalancerDnsName)) .build(); stage.addPost(ShellStep.Builder.create("lbaddr") .envFromCfnOutputs( // Map.of requires Java 9 or later java.util.Map.of("lbAddr", loadBalancerAddress)) .commands(Arrays.asList("echo $lbAddr")) .build());
C#
// given a stack lbStack that exposes a load balancer construct as loadBalancer loadBalancerAddress = new CfnOutput(lbStack, "LbAddress", new CfnOutputProps { Value = string.Format("https://{0}/", lbStack.loadBalancer.LoadBalancerDnsName) }); stage.AddPost(new ShellStep("lbaddr", new ShellStepProps { EnvFromCfnOutputs = new Dictionary<string, CfnOutput> { { "lbAddr", loadBalancerAddress } }, Commands = new string[] { "echo $lbAddr" } }));

Puoi scrivere semplici test di convalida direttamente inShellStep, ma questo approccio diventa complicato quando il test dura più di poche righe. Per test più complessi, potete inserire file aggiuntivi (come script di shell completi o programmi in altri linguaggi) nella proprietà tramite the. ShellStep inputs Gli input possono essere qualsiasi passaggio che abbia un output, inclusa una fonte (come un GitHub repository) o un'altra. ShellStep

L'inserimento di file dal repository dei sorgenti è appropriato se i file sono direttamente utilizzabili nel test (ad esempio, se sono essi stessi eseguibili). In questo esempio, dichiariamo il nostro GitHub repository come source (anziché istanziarlo in linea come parte di). CodePipeline Quindi, passiamo questo set di file sia alla pipeline che al test di convalida.

TypeScript
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'] }));
JavaScript
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'] }));
Python
source = CodePipelineSource.git_hub("OWNER/REPO", "main") pipeline = CodePipeline(self, "Pipeline", pipeline_name="MyPipeline", synth=ShellStep("Synth", input=source, commands=["npm install -g aws-cdk", "python -m pip install -r requirements.txt", "cdk synth"])) stage = pipeline.add_stage(MyApplicationStage(self, "test", env=cdk.Environment(account="111111111111", region="eu-west-1"))) stage.add_post(ShellStep("validate", input=source, commands=["sh ../tests/validate.sh"], ))
Java
final CodePipelineSource source = CodePipelineSource.gitHub("OWNER/REPO", "main"); final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline") .pipelineName("MyPipeline") .synth(ShellStep.Builder.create("Synth") .input(source) .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth")) .build()) .build(); final StageDeployment stage = pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder() .env(Environment.builder() .account("111111111111") .region("eu-west-1") .build()) .build())); stage.addPost(ShellStep.Builder.create("validate") .input(source) .commands(Arrays.asList("sh ../tests/validate.sh")) .build());
C#
var source = CodePipelineSource.GitHub("OWNER/REPO", "main"); var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps { PipelineName = "MyPipeline", Synth = new ShellStep("Synth", new ShellStepProps { Input = source, Commands = new string[] { "npm install -g aws-cdk", "cdk synth" } }) }); var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps { Env = new Environment { Account = "111111111111", Region = "eu-west-1" } })); stage.AddPost(new ShellStep("validate", new ShellStepProps { Input = source, Commands = new string[] { "sh ../tests/validate.sh" } }));

Ottenere i file aggiuntivi dalla fase di sintetizzazione è appropriato se i test devono essere compilati, operazione che viene eseguita come parte della sintesi.

TypeScript
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'] }));
JavaScript
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'] }));
Python
synth_step = ShellStep("Synth", input=CodePipelineSource.git_hub("OWNER/REPO", "main"), commands=["npm install -g aws-cdk", "python -m pip install -r requirements.txt", "cdk synth"]) pipeline = CodePipeline(self, "Pipeline", pipeline_name="MyPipeline", synth=synth_step) stage = pipeline.add_stage(MyApplicationStage(self, "test", env=cdk.Environment(account="111111111111", region="eu-west-1"))) # run a script that was compiled during synthesis stage.add_post(ShellStep("validate", input=synth_step, commands=["node test/validate.js"], ))
Java
final ShellStep synth = ShellStep.Builder.create("Synth") .input(CodePipelineSource.gitHub("OWNER/REPO", "main")) .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth")) .build(); final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline") .pipelineName("MyPipeline") .synth(synth) .build(); final StageDeployment stage = pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder() .env(Environment.builder() .account("111111111111") .region("eu-west-1") .build()) .build())); stage.addPost(ShellStep.Builder.create("validate") .input(synth) .commands(Arrays.asList("node ./tests/validate.js")) .build());
C#
var synth = new ShellStep("Synth", new ShellStepProps { Input = CodePipelineSource.GitHub("OWNER/REPO", "main"), Commands = new string[] { "npm install -g aws-cdk", "cdk synth" } }); var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps { PipelineName = "MyPipeline", Synth = synth }); var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps { Env = new Environment { Account = "111111111111", Region = "eu-west-1" } })); stage.AddPost(new ShellStep("validate", new ShellStepProps { Input = synth, Commands = new string[] { "node ./tests/validate.js" } }));

Note sulla sicurezza

Qualsiasi forma di distribuzione continua presenta rischi intrinseci per la sicurezza. In base al modello di responsabilità AWS condivisa, sei responsabile della sicurezza delle tue informazioni nel AWS cloud. La libreria CDK Pipelines ti offre un vantaggio iniziale incorporando impostazioni predefinite sicure e best practice di modellazione.

Tuttavia, per sua stessa natura, una libreria che necessita di un elevato livello di accesso per soddisfare lo scopo previsto non può garantire una sicurezza completa. Esistono molti vettori di attacco esterni AWS all'organizzazione.

In particolare, tenete presente quanto segue:

  • Fai attenzione al software da cui dipendi. Controlla tutti i software di terze parti che utilizzi nella tua pipeline, perché possono modificare l'infrastruttura che viene implementata.

  • Utilizza il blocco delle dipendenze per evitare aggiornamenti accidentali. CDK Pipelines package-lock.json rispetta yarn.lock e si assicura che le vostre dipendenze siano quelle che vi aspettate.

  • CDK Pipelines funziona con risorse create nel tuo account e la configurazione di tali risorse è controllata dagli sviluppatori che inviano il codice tramite la pipeline. Pertanto, CDK Pipelines da solo non può proteggere da sviluppatori malintenzionati che cercano di aggirare i controlli di conformità. Se il tuo modello di minaccia include sviluppatori che scrivono codice CDK, dovresti disporre di meccanismi di conformità esterni come AWS CloudFormation Hooks (preventivo) o AWS Config (reattivo) che l' AWS CloudFormation Execution Role non dispone delle autorizzazioni per disabilitare.

  • Le credenziali per gli ambienti di produzione dovrebbero avere vita breve. Dopo il bootstrap e il provisioning iniziale, non è affatto necessario che gli sviluppatori dispongano delle credenziali dell'account. Le modifiche possono essere implementate tramite la pipeline. Riduci la possibilità di perdita delle credenziali evitando innanzitutto di averne bisogno.

Risoluzione dei problemi

I seguenti problemi si riscontrano comunemente quando si inizia a usare CDK Pipelines.

Pipeline: errore interno
CREATE_FAILED  | AWS::CodePipeline::Pipeline | Pipeline/Pipeline
Internal Failure

Controlla il tuo token di GitHub accesso. Potrebbe mancare o potrebbe non disporre delle autorizzazioni per accedere al repository.

Chiave: La policy contiene una dichiarazione con uno o più principi non validi
CREATE_FAILED | AWS::KMS::Key | Pipeline/Pipeline/ArtifactsBucketEncryptionKey
Policy contains a statement with one or more invalid principals.

Uno degli ambienti di destinazione non è stato avviato con il nuovo stack bootstrap. Assicurati che tutti gli ambienti di destinazione siano avviati.

Lo stack è nello stato ROLLBACK_COMPLETE e non può essere aggiornato.
Stack STACK_NAME is in ROLLBACK_COMPLETE state and can not be updated. (Service:
AmazonCloudFormation; Status Code: 400; Error Code: ValidationError; Request
ID: ...)

Lo stack non è riuscito nella distribuzione precedente ed è in uno stato non riutilizzabile. Elimina lo stack dalla AWS CloudFormation console e riprova la distribuzione.