You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CDKv2 Pipeline生成无效嵌套模板引用致部署失败

CDK v2 Pipeline部署失败:资产清单错误引用阶段栈模板

问题描述

按照《CDK Book》的CDK Pipelines章节指导,基于cdk init app --language typescript创建的项目构建CDK v2 Pipeline,填充正确账号信息后部署始终失败。

问题根源在于synth步骤生成的资产清单(Pipeline.assets.json)中,额外引用了属于各阶段栈的模板文件,但这些模板实际存在于嵌套云组装目录中,根目录下并无对应文件,导致引用无效。

已将代码简化为仅保留自定义限定符和栈名称的最小可运行示例,升级CDK版本从2.93.0到2.94.0后,问题仍然存在。期望根Pipeline栈的资产文件不包含这些针对阶段栈模板的错误引用。

代码示例

cdk.json

{
  "app": "npx ts-node --prefer-ts-exts bin/create-pipeline.ts",
  "toolkitStackName": "csd-demo-ssm",
  "requireApproval": "never",
  "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
  "context": {
    "@aws-cdk/core:bootstrapQualifier": "demo-ssm",
    "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
    "@aws-cdk/core:checkSecretUsage": true,
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ],
    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
    "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
    "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
    "@aws-cdk/aws-iam:minimizePolicies": true,
    "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
    "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
    "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
    "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
    "@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
    "@aws-cdk/core:enablePartitionLiterals": true,
    "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
    "@aws-cdk/aws-iam:standardizedServicePrincipals": true,
    "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
    "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
    "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
    "@aws-cdk/aws-route53-patters:useCertificate": true,
    "@aws-cdk/customresources:installLatestAwsSdkDefault": false,
    "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
    "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
    "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
    "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
    "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
    "@aws-cdk/aws-redshift:columnId": true,
    "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
    "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
    "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
    "@aws-cdk/aws-kms:aliasNameRef": true,
    "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
    "@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
    "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
    "@aws-cdk/core:newStyleStackSynthesis": true
  }
}

bin/create-pipeline.ts

import * as cdk from 'aws-cdk-lib'
import * as ec2 from 'aws-cdk-lib/aws-ec2'
import * as iam from 'aws-cdk-lib/aws-iam'
import { CdkPipelineStack } from '../lib/CdkPipelineStack'

const env1: cdk.Environment = { account: '111111111111', region: 'us-east-1' }
const env2: cdk.Environment = { account: '999999999999', region: 'us-east-1' }

const app = new cdk.App({
    defaultStackSynthesizer: new cdk.DefaultStackSynthesizer({
        qualifier: 'demo-ssm',
    bootstrapStackVersionSsmParameter: '/cdk-bootstrap/demo-ssm/version'
    })
})
iam.Role.customizeRoles(app, { preventSynthesis: false })

const pipeline = new CdkPipelineStack(app, 'Pipeline', { ciEnv: env1, devEnv: env1, prodEnv: env2 });

app.synth();

lib/CdkPipelineStack.ts

import { Stack, Environment } from 'aws-cdk-lib'
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { Construct } from 'constructs';

import { ProjectStage } from './ProjectStage'

export class CdkPipelineStack extends Stack {

    constructor(scope: Construct, id: string, props: CdkPipelineStackProps ) {
        super(scope, id, { env: props.ciEnv });

        const codeSource = CodePipelineSource.connection('john-heinnickel/automation-runbook-demo', 'main', {
            connectionArn: 'arn:aws:codestar-connections:us-east-1:123456789012:connection/f1f1f1f1-eeee-5555-aaaa-cdccc0000099',
            codeBuildCloneOutput: true,
            triggerOnPush: true
        });
        const pipeline = new CodePipeline(this, 'Pipeline', {
            // we need to activate this for cross account deployments
            pipelineName: 'Pipeline',
            crossAccountKeys: true,
            synth: new ShellStep('Synth', {
                // configure source repo here
                input: codeSource,
                // configure installation of dependencies here
                installCommands: ['npm install --frozen-lockfile'],
                // configure build steps here
                commands: ['npm ci', 'npm run build', 'npx cdk synth'],
            })
        });
    
        const wl1 = pipeline.addStage(
            new ProjectStage(this, 'DevWorkload', { env: props.devEnv }));
        const wl2 = pipeline.addStage(
            new ProjectStage(this, 'ProdWorkload', { env: props.prodEnv }));
    }
}

export interface CdkPipelineStackProps {
    ciEnv: Environment,
    devEnv: Environment,
    prodEnv: Environment
}

lib/ProjectStage.ts

import { Stage, StageProps } from 'aws-cdk-lib'
import { Construct } from 'constructs'

