Reputation: 287540
I'm building an application with AWS CDK that uses CodePipeline. So there are essentially two stacks, one sets up the code pipeline and the other sets up the application (and it's triggered by the pipeline).
I'm working out of what is built in https://cdkworkshop.com/ so in my project I have a file cdk.json
that has an entry app
pointing to a specific TypeScript file (example4-be is the application name):
{
"app": "npx ts-node --prefer-ts-exts bin/example4-be.ts",
This file builds the CodePipeline stack:
#!/usr/bin/env node
import * as cdk from "aws-cdk-lib"
import {PipelineStack} from "../lib/pipeline-stack"
const app = new cdk.App()
new PipelineStack(app, "Example4BePipeline")
so when I try to use sam to run the application locally, it fails saying there are no Lambda functions. I believe it's because it's building the CodePipeline stack and not the application stack. If I change exampe4-be.ts
to this:
#!/usr/bin/env node
import * as cdk from "aws-cdk-lib"
import {Example4BeStack} from "../lib/example4-be-stack";
const app = new cdk.App()
new Example4BeStack(app, "Example4BePipeline")
it works. Example4BeStack
is the application stack. But obviously if I commit this, the CodePipeline will stop working.
How can I have both things working at the same time?
The commands I run to have sam run the application locally are:~
cdk synth --no-staging | out-file template.yaml -encoding utf8
sam local start-api
Upvotes: 0
Views: 569
Reputation: 25679
Create two cdk.App
chains in your codebase, one for the pipeline and one for standalone development/testing with sam local
or cdk deploy
. Your "application" stacks will be part of both chains. Here's a simplified example of the pattern I use:
Pipeline deploy (app-pipeline.ts
): ApiStack
and DatabaseStack
are children of a cdk.Stage
, grandchildren of the PipelineStack
, and great-granchildren of a cdk.App
.
Development deploys (app.ts
): ApiStack
and DatabaseStack
are children of a cdk.App
. Use with sam local
and cdk deploy
for dev and testing.
bin/
app.ts # calls makeAppStacks to add the stacks; runs frequently during development
app-pipeline.ts # adds the PipelineStack to an App
lib/
ApiStack.ts
DatabaseStack.ts
PipelineStack.ts # adds DeployStage to the pipeline
DeployStage.ts # subclasses cdk.Stage; calls makeAppStacks.ts to add the stacks
makeAppStacks.ts # adds the Api and Db stacks to either an App or a Stage
A makeAppStacks
wrapper function instantiates the actual stacks.
// makeAppStacks.ts
export const makeAppStacks = (scope: cdk.App | DeployStage, appName: string, account: string, region: string): void => {
const {table} = new DatabaseStack(scope, 'MyDb', ...)
new ApiStack(scope, 'MyApi', {table, ...})
};
makeAppStacks
gets called in two places. DeployStage.ts
and app.ts
are generic and rarely change:
// DeployStage.ts
export class DeployStage extends cdk.Stage {
constructor(scope: Construct, id: string, props: DeployStageProps) {
super(scope, id, props);
makeAppStacks(this, props.appName, props.env.account, props.env.region);
}
}
// app.ts
const app = new cdk.App();
const account = process.env.AWS_ACCOUNT;
makeAppStacks(app, 'MyApp', account, 'us-east-1');
Add some scripts for convenience:
"scripts": {
"---- app (sandbox env) ----": "",
"deploy-sandbox:cdk": "AWS_ACCOUNT=<Sandbox Acct> npx cdk deploy '*' --app 'ts-node ./bin/app.ts' --profile sandbox --outputs-file cdk.outputs.json",
"deploy-sandbox": "build && test && deploy-sandbox:cdk",
"destroy-sandbox": ...,
"synth-sandbox": ...,
"---- app-pipeline (pipeline env) ----": "",
"deploy-pipeline:cdk": "npx cdk deploy '*' --app 'ts-node ./bin/app-pipeline.ts' --profile pipeline",
"deploy-pipeline": "build && deploy-pipeline:cdk",
}
Upvotes: 1