【发布时间】:2021-12-29 21:05:13
【问题描述】:
在使用 AWS-CDK 时,我如何将堆栈向下传递到管道阶段?
我目前正在尝试创建一个可以将堆栈作为输入的管道。
我已经关注了 aws-cdk 研讨会,并且有一个可以自我更新的管道,并且可以部署一个预打包的 lambda,但我正在尝试创建一个管道构造库,以便我的团队可以创建一个新的实例管道并传入稍后创建的堆栈,该堆栈已添加相关角色和事件规则。
我当前的代码如下:
pipelines-stack.ts
import {
Stack,
StackProps,
pipelines,
DefaultStackSynthesizer,
SecretValue,
aws_codebuild as codebuild,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { PipelineStage } from './pipeline-stage';
export type PipelineStackProps = StackProps;
export interface Environment {
readonly name: string;
readonly accountNumber: string;
}
export class PipelineStack extends Stack {
constructor(scope: Construct, id: string, props: PipelineStackProps,
environments: Environment[], repoName: string, serviceName: string, lambdaPath: string, policies: Array<string>) {
super(scope, id, props);
new DefaultStackSynthesizer({
deployRoleArn: 'arn:aws:iam::{ACCOUNTID}:role/service-role/ops-codepipeline-role',
});
const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
pipelineName: serviceName,
synth: new pipelines.CodeBuildStep('Synth', {
input: pipelines.CodePipelineSource.gitHub(`company_repo/${repoName}`, 'main', {
authentication: SecretValue.secretsManager('github-oauth-token', { jsonField: 'OAUTH_TOKEN' }),
}),
buildEnvironment: {
environmentVariables: {
NPM_TOKEN: {
value: '/codepipeline/npm_token',
type: codebuild.BuildEnvironmentVariableType.PARAMETER_STORE,
},
},
},
commands: [
'echo "@company:registry=https://npm.pkg.github.com/" > .npmrc',
'echo "//npm.pkg.github.com/:_authToken=\\${NPM_TOKEN}" >> .npmrc',
'npm ci',
'npm run build',
'npm test',
'npx cdk synth',
'pip install -r lambda/requirements.txt -t lambda',
],
}),
crossAccountKeys: true,
});
for (const environment of environments) {
const environmentName = environment.name;
const envAccountNumber = environment.accountNumber;
pipeline.addStage(
new PipelineStage(this, environmentName, {
env: {
account: envAccountNumber,
region: 'eu-west-2',
},
}, lambdaPath, policies),
);
}
}
}
pipeline-stage.ts
import { Stage, StageProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { LambdaStack } from './lambda-stack';
export class PipelineStage extends Stage {
constructor(scope: Construct, id: string, props: StageProps, lambdaPath: string, policies: Array<string>) {
super(scope, id, props);
new LambdaStack(this, 'LambdaStack', lambdaPath, policies);
}
}
lambda-stack.ts
import {
Stack,
StackProps,
aws_lambda as lambda,
aws_events as events,
aws_events_targets as targets,
aws_iam as iam,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class LambdaStack extends Stack {
constructor(scope: Construct, id: string, lambdaPath: string, policies: Array<string>, props?: StackProps) {
super(scope, id, props);
const role = new iam.Role(this, 'LambdaCleanupRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
for (const policy of policies) {
role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName(policy));
}
// The code that defines your stack goes here
const fn = new lambda.Function(this, 'lambda-cleanup', {
runtime: lambda.Runtime.PYTHON_3_8,
handler: 'app.handler',
code: lambda.Code.fromAsset(lambdaPath),
role,
});
const rule = new events.Rule(this, 'Schedule Rule', {
schedule: events.Schedule.expression('rate(1 day)'),
});
rule.addTarget(new targets.LambdaFunction(fn));
}
}
建议的解决方案如下:
pipelines-stack.ts
export class PipelineStack extends Stack {
constructor(scope: Construct, id: string, props: PipelineStackProps,
environments: Environment[], repoName: string, serviceName: string, lambdaPath: string, policies: Array<string>, lambdaStack: Stack) {
super(scope, id, props);
// pipeline implementation here
const stage = pipeline.addStage(
new PipelineStage(this, environmentName, {
env: {
account: envAccountNumber,
region: 'eu-west-2',
},
}, lambdaPath, policies, lambdaStack),
);
pipeline-stage.ts
export class PipelineStage extends Stage {
constructor(scope: Construct, id: string, props: StageProps, lambdaPath: string, policies: Array<string>, lambdaStack: Stack) {
super(scope, id, props);
lambdaStack
}
}
但是这样做会导致The given Stage construct ('Default/BymilesLambdaPipelineStack/dev') should contain at least one Stack 错误
团队的最终目标是从我们的注册表中导入一个 npm 包并执行类似于以下的操作:
lambda-deployment-stack.ts
import { LambdaStack } from './lambda-stack.ts'
import { PipelineStack } from '@company-register/cdk-pipeline-python'
const app = new App();
const policies: string[] = [
'service-role/AWSLambdaBasicExecutionRole',
'AWSLambda_FullAccess',
];
new PipelineStack(app, 'LambdaCleanupPipeline', {
env: {
region: 'eu-west-2',
},
}, [
{ name: 'Test', accountNumber: '11111111' },
{ name: 'Ops', accountNumber: '22222222' }],
'bymiles-lambda-cleanup-cdk',
'bymiles-lambda-cleanup-cdk',
new LambdaStack(stack, 'BymilesLambdaStack', 'test/test_lambda', policies)
);
app.synth();
【问题讨论】:
-
是的,一切都已编译,实际上是测试套件抛出错误,但实现几乎相同
-
@fedonev 我已经更新了这个问题,详细介绍了导致该错误的当前实现
-
当前实现失败,因为栈不是在stage的范围内创建的。您需要在舞台中创建堆栈。我不确定您要达到什么目的 - 如果您解释得更好,我相信我们可以提出解决方案。
-
@gshpychka 添加了有关最终目标的更多详细信息
标签: typescript amazon-web-services aws-cdk aws-codepipeline