import { SharedInfraStack } from './SharedInfraStack'
import { StatefulStack } from './StatefulStack'

export class ProjectStage extends Stage {
    constructor(scope: Construct, id: string, props: StageProps) {
        super(scope, id, props)
        const sharedStack = new SharedInfraStack(this, 'SharedInfraStack');
        const statefulStack = new StatefulStack(this, 'StatefulStack', { vpc: sharedStack.vpc } );
    }
}

package.json

{
  "name": "stack-overflow-gist",
  "version": "0.1.0",
  "bin": {
    "create-pipeline": "bin/create-pipeline.js"
  },
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk"
  },
  "devDependencies": {
    "@types/jest": "^29.5.4",
    "@types/node": "20.5.3",
    "aws-cdk": "2.94.0",
    "jest": "^29.6.3",
    "ts-jest": "^29.1.1",
    "ts-node": "^10.9.1",
    "typescript": "~5.1.6"
  },
  "dependencies": {
    "aws-cdk-lib": "2.94.0",
    "constructs": "^10.0.0",
    "source-map-support": "^0.5.21"
  }
}

lib/StatefulStack.ts

import * as iam from 'aws-cdk-lib/aws-iam'
import * as ec2 from 'aws-cdk-lib/aws-ec2' 
import * as kms from 'aws-cdk-lib/aws-kms' 
import { Size } from 'aws-cdk-lib/core'
import { Stack } from 'aws-cdk-lib'
import { Construct } from 'constructs'

import { StatefulStackProps } from './StatefulStackProps'

export class StatefulStack extends Stack {

    constructor(scope: Construct, id: string, props: StatefulStackProps) {
        super(scope, id, props)

        const myVpc = props.vpc

        const nodeRole = new iam.Role(this, 'NodeRole', {
            assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com')
        })
        const nodeInstProf = new iam.InstanceProfile(this, 'NodeInstanceProfile', {
            role: nodeRole
        })
        const secGrp = new ec2.SecurityGroup(this, 'SgNode', {
            vpc: myVpc
        })

        const ebsKey = kms.Key.fromLookup(this, 'EbsKey', { aliasName: 'alias/aws/ebs' })
        const dataVolume: ec2.IVolume = new ec2.Volume(this, 'DataVolume', {
            size: Size.gibibytes(50),
            availabilityZone: 'us-east-1c',
            encryptionKey: ebsKey,
            encrypted: true
        })

        // Create the EC2 instance
        const ec2Instance = new ec2.Instance(this, 'EC2Instance', {
            vpc: myVpc,
            instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3A, ec2.InstanceSize.MEDIUM),
            machineImage: new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 }),
            role: nodeRole,
            securityGroup: secGrp,
            requireImdsv2: true,
            detailedMonitoring: true,
            ssmSessionPermissions: true,
            associatePublicIpAddress: false,
            propagateTagsToVolumeOnCreation: true,
        })

        // Attach the data volumes
        dataVolume.grantAttachVolumeByResourceTag(ec2Instance, [ec2Instance]);
        dataVolume.grantDetachVolumeByResourceTag(ec2Instance, [ec2Instance]);
    }
}

lib/StatefulStackProps.ts

import { StackProps } from 'aws-cdk-lib'
import { IVpc } from 'aws-cdk-lib/aws-ec2'

export interface StatefulStackProps extends StackProps{
    vpc: IVpc
}

lib/SharedInfraStack.ts

// file: lib/shared-infra-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib';
import { Vpc, SubnetType } from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';

export class SharedInfraStack extends Stack {
  public readonly vpc: Vpc;
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // assign a VPC to the class property SharedInfraStack
    this.vpc = new Vpc(this, 'TheVPC', {
      cidr: '10.0.0.0/16',
      natGateways: 1,
      maxAzs: 3,
      subnetConfiguration: [
        {
          cidrMask: 20,
          name: 'public',
          subnetType: SubnetType.PUBLIC,
        },
        {
          cidrMask: 20,
          name: 'application',
          subnetType: SubnetType.PRIVATE_WITH_EGRESS,
        },
        {
          cidrMask: 20,
          name: 'data',
          subnetType: SubnetType.PRIVATE_ISOLATED,
        },
      ],
    });
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": [
      "es2020",
      "dom"
    ],
    "declaration": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": false,
    "inlineSourceMap": true,
    "inlineSources": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "typeRoots": [
      "./node_modules/@types"
    ]
  },
  "exclude": [
    "node_modules",
    "cdk.out"
  ]
}

内容的提问来源于stack exchange,提问作者John Heinnickel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 13:42:31