Jenkins shared library and CDK constructs for AWS infrastructure. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Spicy Automation
AWS CDK infrastructure and Jenkins shared library for Spicy automation. This replaces the legacy Ansible/CloudFormation approach with type-safe TypeScript and integrated Jenkins pipelines.
Quick Start
Minimal VPC Deployment
Create a Jenkinsfile in your VPC repository:
@Library(["spicy-automation@main"]) _
spicyVPC(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-vpc",
ownerTag: "MyTeam",
productTag: "myproduct",
componentTag: "vpc",
)
Minimal ECS Cluster Deployment - Using CloudFormation Imports
Minimal props: Only vpcStackName and numberOfAzs required. VPC info auto-imports from VPC stack exports.
@Library(["spicy-automation@main"]) _
spicyECSCluster(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-ecs-cluster",
vpcStackName: "my-vpc", // Auto-imports VPC ID, CIDR, subnets, and AZs
numberOfAzs: 3,
ownerTag: "MyTeam",
productTag: "myproduct",
componentTag: "ecs-cluster",
environment: "dev"
)
Explicit IDs (backward compatible):
spicyECSCluster(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-ecs-cluster",
vpcId: "vpc-12345678",
vpcCidrBlock: "10.0.0.0/16",
availabilityZones: "ca-central-1a,ca-central-1b,ca-central-1c",
privateSubnetIds: "subnet-aaa,subnet-bbb,subnet-ccc",
ownerTag: "MyTeam",
productTag: "myproduct",
componentTag: "ecs-cluster",
environment: "dev"
)
ECS Service with Mixed Capacity (EC2 + Fargate Burst) - Minimal Props
Minimal props: Only clusterName required. VPC info auto-imports from CloudFormation exports.
@Library(["spicy-automation@main"]) _
spicyECSService(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-api-dev",
serviceName: "my-api",
clusterName: "my-ecs-cluster", // VPC stack name and VPC ID auto-import from cluster stack exports
image: "nexus.kodeniks.com/docker-hosted/my-api:latest",
containerPort: 3000,
capacityProviderStrategy: [
[capacityProvider: "my-ecs-cluster-ec2", base: 2, weight: 3],
[capacityProvider: "FARGATE_SPOT", weight: 1],
],
ownerTag: "MyTeam",
productTag: "myproduct",
componentTag: "api",
environment: "dev"
)
Explicit IDs (backward compatible):
spicyECSService(
// ... other params ...
clusterName: "my-ecs-cluster",
vpcId: "vpc-12345678",
vpcCidrBlock: "10.0.0.0/16",
availabilityZones: "ca-central-1a,ca-central-1b,ca-central-1c",
privateSubnetIds: "subnet-aaa,subnet-bbb,subnet-ccc",
)
Blue/Green Deployment with Instant Rollback
@Library(["spicy-automation@main"]) _
spicyECSService(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-api-prod",
serviceName: "my-api",
clusterName: "my-ecs-cluster-prod",
vpcId: "vpc-12345678",
vpcCidrBlock: "10.0.0.0/16",
availabilityZones: "ca-central-1a,ca-central-1b",
privateSubnetIds: "subnet-aaa,subnet-bbb",
image: "nexus.kodeniks.com/docker-hosted/my-api:latest",
containerPort: 3000,
// Enable Blue/Green
blueGreen: true,
activeHostname: "api.example.com",
inactiveHostname: "inactive-api.example.com",
// ALB routing - listener ARN auto-imports from ${clusterName}-internet-facing-https-listener
priority: 100,
useExternalALB: true,
// externalListenerArn auto-imports when useExternalALB=true
// Test before swap
blueGreenTest: { args, buildInfo ->
sh "curl -f https://${buildInfo.inactiveHostname}/health"
},
// Test after swap
smokeTest: { args, buildInfo ->
sh "curl -f https://${buildInfo.activeHostname}/health"
},
ownerTag: "Platform",
productTag: "myproduct",
componentTag: "api",
environment: "prod"
)
Instant Rollback (30 seconds)
@Library(["spicy-automation@main"]) _
spicyRollback(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-api-prod",
serviceName: "my-api",
// ... same params as deploy ...
)
Documentation
| Document | Description |
|---|---|
| VPC Guide | Complete VPC deployment guide with all options |
| ECS Cluster Guide | ECS cluster with Spot, Capacity Providers |
| ECS Service Guide | ECS service with mixed EC2/Fargate strategy |
| Persistent ALB | Persistent ALB pattern (1:1 with service) |
| Cost Optimization | Cost optimization for testing environments |
| CDK Synth Examples | Complete CDK synth command examples |
| Jenkins Utilities | All available Jenkins utility functions |
| Accounts Configuration | Multi-account setup guide |
| Local Development | Running CDK locally |
| NPM Example | Example Jenkinsfile for NPM publishing |
Features
Infrastructure (CDK)
- SpicyVpc: Multi-AZ VPC with public/private subnets, NAT gateways, NACLs, VPC endpoints
- SpicyEcsCluster: ECS cluster with EC2 Capacity Providers, Mixed Instances Policy for Spot, ALBs
- SpicyEcsService: ECS service with mixed capacity strategy, auto-scaling, circuit breaker
Blue/Green Deployments
- Zero-downtime releases with hostname-based routing
- Instant rollback (~30 seconds) via hostname swap
- Test before swap with
blueGreenTesthook - Rollback window - old version kept for 2+ hours
Pipeline Hooks
- buildCommand: Custom build logic
- onPostBuild: Unit tests, linting, coverage
- onPreDeploy: Setup, test preparation
- blueGreenTest: Integration tests on inactive stack
- onPostDeploy: Cleanup, notifications
- smokeTest: Post-deployment verification
Jenkins Pipelines
- spicyVPC: Deploy VPCs
- spicyECSCluster: Deploy ECS clusters with Spot support
- spicyECSService: Deploy ECS services with EC2 + Fargate burst, blue/green
- spicyRollback: Instant rollback for blue/green deployments
- buildAndPushDockerImage: Build and push Docker images to Nexus
Jenkins Setup
1. Configure Global Library
In Jenkins → Manage Jenkins → Configure System → Global Pipeline Libraries:
| Setting | Value |
|---|---|
| Name | spicy-automation |
| Default version | main |
| Retrieval method | Modern SCM → Git |
| Project Repository | git@git.kodeniks.com:CORP/spicy-automation.git |
| Library Path | jenkins/ |
2. Configure Credentials
| Credential ID | Type | Description |
|---|---|---|
aws-credentials |
Username/Password | AWS Access Key ID / Secret |
kodeniks-gitea-token |
Secret text | Gitea personal access token |
kodeniks-nexus-repository |
Username/Password | Nexus Docker registry credentials |
Project Structure
spicy-automation/
├── bin/spicy-cdk.ts # CDK app entry point
├── lib/
│ ├── constructs/ # Reusable CDK constructs
│ │ ├── spicy-vpc.ts # VPC construct
│ │ ├── spicy-ecs-cluster.ts # ECS cluster construct
│ │ └── spicy-ecs-service.ts # ECS service construct
│ └── stacks/ # CDK stacks
│ ├── spicy-vpc-stack.ts
│ ├── spicy-ecs-cluster-stack.ts
│ └── spicy-ecs-service-stack.ts
├── vars/ # Jenkins shared library
│ ├── spicyVPC.groovy # VPC pipeline
│ ├── spicyECSCluster.groovy # ECS cluster pipeline
│ ├── spicyECSService.groovy # ECS service pipeline
│ ├── buildAndPushDockerImage.groovy # Docker build pipeline
│ ├── cdkUtils.groovy # CDK commands
│ ├── dockerUtils.groovy # Docker/Nexus utilities
│ ├── gitUtils.groovy # Git utilities
│ ├── giteaUtils.groovy # Commit status updates
│ └── accounts.groovy # Account configurations
├── docs/ # Documentation
├── test/ # Jest tests
└── Dockerfile # Jenkins agent image
Useful Commands
# No build step required - runs directly with ts-node!
npx cdk synth -c stackType=vpc -c stackName=my-vpc ...
# Or use pnpm scripts
pnpm run test # Run Jest tests
pnpm run build # Compile TypeScript (optional)
Migration from spicy-automation-legacy
| Feature | spicy-automation-legacy | spicy-automation |
|---|---|---|
| Infrastructure | CloudFormation YAML | TypeScript CDK |
| Provisioning | Ansible | CDK CLI |
| Testing | None | Jest |
| Type Safety | None | Full TypeScript |
| Docker Registry | AWS ECR | Nexus |
CloudFormation outputs are identical, so existing stacks referencing VPC exports continue to work.