CDK Pipeline을 사용한 지속적 통합 및 전달 (CI/CD) - AWS Cloud Development Kit (AWS CDK) v2

AWS CDK v2 개발자 안내서입니다. 구형 CDK v1은 2022년 6월 1일에 유지 보수에 들어갔고 2023년 6월 1일에 지원이 종료되었습니다.

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

CDK Pipeline을 사용한 지속적 통합 및 전달 (CI/CD)

구성 라이브러리의 CDK Pipelines 모듈을 사용하여 애플리케이션의 지속적 AWS 딜리버리를 구성할 수 있습니다. AWS CDK CDK 앱의 소스 코드를 AWS CodeCommitGitHub, 또는 AWS CodeStar에 커밋하면 CDK Pipelines에서 자동으로 새 버전을 빌드, 테스트, 배포할 수 있습니다.

CDK 파이프라인은 자동으로 업데이트됩니다. 애플리케이션 스테이지 또는 스택을 추가하면 파이프라인이 자동으로 재구성되어 새 스테이지 또는 스택을 배포합니다.

참고

CDK 파이프라인은 두 가지 API를 지원합니다. 하나는 CDK Pipelines 개발자 프리뷰에서 사용할 수 있는 오리지널 API입니다. 다른 하나는 프리뷰 단계에서 받은 CDK 고객의 피드백을 통합한 최신 API입니다. 이 항목의 예시에서는 최신 API를 사용합니다. 지원되는 두 API 간의 차이점에 대한 자세한 내용은 aws-cdk 리포지토리의 CDK Pipelines 원본 API를 참조하십시오. GitHub

환경을 부트스트랩하세요. AWS

CDK Pipelines를 사용하려면 먼저 스택을 배포할 환경을 AWS 부트스트랩해야 합니다.

CDK 파이프라인에는 최소 두 개의 환경이 포함됩니다. 첫 번째 환경은 파이프라인이 프로비저닝되는 곳입니다. 두 번째 환경은 애플리케이션의 스택 또는 스테이지를 배포하려는 곳입니다 (스테이지는 관련 스택 그룹). 이러한 환경은 동일할 수 있지만 모범 사례 권장 사항은 서로 다른 환경에서 단계를 서로 격리하는 것입니다.

참고

부트스트랩으로 생성되는 리소스의 종류 및 부트스트랩 스택을 사용자 지정하는 방법에 AWS CDK 부트스트래핑 대한 자세한 내용은 을 참조하십시오.

CDK Pipeline을 사용하여 지속적으로 배포하려면 CDK Toolkit 스택에 다음을 포함해야 합니다.

  • Amazon Simple Storage Service(S3) 버킷

  • 아마존 ECR 리포지토리.

  • 파이프라인의 다양한 부분에 필요한 권한을 부여하는 IAM 역할.

CDK 툴킷은 기존 부트스트랩 스택을 업그레이드하거나 필요한 경우 새 부트스트랩 스택을 생성합니다.

AWS CDK 파이프라인을 프로비저닝할 수 있는 환경을 부트스트랩하려면 다음 cdk bootstrap 예와 같이 호출하십시오. 필요한 경우 npx 명령을 통해 AWS CDK 툴킷을 호출하면 툴킷이 임시로 설치됩니다. 또한 현재 프로젝트에 설치된 툴킷 버전 (있는 경우) 도 사용됩니다.

--cloudformation-execution-policies향후 CDK Pipelines 배포가 실행될 정책의 ARN을 지정합니다. 기본 AdministratorAccess 정책은 파이프라인이 모든 유형의 리소스를 배포할 수 있도록 합니다. AWS 이 정책을 사용하는 경우 AWS CDK 앱을 구성하는 모든 코드와 종속성을 신뢰해야 합니다.

대부분의 조직에서는 자동화를 통해 배포할 수 있는 리소스 종류에 대해 더 엄격한 제어를 요구합니다. 파이프라인에서 사용해야 하는 정책을 결정하려면 조직 내 해당 부서에 문의하세요.

기본 AWS 프로필에 필요한 인증 구성 및 AWS 리전이 포함되어 있는 경우 이 --profile 옵션을 생략할 수 있습니다.

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

