Shipping code to production should be boring. If your deployments are stressful, your pipeline is wrong. A well-designed CI/CD pipeline makes releases routine, reversible, and observable — whether you deploy once a day or fifty times.
AWS provides both native CI/CD services (CodePipeline, CodeBuild, CodeDeploy) and deep integration with third-party tools (GitHub Actions, GitLab CI). The choice depends on your team's workflow preferences and how much you want to stay inside the AWS ecosystem.
This guide covers the deployment strategies that matter, the pipeline architectures that work, and the decision framework for choosing your CI/CD stack.
Deployment Strategies: How Code Reaches Production
Strategy 1: Rolling Deployment
How it works: Replace instances/tasks gradually. Old and new versions run simultaneously during the transition.
Time 0: [v1] [v1] [v1] [v1] (4 tasks, all v1)
Time 1: [v2] [v1] [v1] [v1] (1 updated)
Time 2: [v2] [v2] [v1] [v1] (2 updated)
Time 3: [v2] [v2] [v2] [v1] (3 updated)
Time 4: [v2] [v2] [v2] [v2] (complete)
Pros: Simple, no extra infrastructure, works everywhere.
Cons: Two versions run simultaneously (must be backward-compatible). Rollback means rolling forward to v1 again.
AWS implementation: ECS rolling update (default), EKS rolling update, EC2 Auto Scaling group instance refresh.
Strategy 2: Blue/Green Deployment
How it works: Deploy new version (green) alongside old version (blue). Switch traffic atomically. Keep blue alive for instant rollback.
┌─────────────────┐ ┌─────────────────┐
│ BLUE (v1) │ │ GREEN (v2) │
│ (serving) │ │ (staged) │
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────┐
│ ALB / Route53 │
│ 100% → Blue (until cutover) │
│ Then: 100% → Green │
└─────────────────────────────────────────────┘
Pros: Zero downtime. Instant rollback (switch traffic back to blue). Full testing on green before cutover.
Cons: 2x infrastructure during deployment (cost). Database schema changes need careful handling.
AWS implementation:
- ECS native blue/green (GA July 2025) — built into ECS service, no CodeDeploy needed
- CodeDeploy blue/green for ECS (original approach)
- Route53 weighted routing (for broader blue/green)
- ALB target group swap
Strategy 3: Canary Deployment
How it works: Route a small percentage of traffic (1-10%) to the new version. Monitor errors. If healthy, gradually shift more traffic. If unhealthy, route all traffic back to old version.
Step 1: 95% → v1, 5% → v2 (canary)
Step 2: 70% → v1, 30% → v2 (expanding)
Step 3: 50% → v1, 50% → v2 (halfway)
Step 4: 0% → v1, 100% → v2 (complete)
Pros: Minimal blast radius. Real production traffic validates new version. Automatic rollback on alarm.
Cons: Complex routing. Must handle session affinity. Slower than blue/green.
AWS implementation:
- ECS native canary/linear (GA October 2025) — percentage-based traffic shifting built into ECS
- CodeDeploy canary (Lambda, ECS)
- App Mesh / VPC Lattice (weighted routing between versions)
- ALB weighted target groups
Strategy 4: Feature Flags (Decouple Deploy from Release)
How it works: Deploy code with new features disabled. Enable features independently via configuration (not deployment). Rollback = toggle flag off.
AWS implementation: AppConfig feature flags (native), LaunchDarkly, or custom DynamoDB-backed flags.
Benefit: Deploy anytime. Release (enable feature) separately. Different features for different users (A/B testing).
ECS Native Deployment Capabilities (2025-2026)
ECS received major deployment upgrades — eliminating the need for CodeDeploy in most container scenarios:
| Feature | Release | What It Does |
|---|---|---|
| Native blue/green | July 2025 | Built-in blue/green without CodeDeploy |
| Linear/canary | October 2025 | Percentage-based traffic shifting |
| NLB support for linear/canary | February 2026 | Canary for TCP/gRPC workloads |
| Pause/continue | May 2026 | Pause deployment for manual validation |
| Configurable circuit breaker | July 2026 | Custom failure thresholds for auto-rollback |
ECS Deployment Configuration
{
"deploymentConfiguration": {
"deploymentType": "BLUE_GREEN",
"blueGreenDeploymentConfiguration": {
"trafficRoutingConfig": {
"type": "CANARY",
"canaryConfig": {
"interval": 300,
"percentage": 10
}
},
"terminationWaitTimeInMinutes": 60,
"deploymentCircuitBreaker": {
"enable": true,
"rollback": true,
"failureThreshold": 5
}
}
}
}
This deploys with 10% canary, waits 5 minutes, then shifts remaining traffic. If 5+ tasks fail health checks, automatic rollback triggers.
Pipeline Architecture: AWS-Native Stack
AWS CodePipeline + CodeBuild + CodeDeploy
┌──────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ Source │────→│ Build │────→│ Test │────→│ Deploy │
│(CodeCommit│ │(CodeBuild)│ │(CodeBuild)│ │(CodeDeploy│
│ or GitHub)│ │ │ │ │ │ or ECS) │
└──────────┘ └───────────┘ └───────────┘ └───────────┘
CodePipeline: Orchestrates the pipeline stages. Triggers on source change.
CodeBuild: Runs build commands, tests, security scans in managed containers.
CodeDeploy: Handles deployment strategies (rolling, blue/green, canary).
Pipeline Stages Best Practice
Source → Build → Unit Test → SAST Scan → Container Scan →
Deploy Dev → Integration Test → Deploy Staging →
Load Test → Manual Approval → Deploy Production
Multi-Account Pipeline Pattern
Tooling Account (pipeline lives here)
│
├── Deploy → Dev Account (automatic)
├── Deploy → Staging Account (automatic + integration tests)
└── Deploy → Production Account (manual approval gate)
Cross-account deployment uses IAM roles. Pipeline in tooling account assumes role in target account to deploy.
Pipeline Architecture: GitHub Actions
For teams using GitHub as source control, GitHub Actions provides a complete CI/CD solution with AWS integration:
name: Deploy to ECS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC for AWS auth
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
aws-region: eu-west-1
- uses: aws-actions/amazon-ecr-login@v2
- name: Build and push image
run: |
docker build -t $ECR_REGISTRY/my-app:$GITHUB_SHA .
docker push $ECR_REGISTRY/my-app:$GITHUB_SHA
- uses: aws-actions/amazon-ecs-deploy-task-definition@v2
with:
task-definition: task-def.json
service: my-service
cluster: production
wait-for-service-stability: true
GitHub Actions + OIDC (No Long-Lived Credentials)
Use OpenID Connect (OIDC) to authenticate GitHub Actions to AWS — no access keys needed:
- Create IAM Identity Provider for GitHub in AWS
- Create IAM role with trust policy for specific repo/branch
- GitHub Actions exchanges OIDC token for temporary AWS credentials
Security: Credentials are short-lived (1 hour), scoped to specific repos, and never stored as secrets.
CodePipeline vs GitHub Actions vs GitLab CI
| Criteria | CodePipeline | GitHub Actions | GitLab CI |
|---|---|---|---|
| Source integration | CodeCommit, GitHub, S3, ECR | GitHub (native) | GitLab (native) |
| Build | CodeBuild (managed) | Hosted runners or self-hosted | Shared or self-hosted runners |
| AWS integration | Deep (native IAM, VPC, cross-account) | Good (via aws-actions, OIDC) | Good (via CLI, OIDC) |
| Deployment strategies | CodeDeploy (full support) | Manual (scripts + AWS CLI) | Manual (scripts + AWS CLI) |
| Pricing | Free pipeline + CodeBuild minutes ($0.005/min) | 2000 free min/month, then $0.008/min | 400 free min/month, then $0.005/min |
| Ecosystem | AWS-only | 20K+ marketplace actions | 500+ templates |
| Multi-cloud | ❌ | ✅ | ✅ |
| Pipeline as code | YAML or console | YAML (.github/workflows/) |
YAML (.gitlab-ci.yml) |
| Approval gates | Manual approval action | Environment protection rules | Manual jobs |
| Best for | AWS-native teams, complex deployment strategies | Teams on GitHub, multi-cloud | Teams on GitLab, self-hosted preference |
When to Choose What
- CodePipeline: You want native blue/green/canary via CodeDeploy, cross-account deployment patterns, or deep AWS integration without custom scripting.
- GitHub Actions: Your code lives on GitHub, team prefers GitHub's ecosystem, and you want multi-cloud flexibility.
- GitLab CI: Your code lives on GitLab, you want self-hosted runners, or you need built-in security scanning (SAST/DAST).
Security in the Pipeline
Shift-Left Security
| Stage | Tool | What It Catches |
|---|---|---|
| Pre-commit | git-secrets, talisman | Hardcoded credentials before they enter repo |
| Build | SAST (CodeGuru, Snyk, Semgrep) | Code vulnerabilities (SQL injection, XSS) |
| Build | SCA (Dependabot, Snyk) | Vulnerable dependencies |
| Container Build | ECR image scanning, Trivy | Container CVEs |
| Pre-Deploy | IAM policy validation (IAM Access Analyzer) | Over-privileged roles |
| Post-Deploy | DAST (OWASP ZAP) | Runtime vulnerabilities |
Pipeline Security Best Practices
- No long-lived credentials — use OIDC (GitHub) or IAM roles (CodeBuild)
- Least privilege — pipeline role can only deploy to specific services/accounts
- Artifact signing — sign container images (cosign / Notation) to ensure integrity
-
Immutable artifacts — tag images with git SHA, never overwrite
:latestin production - Approval gates — require human approval before production deployment
- Audit trail — CloudTrail logs all deployment actions
Deployment Observability
A deployment isn't done when the pipeline turns green. Monitor after deploy:
Post-Deploy Validation
Deploy v2 → Wait 5 min → Check:
├── Error rate increased? → Rollback
├── Latency p99 > threshold? → Rollback
├── Health check failures? → Rollback
└── All green → Deployment successful
CloudWatch Alarms as Deployment Gates
Configure CodeDeploy / ECS circuit breaker to monitor CloudWatch alarms:
- If alarm triggers during canary/linear deployment → automatic rollback
- No human intervention needed for obvious failures
Common Pipeline Anti-Patterns
| Anti-Pattern | Problem | Fix |
|---|---|---|
| No staging environment | Bugs found in production | Always deploy to staging first |
| Tests only in CI, not in deployment | Broken integration passes build | Run integration tests post-deploy |
| Manual deployment to production | Error-prone, unauditable | Automate everything, gate with approval |
| Same pipeline for all environments | No quality gates between stages | Multi-stage with promotion (dev → staging → prod) |
:latest tag in production |
Can't tell which version is running | Use git SHA or semantic version tags |
| Secrets in pipeline code | Credential exposure | Use OIDC, Secrets Manager, or Parameter Store |
| No rollback plan | Stuck with broken deployment | Blue/green or canary with auto-rollback |
Summary
CI/CD on AWS comes down to three decisions:
- Deployment strategy — Rolling (simple), Blue/Green (zero-downtime), Canary (lowest risk), or Feature Flags (decouple deploy from release)
- Pipeline tool — CodePipeline (AWS-native, deep integration), GitHub Actions (flexible, multi-cloud), or GitLab CI (self-hosted, built-in security)
- Safety mechanisms — Approval gates, CloudWatch alarm-based rollback, immutable artifacts, shift-left security scanning
The 2026 default for containers: ECS native blue/green with canary traffic shifting + configurable circuit breaker. No CodeDeploy needed for standard ECS workloads.
The 2026 default for pipeline: GitHub Actions with OIDC auth for most teams. CodePipeline when you need native cross-account patterns or CodeDeploy's advanced strategies.
Alpesh Kumbhare is an AWS Architect at Atos, specializing in AWS infrastructure automation and DevOps practices. Connect on LinkedIn.
Top comments (0)