Jenkins shared library and CDK constructs for AWS infrastructure. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
7.9 KiB
Persistent ALB Pattern (bg-common)
The persistent ALB pattern ensures that ALB DNS names remain constant even when service stacks are deleted and recreated. This matches the legacy bg-common pattern.
How It Works
The bg-common ALB stack is always created separately. Services reference it via albLoadBalancerArn:
- bg-common ALB stack is deployed separately (
{serviceStackName}-albor viaspicyALB) - The ALB stack persists across service deployments
- Service stacks reference the existing ALB via
albLoadBalancerArn(maps toexistingALBin construct) - ALB DNS name stays constant even when service stacks are deleted/recreated
Stack Naming
- ALB Stack:
{serviceStackName}-alb(shared between blue/green) - Service Stack (Rolling):
{serviceStackName} - Service Stack (Blue/Green):
{serviceStackName}-blueand{serviceStackName}-green
For blue/green deployments, both blue and green services share the same ALB stack.
Usage
Rolling Deployment (Non-Blue/Green)
@Library(["spicy-automation@main"]) _
spicyECSService(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-api-dev",
serviceName: "my-api",
// ... cluster/VPC config ...
// Container
image: "nexus.kodeniks.com/docker-hosted/my-api:latest",
containerPort: 3000,
// Reference bg-common ALB (always created separately) - auto-imports from ALB stack
albStackName: "my-api-dev-alb", // Auto-imports ALB ARN and listener ARNs
// Routing
hostHeader: "api-dev.example.com",
priority: 100,
// Tags
ownerTag: "MyTeam",
productTag: "my-product",
componentTag: "api",
environment: "dev",
)
What happens:
- Pipeline deploys
my-api-dev-albstack (ALB) - Pipeline gets ALB outputs (DNS, listener ARNs)
- Pipeline deploys
my-api-devstack (service) referencing the ALB - ALB DNS name stays constant:
my-api-dev-alb-123456789.ca-central-1.elb.amazonaws.com
Blue/Green Deployment
@Library(["spicy-automation@main"]) _
spicyECSService(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-api-prod", // Base name (blue/green suffixes added automatically)
serviceName: "my-api",
// ... cluster/VPC config ...
// Container
image: "nexus.kodeniks.com/docker-hosted/my-api:latest",
containerPort: 3000,
// Blue/Green
blueGreen: true,
activeHostname: "api.example.com",
inactiveHostname: "inactive-api.example.com",
bgHostedZoneId: "Z1234567890", // Route53 hosted zone
// Reference bg-common ALB (always created separately) - auto-imports from ALB stack
albStackName: "my-api-prod-alb", // Auto-imports ALB ARN and listener ARNs
healthCheckPath: "/health",
// Tags
ownerTag: "MyTeam",
productTag: "my-product",
componentTag: "api",
environment: "prod",
)
What happens:
- Pipeline deploys
my-api-prod-albstack (ALB) - only once, shared by blue/green - Pipeline gets ALB outputs (or uses
albStackNamefor auto-import) - Pipeline deploys
my-api-prod-greenstack (inactive service) referencing the ALB - Service creates listener rules on both HTTP and HTTPS listeners (if both available)
- Pipeline swaps hostname routing via ALB listener rule priorities (no DNS changes)
- ALB DNS name stays constant across all deployments
How Blue/Green Routing Works:
- DNS Records: Both
api.example.comandinactive-api.example.comDNS records are created and always point to the same ALB - Traffic Routing: Controlled by ALB listener rule priorities, not DNS:
- Active service: Listener rule with priority 100 for
api.example.com - Inactive service: Listener rule with priority 200 for
inactive-api.example.com
- Active service: Listener rule with priority 100 for
- Swapping: When swapping, only the listener rule priorities are updated (via CDK deployment). DNS records never change.
- Result: Zero-downtime swaps in ~30 seconds (just ALB rule updates, no DNS propagation delays)
Benefits
- Static DNS: ALB DNS name never changes (unless ALB stack is deleted)
- No DNS Updates: Cloudflare/Route53 records set once and never need updating
- Faster Deployments: ALB stack only updates when ALB config changes
- Cost Efficient: ALB persists, avoiding recreation costs
ALB Stack Lifecycle
- Created: Deployed separately via
spicyALBpipeline function or manually - Updated: When ALB configuration changes (certificate, scheme, etc.)
- Deleted: Only when explicitly destroyed (not deleted with service stacks)
Stack Outputs
The ALB stack exports these outputs (used by service stacks via CloudFormation imports):
| Output Key | Description | Export Name |
|---|---|---|
LoadBalancerDNS |
ALB DNS name | {stackName}-internet-facing-url |
LoadBalancerArn |
ALB ARN | {stackName}-internet-facing-arn |
HTTPListenerArn |
HTTP listener ARN | {stackName}-internet-facing-http-listener |
HTTPSListenerArn |
HTTPS listener ARN | {stackName}-internet-facing-https-listener |
Minimal Props: When using albStackName in service stack, these are auto-imported via CloudFormation Fn::ImportValue. The service creates listener rules on both HTTP and HTTPS listeners (if both are available), matching the old template behavior.
| SecurityGroupId | ALB security group ID | {stackName}-internet-facing-security-group |
Deploying the bg-common ALB Stack
The bg-common ALB stack must be deployed separately before deploying services:
@Library(["spicy-automation@main"]) _
// Deploy bg-common ALB stack
spicyALB(
jenkinsAwsCredentialsId: "aws-credentials",
region: "ca-central-1",
stackName: "my-api-dev-alb",
vpcId: "vpc-12345678",
availabilityZones: "ca-central-1a,ca-central-1b",
subnetIds: "subnet-xxx,subnet-yyy",
scheme: "internet-facing",
certificateArn: "arn:aws:acm:...",
ownerTag: "MyTeam",
productTag: "my-product",
componentTag: "alb",
environment: "dev",
)
// Then deploy service referencing the ALB
spicyECSService(
// ... config ...
albLoadBalancerArn: "arn:aws:elasticloadbalancing:...", // From ALB stack outputs
albHttpsListenerArn: "arn:aws:elasticloadbalancing:...", // From ALB stack outputs
)
Comparison with Legacy bg-common
| Feature | Legacy bg-common | New Persistent ALB |
|---|---|---|
| Stack Name | {envName}-bg-common |
{serviceStackName}-alb |
| Deployment | Separate pipeline step | Separate pipeline step (via spicyALB) |
| Blue/Green | Shared ALB | Shared ALB |
| DNS Management | Manual | Automatic (Route53) or Manual (Cloudflare) |
| Stack Lifecycle | Manual | Manual (deployed separately) |
Troubleshooting
ALB Stack Not Found
If the ALB stack doesn't exist, the pipeline will create it automatically. If you see errors:
- Check the ALB stack name:
{serviceStackName}-alb - Verify the stack exists:
aws cloudformation describe-stacks --stack-name {stackName}-alb - Check stack outputs:
aws cloudformation describe-stacks --stack-name {stackName}-alb --query 'Stacks[0].Outputs'
ALB DNS Name Changed
This should never happen with the persistent ALB pattern. If it does:
- Check if the ALB stack was deleted/recreated
- Verify the ALB stack name is consistent
- Check CloudFormation stack events for ALB replacement
Service Can't Find ALB
If the service stack can't reference the ALB:
- Verify ALB stack outputs are available
- Check that
albLoadBalancerArnis set in the service context - Verify the ALB ARN is correct