파이프라인에서 AWS CDK 애플리케이션을 배포할 추가 환경을 부트스트랩하려면 다음 명령을 대신 사용하십시오. --trust옵션은 이 환경에 AWS CDK 애플리케이션을 배포할 수 있는 권한을 가져야 하는 다른 계정을 나타냅니다. 이 옵션의 경우 파이프라인의 AWS 계정 ID를 지정합니다.

다시 말하지만, 기본 AWS 프로필에 필요한 인증 구성 및 AWS 리전이 포함되어 있으면 이 --profile 옵션을 생략할 수 있습니다.

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
작은 정보

관리 자격 증명은 초기 파이프라인을 부트스트랩하고 프로비저닝할 때만 사용하십시오. 이후에는 로컬 컴퓨터가 아닌 파이프라인 자체를 사용하여 변경 내용을 배포하세요.

기존 부트스트랩 환경을 업그레이드하는 경우 새 버킷이 생성되면 이전 Amazon S3 버킷이 분리됩니다. Amazon S3 콘솔을 사용하여 수동으로 삭제합니다.

부트스트랩 스택이 삭제되지 않도록 보호

부트스트랩 스택이 삭제되면 CDK 배포를 지원하기 위해 해당 환경에 원래 프로비저닝된 AWS 리소스도 삭제됩니다. 그러면 파이프라인 작동이 중지됩니다. 이 경우 복구를 위한 일반적인 해결 방법은 없습니다.

환경을 부트스트랩한 후에는 해당 환경의 부트스트랩 스택을 삭제하고 다시 만들지 마십시오. 대신 명령을 다시 실행하여 부트스트랩 스택을 새 버전으로 업데이트해 보십시오. cdk bootstrap

부트스트랩 스택이 실수로 삭제되는 것을 방지하려면 종료 보호를 활성화하는 cdk bootstrap 명령과 함께 --termination-protection 옵션을 제공하는 것이 좋습니다. 새 부트스트랩 스택이나 기존 부트스트랩 스택에서 종료 보호를 활성화할 수 있습니다. 이 옵션에 대한 자세한 내용은 을 참조하십시오. --termination-protection

종료 보호를 활성화한 후 AWS CLI 또는 CloudFormation 콘솔을 사용하여 확인할 수 있습니다.

종료 보호를 활성화하려면
  1. 다음 명령을 실행하여 새 부트스트랩 스택 또는 기존 부트스트랩 스택에서 종료 보호를 활성화합니다.

    $ cdk bootstrap --termination-protection
  2. AWS CLI 또는 CloudFormation 콘솔을 사용하여 확인하십시오. 다음은 AWS CLI사용을 보여 주는 예제입니다. 부트스트랩 스택 이름을 수정한 경우 스택 CDKToolkit 이름으로 바꾸십시오.

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

프로젝트 초기화

