使用AWS-CDK TypeScript更新单栈时RDS栈异常更新问题咨询
AWS CDK多栈部署中RDS栈无变更却触发更新的问题排查与解决
问题梳理
你把VPC、RDS和应用拆成独立CDK栈的思路很合理——毕竟VPC和RDS的创建销毁耗时确实久,拆分后能节省不少部署时间。但现在遇到了头疼的问题:解决DB实例命名问题后,部署Application栈时VPC栈能正常跳过,可RDS栈每次都要尝试更新,实际上这个栈根本没有任何代码变更。
你提到CloudFormation可以用栈策略阻止不必要更新,但CDK的相关功能还在开发中,现有的setPolicy示例又会创建新资源,完全不符合需求。先看看你的代码和diff输出,我们来一步步解决这个问题。
你的CDK代码
const app = new cdk.App(); const vpc = new VpcStack(app, "vpc", { env, appEnvironment: "staging" }); const rds = new RdsStack(app, "rds", { env, vpc: vpc.vpc, appEnvironment: "staging", masterPassword: dbPassword, }); rds.addDependency(vpc); const appStack = new AppStack(app, "app", { env, // configure the environments you want to setup. The default is production & staging, but for testing we'll just do staging. appEnvironments: ["staging"], environmentProps: { // per environment options go here staging: { vpc: vpc.vpc, db: { instance: rds.dbInstance, securityGroup: rds.securityGroup, username: rds.username, password: dbPassword, }, ebOptions: { ec2KeyName: "App", }, }, }, }); appStack.addDependency(rds); const pipeStack = new PipelineStack(app, "pipeline", { appEnvironment: "staging" }); pipeStack.addDependency(appStack); app.synth();
CDK Diff输出
cdk diff Stack vpcStaging There were no differences Stack rdsStaging Resources [~] AWS::RDS::DBInstance instance instanceB**** replace ├─ [~] DBName (requires replacement) │ ├─ [-] rds_staging │ └─ [+] DBRds ├─ [~] DeletionPolicy │ ├─ [-] Delete │ └─ [+] Retain └─ [~] UpdateReplacePolicy ├─ [-] Delete └─ [+] Retain Stack application Template [-] Description Description: Elasticbeanstalk setup for application Security Group Changes ┌───┬─────────────────────────────────────────────┬─────┬─────────────────────────────────────────────┬─────────────────────────────────────────────┐ │ │ Group │ Dir │ Protocol │ Peer │ ├───┼─────────────────────────────────────────────┼─────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ - │ {"Fn::ImportValue":"rdsStaging:ExportsOutput │ In │ TCP {"Fn::ImportValue":"rdsStaging:ExportsOu │ ${prodsecurityGroupD*****.GroupId} │ │ │ FnGetAttsecurityGroup88888GroupId***** │ │ tputFnGetAttinstance*****EndpointPort***** │ │ │ │ 1"} │ │ *****"} │ │ ├───┼─────────────────────────────────────────────┼─────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ + │ ${staging/securityGroup.GroupId} │ Out │ Everything │ Everyone (IPv4) │ ├───┼─────────────────────────────────────────────┼─────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ + │ {"Fn::ImportValue":"rdsStaging:ExportsOutput │ In │ TCP {"Fn::ImportValue":"rdsStaging:ExportsOu │ ${staging/securityGroup.GroupId} │ │ │ FnGetAttsecurityGroup*****GroupId***** │ │ tputFnGetAttinstance*****EndpointPort***** │ │ │ │ 1"} │ │ *****"} │ │ └───┴─────────────────────────────────────────────┴─────┴─────────────────────────────────────────────┴─────────────────────────────────────────────┘ (NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) Resources [-] AWS::EC2::SecurityGroup stagingsecurityGroup****** destroy [-] AWS::EC2::SecurityGroupIngress stagingsecurityGrouprdsStagingsecurityGroup*****IndirectPortto***** destroy [-] AWS::ElasticBeanstalk::Environment staging***** destroy [+] AWS::EC2::SecurityGroup staging/securityGroup stagingsecurityGroup***** [+] AWS::EC2::SecurityGroupIngress staging/securityGroup/rdsStagingsecurityGroup*****:{IndirectPort} to stagingsecurityGrouprdsStagingsecurityGroup*****IndirectPortto***** [+] AWS::ElasticBeanstalk::Environment staging/staging staging*****
问题根源与解决步骤
1. 先解决RDS实例的配置变更问题
从diff里能明显看到,你的RDS实例有三个关键变化:
DBName从rds_staging变成了DBRds(这个变更还会触发实例替换)DeletionPolicy和UpdateReplacePolicy从Delete改成了Retain
这就是RDS栈每次触发更新的核心原因!你需要去检查RdsStack里创建DB实例的代码:
- 是不是不小心把
DBName的配置改了?比如从固定的rds_staging换成了动态生成的值或者硬编码成了DBRds? - 是不是误加了
removalPolicy: cdk.RemovalPolicy.RETAIN?如果这不是你刻意设置的,改回原来的配置就行。
把这两个点修复后,RDS栈应该就不会再无意义地触发更新了。
2. 用栈策略兜底(可选)
如果之后还是需要防止RDS栈被意外更新,虽然CDK原生的栈策略功能还在开发,但可以手动给RDS栈添加CloudFormation栈策略。在RdsStack的构造函数里加入以下代码:
this.templateOptions.stackPolicy = [ // 允许所有资源的更新操作 { Effect: "Allow", Action: "Update:*", Principal: "*", Resource: "*", }, // 阻止对RDS实例的更新 { Effect: "Deny", Action: "Update:*", Principal: "*", Resource: "LogicalResourceId/instance", // 替换成你的RDS实例的实际逻辑ID Condition: { StringEquals: { "ResourceType": "AWS::RDS::DBInstance" } } } ];
注意:这里的LogicalResourceId/instance要替换成你RDS实例在CloudFormation模板里的真实逻辑ID,可以通过运行cdk synth rdsStaging查看生成的模板找到这个ID。
这样配置后,CloudFormation就会阻止对RDS实例的任何更新操作,除非你手动修改栈策略。
内容的提问来源于stack exchange,提问作者scope
相关产品推荐
相关产品推荐

