在CDK(TypeScript)应用中创建AWS S3 Glacier堆栈失败求助
问题分析与解决方案
问题描述
使用AWS CDK(TypeScript)创建S3 Glacier归档存储桶时,运行cdk list命令报错:Error: Cannot use 'noncurrent' rules on a nonversioned bucket,相关代码如下:
cdk-app-1.ts
import 'source-map-support/register'; import * as cdk from 'aws-cdk-lib'; import { S3GlacierStack } from '../lib/s3-glacier-stack'; const app = new cdk.App(); new S3GlacierStack(app, 'S3GlacierStack', {});
s3-glacier-stack.ts
import * as cdk from 'aws-cdk-lib'; import * as s3 from "aws-cdk-lib/aws-s3"; import { Construct } from 'constructs'; export class S3GlacierStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const bucket = new s3.Bucket(this, 's3-glacier', { lifecycleRules: [{ abortIncompleteMultipartUploadAfter: cdk.Duration.minutes(30), enabled: false, expiration: cdk.Duration.days(30), expirationDate: new Date(), expiredObjectDeleteMarker: false, id: 's3-glacier', noncurrentVersionExpiration: cdk.Duration.days(30), noncurrentVersionsToRetain: 123, noncurrentVersionTransitions: [{ storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(30), noncurrentVersionsToRetain: 123, }], objectSizeGreaterThan: 500, prefix: 'prefix', objectSizeLessThan: 10000, transitions: [{ storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(30), transitionDate: new Date(), }], }] }); } }
package.json
{ "name": "cdk-app-1", "version": "0.1.0", "bin": { "cdk-app-1": "bin/cdk-app-1.js" }, "scripts": { "build": "tsc", "watch": "tsc -w", "test": "jest", "cdk": "cdk" }, "devDependencies": { "@types/jest": "^27.5.2", "@types/node": "10.17.27", "@types/prettier": "2.6.0", "jest": "^27.5.1", "ts-jest": "^27.1.4", "aws-cdk": "2.50.0", "ts-node": "^10.9.1", "typescript": "~3.9.7" }, "dependencies": { "aws-cdk-lib": "2.50.0", "constructs": "^10.0.0", "source-map-support": "^0.5.21" } }
错误原因
你在生命周期规则中配置了noncurrentVersionExpiration、noncurrentVersionTransitions这类针对非当前对象版本的规则,但AWS S3桶默认是未开启版本控制的。这类规则仅适用于已启用版本控制的桶,因此CDK在验证配置时抛出错误。
推荐方案
根据归档需求,有两种合理的实现方式:
方案1:不需要版本控制(移除非当前版本规则)
如果不需要保留对象历史版本,直接删除所有noncurrent开头的配置项,仅保留当前版本转Glacier的规则即可:
修改后的s3-glacier-stack.ts代码:
import * as cdk from 'aws-cdk-lib'; import * as s3 from "aws-cdk-lib/aws-s3"; import { Construct } from 'constructs'; export class S3GlacierStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const bucket = new s3.Bucket(this, 's3-glacier', { lifecycleRules: [{ abortIncompleteMultipartUploadAfter: cdk.Duration.minutes(30), enabled: true, // 启用规则需设为true expiration: cdk.Duration.days(30), id: 's3-glacier-archive-rule', prefix: 'prefix', transitions: [{ storageClass: s3.StorageClass.GLACIER, // 对应Glacier Flexible Retrieval存储类 transitionAfter: cdk.Duration.days(30), }], }] }); } }
方案2:开启版本控制(适合归档场景)
归档场景通常建议开启版本控制,以便误删或修改后恢复历史版本。此时需在桶配置中开启版本控制,同时合理配置非当前版本的生命周期规则:
修改后的s3-glacier-stack.ts代码:
import * as cdk from 'aws-cdk-lib'; import * as s3 from "aws-cdk-lib/aws-s3"; import { Construct } from 'constructs'; export class S3GlacierStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const bucket = new s3.Bucket(this, 's3-glacier', { versioned: true, // 开启版本控制 lifecycleRules: [{ abortIncompleteMultipartUploadAfter: cdk.Duration.minutes(30), enabled: true, // 当前版本30天后转Glacier transitions: [{ storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(30), }], // 非当前版本30天后转Glacier,保留123个版本后删除 noncurrentVersionTransitions: [{ storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(30), }], noncurrentVersionExpiration: cdk.Duration.days(30), noncurrentVersionsToRetain: 123, prefix: 'prefix', }] }); } }
额外注意事项
- 原代码中
enabled: false会禁用整个生命周期规则,若要启用需设为true expiration和expirationDate不要同时配置,CDK会触发验证错误,建议仅保留其中一种GLACIER对应Glacier Flexible Retrieval存储类,若需更经济的归档选项,可使用GLACIER_IR(即时检索)或DEEP_ARCHIVE(深度归档)
内容的提问来源于stack exchange,提问作者Joseph Katzman
相关产品推荐
相关产品推荐