비어 있는 새 GitHub 프로젝트를 만들고 디렉터리의 워크스테이션에 복제합니다my-pipeline. (이 항목의 코드 예제에서는 다음을 사용합니다 GitHub. AWS CodeStar 또는 를 사용할 수도 AWS CodeCommit있습니다.

git clone GITHUB-CLONE-URL my-pipeline cd my-pipeline
참고

앱의 기본 디렉터리가 아닌 my-pipeline 다른 이름을 사용할 수 있습니다. 하지만 이렇게 하면 이 주제 뒷부분에서 파일 및 클래스 이름을 수정해야 합니다. 이는 AWS CDK 툴킷이 일부 파일 및 클래스 이름을 기본 디렉토리 이름을 기반으로 하기 때문입니다.

복제한 후 평소와 같이 프로젝트를 초기화하십시오.

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

앱을 만든 후 다음 두 명령도 입력합니다. 이는 앱의 Python 가상 환경을 활성화하고 AWS CDK 핵심 종속성을 설치합니다.

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

IDE를 사용하는 경우 이제 프로젝트를 열거나 가져올 수 있습니다. 예를 들어 Eclipse에서는 [파일] > [가져오기] > [Maven] > [기존 Maven 프로젝트] 를 선택합니다. 프로젝트 설정이 Java 8 (1.8) 을 사용하도록 설정되어 있는지 확인하십시오.

C#
$ cdk init app --language csharp

Visual Studio를 사용하는 경우 src 디렉터리에서 솔루션 파일을 여십시오.

Go
$ cdk init app --language go

앱을 만든 후에는 다음 명령도 입력하여 앱에 필요한 AWS Construct Library 모듈을 설치합니다.

$ go get
중요

cdk.jsoncdk.context.json 파일을 소스 컨트롤에 커밋해야 합니다. 컨텍스트 정보 (예: AWS 계정에서 검색된 기능 플래그 및 캐시된 값) 는 프로젝트 상태의 일부입니다. 다른 환경에서는 값이 다를 수 있으며, 이로 인해 결과에 예상치 못한 변화가 발생할 수 있습니다. 자세한 정보는 컨텍스트 값 및 AWS CDK을 참조하세요.

파이프라인을 정의하세요.

CDK Pipelines 애플리케이션에는 적어도 두 개의 스택이 포함됩니다. 하나는 파이프라인 자체를 나타내는 스택이고 다른 하나는 파이프라인을 통해 배포된 애플리케이션을 나타내는 스택입니다. 또한 스택을 여러 단계로 그룹화하여 인프라 스택의 복사본을 여러 환경에 배포할 수 있습니다. 지금은 파이프라인을 살펴보고 나중에 배포할 애플리케이션을 자세히 살펴보겠습니다.

CodePipeline구문은 배포 AWS CodePipeline 엔진으로 사용하는 CDK 파이프라인을 나타내는 구조입니다. CodePipeline스택에서 인스턴스화할 때는 파이프라인의 소스 위치 (예: 리포지토리) 를 GitHub 정의합니다. 앱을 빌드하기 위한 명령도 정의합니다.

예를 들어, 다음은 소스가 GitHub 리포지토리에 저장되는 파이프라인을 정의합니다. 또한 TypeScript CDK 애플리케이션을 위한 빌드 단계도 포함됩니다. 표시된 곳에 GitHub 리포지토리에 대한 정보를 입력하세요.

참고

기본적으로 파이프라인은 Secrets Manager에 다음과 같은 이름으로 github-token 저장된 개인용 액세스 토큰을 GitHub 사용하여 인증합니다.

또한 AWS 계정과 지역을 지정하도록 파이프라인 스택의 인스턴스화를 업데이트해야 합니다.

TypeScript

에서 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();
JavaScript

에서 lib/my-pipeline-stack.js (프로젝트 폴더 이름이 지정되지 않은 경우 다를 수 my-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 }

에서 bin/my-pipeline.js (프로젝트 폴더 이름이 지정되지 않은 경우 다를 수 my-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

에서 my-pipeline/my-pipeline-stack.py (프로젝트 폴더 이름이 지정되지 않은 경우 다를 수 my-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"] ) )

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

에서 src/main/java/com/myorg/MyPipelineStack.java (프로젝트 폴더 이름이 지정되지 않은 경우 다를 수 my-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(); } }

에서 src/main/java/com/myorg/MyPipelineApp.java (프로젝트 폴더 이름이 지정되지 않은 경우 다를 수 my-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#

에서 src/MyPipeline/MyPipelineStack.cs (프로젝트 폴더 이름이 지정되지 않은 경우 다를 수 my-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" } }) }); } } }

에서 src/MyPipeline/Program.cs (프로젝트 폴더 이름이 지정되지 않은 경우 다를 수 my-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")), } }

파이프라인을 수동으로 한 번 배포해야 합니다. 그 후에는 파이프라인이 소스 코드 리포지토리에서 최신 상태로 유지됩니다. 따라서 리포지토리의 코드가 배포하려는 코드인지 확인하세요. 변경 사항을 확인하고 GitHub 다음으로 푸시한 다음 배포하십시오.

git add --all git commit -m "initial commit" git push cdk deploy
작은 정보

이제 초기 배포가 완료되었으므로 로컬 AWS 계정에는 더 이상 관리 액세스 권한이 필요하지 않습니다. 앱의 모든 변경 사항이 파이프라인을 통해 배포되기 때문입니다. 푸시만 하면 GitHub 됩니다.

적용 단계

파이프라인에 한 번에 추가할 수 있는 멀티스택 AWS 애플리케이션을 정의하려면 의 서브클래스를 정의하십시오. Stage (이는 CDK Pipelines 모듈과 다릅니다CdkStage.)

스테이지에는 애플리케이션을 구성하는 스택이 포함됩니다. 스택 간에 종속성이 있는 경우 스택이 올바른 순서로 파이프라인에 자동으로 추가됩니다. 서로 종속되지 않는 스택은 병렬로 배포됩니다. 를 호출하여 스택 간의 종속성 관계를 추가할 수 있습니다. stack1.addDependency(stack2)

스테이지는 기본 env 인수를 받아들이며, 이 인수는 내부 스택의 기본 환경이 됩니다. (스택에는 여전히 자체 환경을 지정할 수 있습니다.)

Stage인스턴스를 addStage() 호출하여 파이프라인에 애플리케이션을 추가합니다. 단계를 인스턴스화하고 파이프라인에 여러 번 추가하여 DTAP 또는 다중 지역 애플리케이션 파이프라인의 여러 단계를 정의할 수 있습니다.

간단한 Lambda 함수를 포함하는 스택을 생성하고 해당 스택을 스테이지에 배치합니다. 그런 다음 파이프라인에 스테이지를 추가하여 배포할 수 있도록 하겠습니다.

TypeScript

Lambda 함수를 포함하는 애플리케이션 lib/my-pipeline-lambda-stack.ts 스택을 보관할 새 파일을 생성합니다.

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

Lambda 함수를 포함하는 애플리케이션 lib/my-pipeline-lambda-stack.js 스택을 보관할 새 파일을 생성합니다.

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 }

스테이지를 보관할 새 lib/my-pipeline-app-stage.js 파일을 생성하십시오.

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

lib/my-pipeline-stack.ts편집하여 파이프라인에 스테이지를 추가하세요.

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

Lambda 함수를 포함하는 애플리케이션 my_pipeline/my_pipeline_lambda_stack.py 스택을 보관할 새 파일을 생성합니다.

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

스테이지를 보관할 새 my_pipeline/my_pipeline_app_stage.py 파일을 생성하십시오.

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")

my_pipeline/my-pipeline-stack.py편집하여 파이프라인에 스테이지를 추가하세요.

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

Lambda 함수를 포함하는 애플리케이션 src/main/java/com.myorg/MyPipelineLambdaStack.java 스택을 보관할 새 파일을 생성합니다.

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

스테이지를 보관할 새 src/main/java/com.myorg/MyPipelineAppStage.java 파일을 생성하십시오.

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

src/main/java/com.myorg/MyPipelineStack.java편집하여 파이프라인에 스테이지를 추가하세요.

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#

Lambda 함수를 포함하는 애플리케이션 src/MyPipeline/MyPipelineLambdaStack.cs 스택을 보관할 새 파일을 생성합니다.

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

스테이지를 보관할 새 src/MyPipeline/MyPipelineAppStage.cs 파일을 생성하십시오.

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

src/MyPipeline/MyPipelineStack.cs편집하여 파이프라인에 스테이지를 추가하세요.

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

에서 추가하는 모든 애플리케이션 단계는 해당 파이프라인 단계를 추가합니다. 이 단계는 addStage() 호출에서 반환된 StageDeployment인스턴스로 표시됩니다. addStage() 또는 메서드를 호출하여 배포 전 또는 배포 후 작업을 스테이지에 추가할 수 있습니다. addPre() 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"));

예를 들어 스테이지를 여러 계정 또는 지역에 배포할 때 Wave에 스테이지를 추가하여 병렬로 배포할 수 있습니다.

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

배포 테스트

CDK 파이프라인에 단계를 추가하여 수행 중인 배포를 검증할 수 있습니다. 예를 들어 CDK 파이프라인 라이브러리를 사용하여 다음과 같은 작업을 수행할 수 있습니다. ShellStep

  • Lambda 함수가 지원하는 새로 배포된 Amazon API Gateway에 액세스하려고 합니다.

  • 명령을 실행하여 배포된 리소스의 설정을 확인합니다. AWS CLI

가장 간단한 형태로 유효성 검사 작업을 추가하는 방법은 다음과 같습니다.

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

AWS CloudFormation 배포를 많이 하면 예측할 수 없는 이름을 가진 리소스가 생성됩니다. 따라서 CDK Pipeline은 배포 후 출력을 AWS CloudFormation 읽을 수 있는 방법을 제공합니다. 이를 통해 (예를 들어) 로드 밸런서의 생성된 URL을 테스트 작업에 전달할 수 있습니다.

출력을 사용하려면 관심 있는 CfnOutput 객체를 노출하세요. 그런 다음 단계 envFromCfnOutputs 속성에 전달하여 해당 단계 내에서 환경 변수로 사용할 수 있도록 하세요.

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

에서 바로 간단한 검증 테스트를 작성할 수 있지만 테스트가 몇 줄 이상이면 이 방법을 다루기가 어려워집니다. ShellStep 더 복잡한 테스트의 경우 전체 셸 스크립트 또는 다른 언어로 작성된 프로그램과 같은 추가 파일을 ShellStep via 속성으로 가져올 수 있습니다. inputs 입력은 소스 (예: GitHub 리포지토리) 등을 포함하여 출력이 있는 모든 단계가 될 수 있습니다. ShellStep

파일을 테스트에서 직접 사용할 수 있는 경우 (예: 파일 자체가 실행 가능한 경우) 소스 리포지토리에서 파일을 가져오는 것이 좋습니다. 이 예시에서는 GitHub 저장소를 source (의 일부로 인라인으로 인스턴스화하는 대신) 로 선언합니다. CodePipeline 그런 다음 이 파일 세트를 파이프라인과 검증 테스트 모두에 전달합니다.

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

합성의 일부로 수행되는 테스트를 컴파일해야 하는 경우에는 신디사이저 단계에서 추가 파일을 가져오는 것이 좋습니다.

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

보안 참고 사항

모든 형태의 지속적 전송에는 보안 위험이 내재되어 있습니다. AWS 공동 책임 모델에 따라 클라우드 내 정보의 보안에 대한 책임은 귀하에게 있습니다. AWS CDK Pipelines 라이브러리는 보안 기본값과 모델링 모범 사례를 통합하여 한 발 앞서 나갈 수 있게 해줍니다.

그러나 라이브러리의 특성상 의도한 목적을 달성하기 위해 높은 수준의 액세스가 필요한 라이브러리는 완벽한 보안을 보장할 수 없습니다. 조직 외부에는 많은 공격 벡터가 AWS 있습니다.

특히 다음 사항에 유의하세요.

  • 사용하고 있는 소프트웨어를 염두에 두세요. 파이프라인에서 실행하는 모든 타사 소프트웨어를 검토하세요. 배포되는 인프라가 변경될 수 있기 때문입니다.

  • 종속성 잠금을 사용하여 실수로 인한 업그레이드를 방지하세요. CDK Pipelines는 사용자의 종속성을 package-lock.json yarn.lock 존중하고 사용자가 기대하는 것과 일치하는지 확인합니다.

  • CDK Pipelines는 자체 계정에서 생성된 리소스에서 실행되며, 이러한 리소스의 구성은 파이프라인을 통해 코드를 제출하는 개발자가 제어합니다. 따라서 CDK Pipelines 자체로는 규정 준수 검사를 우회하려는 악의적인 개발자로부터 보호할 수 없습니다. 위협 모델에 개발자가 CDK 코드를 작성하는 것을 포함하는 경우 실행 역할에 비활성화할 권한이 없는 AWS CloudFormation Hooks (예방) 또는 AWS Config (반응형) 와 같은 외부 규정 준수 메커니즘을 마련해야 합니다. AWS CloudFormation

  • 프로덕션 환경의 자격 증명은 수명이 짧아야 합니다. 부트스트래핑과 초기 프로비저닝 후에는 개발자가 계정 자격 증명을 보유할 필요가 전혀 없습니다. 파이프라인을 통해 변경 내용을 배포할 수 있습니다. 처음부터 자격 증명이 필요하지 않으므로 자격 증명이 유출될 가능성을 줄이세요.

문제 해결

CDK Pipelines를 시작할 때 일반적으로 발생하는 문제는 다음과 같습니다.

파이프라인: 내부 장애
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 콘솔에서 스택을 삭제하고 배포를 다시 시도합니다.