Jenkins shared library and CDK constructs for AWS infrastructure. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8.2 KiB
Local Development Guide
Run and test CDK locally without Jenkins.
Prerequisites
- Node.js 22+
- pnpm (package manager)
- AWS CLI (configured with credentials)
Setup
cd spicy-automation
# Install dependencies
pnpm install
Bootstrapping
Before deploying any CDK stacks, you must bootstrap the CDK environment in your AWS account and region. This is a one-time setup per account/region combination.
Bootstrap Command
# Using Docker (same as your deploy command)
docker run -v ~/.aws:/root/.aws:ro spicy-sdk \
cdk bootstrap \
aws://ACCOUNT_ID/REGION
# Or locally with npx
npx cdk bootstrap aws://ACCOUNT_ID/REGION
# Example for ca-central-1
npx cdk bootstrap aws://$AWS_ACCOUNT_ID/ca-central-1
What Bootstrap Does
CDK bootstrap creates the following resources in your AWS account:
- S3 bucket for storing CDK assets
- IAM roles for deployment
- SSM parameters for tracking bootstrap version
Verify Bootstrap Status
# Check if environment is bootstrapped
aws ssm get-parameter \
--name /cdk-bootstrap/hnb659fds/version \
--region ca-central-1
If the parameter exists, the environment is bootstrapped. If you get a ParameterNotFound error, you need to bootstrap.
Bootstrap Qualifier
This project uses the bootstrap qualifier hnb659fds (configured in cdk.json). This qualifier must match between bootstrap and deploy commands.
Running CDK Commands
CDK runs directly with ts-node - no build step required!
Synthesize a Template
# Minimal VPC
npx cdk synth \
-c stackType=vpc \
-c stackName=my-vpc \
-c ownerTag=MyTeam \
-c productTag=myapp \
-c componentTag=vpc
# With custom options
npx cdk synth \
-c stackType=vpc \
-c stackName=my-vpc \
-c ownerTag=MyTeam \
-c productTag=myapp \
-c componentTag=vpc \
-c vpcCidr=10.0.0.0/16 \
-c numberOfAzs=2 \
-c createAdditionalPrivateSubnets=false
Show Diff
npx cdk diff \
-c stackType=vpc \
-c stackName=my-vpc \
-c ownerTag=MyTeam \
-c productTag=myapp \
-c componentTag=vpc
Deploy
# Requires AWS credentials
export AWS_PROFILE=my-profile
# or
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=ca-central-1
npx cdk deploy \
-c stackType=vpc \
-c stackName=my-vpc \
-c ownerTag=MyTeam \
-c productTag=myapp \
-c componentTag=vpc
Destroy
npx cdk destroy \
-c stackType=vpc \
-c stackName=my-vpc \
-c stackType=vpc
Context Parameters
All VPC parameters can be passed via -c key=value:
| Context Key | Type | Description |
|---|---|---|
stackType |
string | Stack type: vpc, ecs-cluster, ecs-service |
stackName |
string | CloudFormation stack name |
ownerTag |
string | Owner tag |
productTag |
string | Product tag |
componentTag |
string | Component tag |
build |
string | Build tag (defaults to git SHA) |
vpcCidr |
string | VPC CIDR block |
vpcTenancy |
string | default or dedicated |
numberOfAzs |
string | 2, 3, or 4 |
availabilityZones |
string | Comma-separated AZ list |
createPrivateSubnets |
string | true or false |
createAdditionalPrivateSubnets |
string | true or false |
publicSubnetTag |
string | Tag for public subnets |
privateSubnetATag |
string | Tag for private subnets type 1 |
privateSubnetBTag |
string | Tag for private subnets type 2 |
Running Tests
# Run all tests
pnpm test
# Run with coverage
pnpm test -- --coverage
# Run specific test
pnpm test -- --testNamePattern="creates VPC"
# Watch mode
pnpm test -- --watch
Project Structure
spicy-automation/
├── bin/
│ └── spicy-cdk.ts # CDK app entry point
├── lib/
│ ├── constructs/ # Reusable constructs
│ │ ├── spicy-vpc.ts # VPC construct
│ │ └── index.ts
│ ├── stacks/ # Stack definitions
│ │ ├── spicy-vpc-stack.ts
│ │ └── index.ts
│ └── index.ts
├── test/
│ └── spicy-cdk.test.ts # Jest tests
├── jenkins/
│ └── vars/ # Jenkins shared library
├── cdk.json # CDK configuration
├── tsconfig.json # TypeScript configuration
└── package.json
Adding a New Construct
1. Create the Construct
lib/constructs/my-construct.ts:
import * as cdk from 'aws-cdk-lib/core';
import { Construct } from 'constructs';
export interface MyConstructProps {
readonly name: string;
// ... other props
}
export class MyConstruct extends Construct {
constructor(scope: Construct, id: string, props: MyConstructProps) {
super(scope, id);
// Create resources...
}
}
2. Export from Index
lib/constructs/index.ts:
export * from './spicy-vpc';
export * from './my-construct';
3. Create a Stack
lib/stacks/my-stack.ts:
import * as cdk from 'aws-cdk-lib/core';
import { Construct } from 'constructs';
import { MyConstruct, MyConstructProps } from '../constructs/my-construct';
export class MyStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: MyConstructProps & cdk.StackProps) {
super(scope, id, props);
new MyConstruct(this, 'MyConstruct', props);
}
static fromContext(scope: Construct, id: string, stackProps?: cdk.StackProps): MyStack {
const app = scope.node.root as cdk.App;
return new MyStack(app, id, {
...stackProps,
name: app.node.tryGetContext('name') ?? 'default',
});
}
}
4. Register in App
bin/spicy-cdk.ts:
import { MyStack } from '../lib/stacks';
switch (stackType) {
case 'vpc':
SpicyVpcStack.fromContext(app, stackName, { env });
break;
case 'my-stack':
MyStack.fromContext(app, stackName, { env });
break;
// ...
}
5. Add Tests
test/my-stack.test.ts:
import { Template } from 'aws-cdk-lib/assertions';
import * as cdk from 'aws-cdk-lib/core';
import { MyStack } from '../lib/stacks/my-stack';
describe('MyStack', () => {
test('creates resources', () => {
const app = new cdk.App();
const stack = new MyStack(app, 'TestStack', {
name: 'test',
});
const template = Template.fromStack(stack);
// Assert on resources
template.resourceCountIs('AWS::SomeService::Resource', 1);
});
});
TypeScript Configuration
The project uses CommonJS modules for compatibility with ts-node:
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"strict": true,
"esModuleInterop": true
}
}
Debugging
Enable CDK Debug Output
CDK_DEBUG=true npx cdk synth ...
View Synthesized Template
Templates are output to cdk.out/:
npx cdk synth -c stackType=vpc -c stackName=test ...
cat cdk.out/test.template.json | jq .
Check Logical IDs
Verify resource logical IDs are stable:
npx cdk synth ... 2>&1 | grep -E "^ [A-Za-z]+:"
Building (Optional)
While not required (ts-node runs TypeScript directly), you can compile:
# Compile to JavaScript
pnpm run build
# Watch mode
pnpm run watch
Output goes to dist/.
IDE Setup
VS Code
Recommended extensions:
- ESLint
- Prettier
- AWS Toolkit
.vscode/settings.json:
{
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true
}
Cursor
The project works out of the box with Cursor's TypeScript support.