Jenkins shared library and CDK constructs for AWS infrastructure. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
280 lines
9.9 KiB
Markdown
280 lines
9.9 KiB
Markdown
# 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:
|
|
|
|
```groovy
|
|
@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.
|
|
|
|
```groovy
|
|
@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):**
|
|
|
|
```groovy
|
|
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.
|
|
|
|
```groovy
|
|
@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):**
|
|
|
|
```groovy
|
|
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
|
|
|
|
```groovy
|
|
@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)
|
|
|
|
```groovy
|
|
@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](docs/VPC.md) | Complete VPC deployment guide with all options |
|
|
| [ECS Cluster Guide](docs/ECS_CLUSTER.md) | ECS cluster with Spot, Capacity Providers |
|
|
| [ECS Service Guide](docs/ECS_SERVICE.md) | ECS service with mixed EC2/Fargate strategy |
|
|
| [Persistent ALB](docs/PERSISTENT_ALB.md) | Persistent ALB pattern (1:1 with service) |
|
|
| [Cost Optimization](docs/COST_OPTIMIZATION_TESTING.md) | Cost optimization for testing environments |
|
|
| [CDK Synth Examples](docs/CDK_SYNTH_EXAMPLES.md) | Complete CDK synth command examples |
|
|
| [Jenkins Utilities](docs/JENKINS_UTILITIES.md) | All available Jenkins utility functions |
|
|
| [Accounts Configuration](docs/ACCOUNTS.md) | Multi-account setup guide |
|
|
| [Local Development](docs/DEVELOPMENT.md) | Running CDK locally |
|
|
| [NPM Example](docs/JENKINSFILE_EXAMPLE_NPM.md) | 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 `blueGreenTest` hook
|
|
- **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
|
|
|
|
```bash
|
|
# 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.
|