npx skills add https://github.com/adaptationio/skrillz --skill ecs-deploymentSKILL.md
ECS Deployment Strategies
Complete guide to deploying ECS services safely and efficiently, from rolling updates to blue-green deployments.
Quick Reference
| Strategy | Downtime | Rollback Speed | Complexity | Best For |
|---|---|---|---|---|
| Rolling Update | Zero | Medium | Low | Most workloads |
| Blue-Green | Zero | Instant | High | Critical services |
| Canary | Zero | Fast | High | Risk mitigation |
Rolling Updates (Default)
Configuration
resource "aws_ecs_service" "app" {
deployment_configuration {
maximum_percent = 200 # Allow 2x during deployment
minimum_healthy_percent = 100 # Keep 100% healthy
}
deployment_circuit_breaker {
enable = true # Auto-detect failures
rollback = true # Auto-rollback on failure
}
}
Behavior
- New task definition registered
- New tasks launched (up to maximum_percent)
- Health checks pass on new tasks
- Old tasks drained and stopped
- Continues until all tasks updated
Boto3 Deployment
import boto3
ecs = boto3.client('ecs')
def deploy_rolling_update(cluster: str, service: str,
new_image: str, container_name: str):
"""Deploy new image via rolling update"""
# 1. Get current task definition
svc = ecs.describe_services(cluster=cluster, services=[service])
current_task_def = svc['services'][0]['taskDefinition']
# 2. Create new task definition revision
task_def = ecs.describe_task_definition(taskDefinition=current_task_def)
new_task_def = task_def['taskDefinition'].copy()
# Remove response-only fields
for field in ['taskDefinitionArn', 'revision', 'status',
'requiresAttributes', 'compatibilities',
'registeredAt', 'registeredBy']:
new_task_def.pop(field, None)
# Update image
for container in new_task_def['containerDefinitions']:
if container['name'] == container_name:
container['image'] = new_image
response = ecs.register_task_definition(**new_task_def)
new_task_def_arn = response['taskDefinition']['taskDefinitionArn']
# 3. Update service
ecs.update_service(
cluster=cluster,
service=service,
taskDefinition=new_task_def_arn,
forceNewDeployment=True
)
print(f"Deploying {new_task_def_arn}")
return new_task_def_arn
# Usage
deploy_rolling_update(
cluster='production',
service='api',
new_image='123456789.dkr.ecr.us-east-1.amazonaws.com/api:v2.0',
container_name='api'
)
Monitor Deployment
def wait_for_deployment(cluster: str, service: str, timeout: int = 600):
"""Wait for deployment to complete"""
import time
start = time.time()
while time.time() - start < timeout:
response = ecs.describe_services(cluster=cluster, services=[service])
svc = response['services'][0]
for deployment in svc['deployments']:
print(f"Deployment {deployment['id'][:8]}: "
f"{deployment['rolloutState']} "
f"({deployment['runningCount']}/{deployment['desiredCount']})")
if deployment['status'] == 'PRIMARY':
if deployment['rolloutState'] == 'COMPLETED':
print("Deployment successful!")
return True
elif deployment['rolloutState'] == 'FAILED':
print(f"Deployment failed: {deployment.get('rolloutStateReason')}")
return False
time.sleep(15)
print("Deployment timed out")
return False
Blue-Green Deployments
Architecture
┌─────────────┐
│ ALB │
└──────┬──────┘
│
┌───────────────┴───────────────┐
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Target Group│ │ Target Group│
│ (Blue) │ │ (Green) │
└──────┬──────┘ └──────┬──────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ ECS Service │ │ ECS Service │
│ (Blue) │ │ (Green) │
└─────────────┘ └─────────────┘
Terraform with CodeDeploy
# Two target groups
resource "aws_lb_target_group" "blue" {
name = "app-blue"
port = 8080
protocol = "HTTP"
vpc_id = module.vpc.vpc_id
target_type = "ip"
health_check {
path = "/health"
}
}
resource "aws_lb_target_group" "green" {
name = "app-green"
port = 8080
protocol = "HTTP"
vpc_id = module.vpc.vpc_id
target_type = "ip"
health_check {
path = "/health"
}
}
# ALB with two listeners
resource "aws_lb_listener" "prod" {
load_balancer_arn = aws_lb.app.arn
port = 443
protocol
...
Repository
adaptationio/skrillzParent repository
Repository Stats
Stars1
Forks0