Module Overview
Estimated Time: 4-5 hours | Difficulty: Advanced | Prerequisites: Compute, Security, Networking
- CodePipeline, CodeBuild, CodeDeploy for CI/CD
- CloudFormation for infrastructure provisioning
- AWS CDK for programmatic infrastructure
- Deployment strategies (blue-green, canary)
- GitOps and infrastructure automation
- DevOps best practices and patterns
AWS DevOps Services Overview
Copy
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AWS DevOps Ecosystem โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ SOURCE BUILD DEPLOY โ
โ โโโโโโ โโโโโ โโโโโโ โ
โ CodeCommit CodeBuild CodeDeploy โ
โ GitHub (Compile, Test, (EC2, ECS, โ
โ Bitbucket Package) Lambda, On-prem) โ
โ S3 โ
โ โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโ โ
โ โ CodePipelineโ โ
โ โ (Orchestrate)โ โ
โ โโโโโโโโโโโโโโโ โ
โ โ
โ INFRASTRUCTURE AS CODE: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โข CloudFormation (YAML/JSON templates) โ
โ โข AWS CDK (TypeScript, Python, Java, Go, C#) โ
โ โข Terraform (HCL, multi-cloud) โ
โ โข Pulumi (General-purpose languages) โ
โ โ
โ SUPPORTING SERVICES: โ
โ โข CodeArtifact (Package management) โ
โ โข ECR (Container registry) โ
โ โข Systems Manager (Configuration) โ
โ โข Secrets Manager (Credentials) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
CodePipeline
Pipeline Architecture
Copy
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CodePipeline Structure โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ PIPELINE โ โ
โ โ โ โ
โ โ Stage 1: Source โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Action: GitHub (Push to main) โ โ โ
โ โ โ Output: SourceArtifact โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ โ โ
โ โ โผ โ โ
โ โ Stage 2: Build โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Action: CodeBuild โ โ โ
โ โ โ Input: SourceArtifact โ โ โ
โ โ โ Output: BuildArtifact โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ โ โ
โ โ โผ โ โ
โ โ Stage 3: Test (Parallel Actions) โ โ
โ โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Unit Tests โ โ Integration โ โ Security Scan โ โ โ
โ โ โ (CodeBuild) โ โ Tests โ โ (CodeBuild) โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ โ โ
โ โ โผ โ โ
โ โ Stage 4: Deploy to Staging โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Action: CodeDeploy (Blue/Green) โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ โ โ
โ โ โผ โ โ
โ โ Stage 5: Manual Approval โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Action: Approval (SNS notification) โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ โ โ
โ โ โผ โ โ
โ โ Stage 6: Deploy to Production โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ Action: CodeDeploy (Canary 10%, then 100%) โ โ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ
โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
CodePipeline Terraform
Copy
# CodePipeline with GitHub source and ECS deploy
resource "aws_codepipeline" "app_pipeline" {
name = "app-pipeline"
role_arn = aws_iam_role.codepipeline_role.arn
artifact_store {
location = aws_s3_bucket.pipeline_artifacts.bucket
type = "S3"
encryption_key {
id = aws_kms_key.pipeline.arn
type = "KMS"
}
}
# Source Stage - GitHub
stage {
name = "Source"
action {
name = "GitHub_Source"
category = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["source_output"]
configuration = {
ConnectionArn = aws_codestarconnections_connection.github.arn
FullRepositoryId = "myorg/myrepo"
BranchName = "main"
DetectChanges = true
}
}
}
# Build Stage
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["source_output"]
output_artifacts = ["build_output"]
version = "1"
configuration = {
ProjectName = aws_codebuild_project.app_build.name
}
}
}
# Test Stage (Parallel)
stage {
name = "Test"
action {
name = "UnitTests"
category = "Test"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["source_output"]
version = "1"
run_order = 1
configuration = {
ProjectName = aws_codebuild_project.unit_tests.name
}
}
action {
name = "SecurityScan"
category = "Test"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["source_output"]
version = "1"
run_order = 1 # Same run_order = parallel
configuration = {
ProjectName = aws_codebuild_project.security_scan.name
}
}
}
# Deploy to Staging
stage {
name = "Deploy_Staging"
action {
name = "Deploy"
category = "Deploy"
owner = "AWS"
provider = "ECS"
input_artifacts = ["build_output"]
version = "1"
configuration = {
ClusterName = aws_ecs_cluster.staging.name
ServiceName = aws_ecs_service.staging.name
FileName = "imagedefinitions.json"
}
}
}
# Manual Approval
stage {
name = "Approval"
action {
name = "ManualApproval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = "1"
configuration = {
NotificationArn = aws_sns_topic.pipeline_approvals.arn
CustomData = "Please review staging deployment before production"
}
}
}
# Deploy to Production
stage {
name = "Deploy_Production"
action {
name = "Deploy"
category = "Deploy"
owner = "AWS"
provider = "CodeDeployToECS"
input_artifacts = ["build_output"]
version = "1"
configuration = {
ApplicationName = aws_codedeploy_app.app.name
DeploymentGroupName = aws_codedeploy_deployment_group.prod.deployment_group_name
TaskDefinitionTemplateArtifact = "build_output"
TaskDefinitionTemplatePath = "taskdef.json"
AppSpecTemplateArtifact = "build_output"
AppSpecTemplatePath = "appspec.yaml"
}
}
}
}
CodeBuild
Build Specification
Copy
# buildspec.yml
version: 0.2
env:
variables:
NODE_ENV: production
parameter-store:
DB_PASSWORD: /app/db/password
secrets-manager:
API_KEY: prod/api-key:API_KEY
phases:
install:
runtime-versions:
nodejs: 18
commands:
- echo Installing dependencies...
- npm ci
pre_build:
commands:
- echo Logging into ECR...
- aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REPO
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:-latest}
build:
commands:
- echo Building application...
- npm run build
- echo Building Docker image...
- docker build -t $ECR_REPO:$IMAGE_TAG .
- docker tag $ECR_REPO:$IMAGE_TAG $ECR_REPO:latest
post_build:
commands:
- echo Pushing Docker image...
- docker push $ECR_REPO:$IMAGE_TAG
- docker push $ECR_REPO:latest
- echo Creating image definitions file...
- printf '[{"name":"app","imageUri":"%s"}]' $ECR_REPO:$IMAGE_TAG > imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
- taskdef.json
- appspec.yaml
discard-paths: yes
cache:
paths:
- node_modules/**/*
- /root/.npm/**/*
reports:
jest-reports:
files:
- 'coverage/clover.xml'
file-format: CLOVERXML
security-reports:
files:
- 'trivy-results.json'
file-format: CUCUMBERJSON
CodeBuild Project Terraform
Copy
resource "aws_codebuild_project" "app_build" {
name = "app-build"
description = "Build and push Docker image"
build_timeout = "30"
service_role = aws_iam_role.codebuild_role.arn
artifacts {
type = "CODEPIPELINE"
}
environment {
compute_type = "BUILD_GENERAL1_MEDIUM"
image = "aws/codebuild/amazonlinux2-x86_64-standard:4.0"
type = "LINUX_CONTAINER"
image_pull_credentials_type = "CODEBUILD"
privileged_mode = true # Required for Docker builds
environment_variable {
name = "ECR_REPO"
value = aws_ecr_repository.app.repository_url
}
environment_variable {
name = "AWS_REGION"
value = data.aws_region.current.name
}
}
source {
type = "CODEPIPELINE"
buildspec = "buildspec.yml"
}
cache {
type = "LOCAL"
modes = ["LOCAL_DOCKER_LAYER_CACHE", "LOCAL_SOURCE_CACHE"]
}
logs_config {
cloudwatch_logs {
group_name = "/codebuild/app-build"
stream_name = "build-logs"
}
}
vpc_config {
vpc_id = aws_vpc.main.id
subnets = aws_subnet.private[*].id
security_group_ids = [aws_security_group.codebuild.id]
}
}
CodeDeploy
Deployment Strategies
Copy
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Deployment Strategies โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ IN-PLACE (Rolling) โ
โ โโโโโโโโโโโโโโโโโโ โ
โ [v1] [v1] [v1] [v1] โโโถ [v2] [v1] [v1] [v1] โโโถ [v2] [v2]...โ
โ โข Update instances one at a time โ
โ โข Brief capacity reduction โ
โ โข Rollback = redeploy v1 โ
โ โข Good for: EC2, on-prem โ
โ โ
โ BLUE/GREEN โ
โ โโโโโโโโโโ โ
โ Blue (v1): [โ ] [โ ] [โ ] [โ ] โโโ Production traffic โ
โ Green(v2): [โก] [โก] [โก] [โก] โโโ New version deployed โ
โ โ
โ After testing, swap traffic: โ
โ Blue (v1): [โ ] [โ ] [โ ] [โ ] โโโ Standby (for rollback) โ
โ Green(v2): [โก] [โก] [โก] [โก] โโโ Production traffic โ
โ โ
โ โข Zero downtime โ
โ โข Instant rollback (swap back) โ
โ โข Double the resources temporarily โ
โ โข Good for: ECS, Lambda, critical apps โ
โ โ
โ CANARY โ
โ โโโโโโ โ
โ [v1] [v1] [v1] [v1] โโโถ [v2] [v1] [v1] [v1] (10% traffic) โ
โ Monitor for errors... โ
โ If healthy: โโโถ [v2] [v2] [v2] [v2] (100% traffic) โ
โ If errors: โโโถ [v1] [v1] [v1] [v1] (rollback) โ
โ โ
โ CANARY OPTIONS: โ
โ โข Canary10Percent5Minutes โ
โ โข Canary10Percent10Minutes โ
โ โข Canary10Percent15Minutes โ
โ โข Linear10PercentEvery1Minute โ
โ โข Linear10PercentEvery3Minutes โ
โ โข AllAtOnce (not recommended for prod) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
CodeDeploy for ECS
Copy
# appspec.yaml for ECS Blue/Green
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: <TASK_DEFINITION>
LoadBalancerInfo:
ContainerName: "app"
ContainerPort: 8080
PlatformVersion: "LATEST"
Hooks:
- BeforeInstall: "LambdaFunctionToValidateBeforeInstall"
- AfterInstall: "LambdaFunctionToValidateAfterInstall"
- AfterAllowTestTraffic: "LambdaFunctionToRunSmokeTests"
- BeforeAllowTraffic: "LambdaFunctionToValidateBeforeTraffic"
- AfterAllowTraffic: "LambdaFunctionToValidateAfterTraffic"
Copy
# CodeDeploy for ECS with Blue/Green
resource "aws_codedeploy_app" "app" {
name = "app"
compute_platform = "ECS"
}
resource "aws_codedeploy_deployment_group" "production" {
app_name = aws_codedeploy_app.app.name
deployment_group_name = "production"
service_role_arn = aws_iam_role.codedeploy_role.arn
deployment_config_name = "CodeDeployDefault.ECSCanary10Percent5Minutes"
ecs_service {
cluster_name = aws_ecs_cluster.main.name
service_name = aws_ecs_service.app.name
}
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
blue_green_deployment_config {
deployment_ready_option {
action_on_timeout = "CONTINUE_DEPLOYMENT"
wait_time_in_minutes = 0
}
terminate_blue_instances_on_deployment_success {
action = "TERMINATE"
termination_wait_time_in_minutes = 60
}
}
load_balancer_info {
target_group_pair_info {
prod_traffic_route {
listener_arns = [aws_lb_listener.https.arn]
}
test_traffic_route {
listener_arns = [aws_lb_listener.test.arn]
}
target_group {
name = aws_lb_target_group.blue.name
}
target_group {
name = aws_lb_target_group.green.name
}
}
}
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE", "DEPLOYMENT_STOP_ON_ALARM"]
}
alarm_configuration {
enabled = true
alarms = [aws_cloudwatch_metric_alarm.error_rate.name]
}
}
CloudFormation
Stack Template
Copy
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Production VPC with ECS Cluster'
Parameters:
Environment:
Type: String
Default: production
AllowedValues: [development, staging, production]
VpcCidr:
Type: String
Default: 10.0.0.0/16
Mappings:
EnvironmentConfig:
development:
InstanceType: t3.small
MinSize: 1
MaxSize: 2
staging:
InstanceType: t3.medium
MinSize: 2
MaxSize: 4
production:
InstanceType: t3.large
MinSize: 3
MaxSize: 10
Conditions:
IsProduction: !Equals [!Ref Environment, production]
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub ${Environment}-vpc
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 6, 8]]
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${Environment}-public-1
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub ${Environment}-cluster
ClusterSettings:
- Name: containerInsights
Value: !If [IsProduction, enabled, disabled]
CapacityProviders:
- FARGATE
- FARGATE_SPOT
DefaultCapacityProviderStrategy:
- CapacityProvider: FARGATE
Weight: !If [IsProduction, 1, 0]
- CapacityProvider: FARGATE_SPOT
Weight: !If [IsProduction, 0, 1]
# Nested stack for modularity
DatabaseStack:
Type: AWS::CloudFormation::Stack
Condition: IsProduction
Properties:
TemplateURL: https://s3.amazonaws.com/templates/database.yaml
Parameters:
VpcId: !Ref VPC
SubnetIds: !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
Outputs:
VpcId:
Description: VPC ID
Value: !Ref VPC
Export:
Name: !Sub ${Environment}-VpcId
ClusterArn:
Description: ECS Cluster ARN
Value: !GetAtt ECSCluster.Arn
Export:
Name: !Sub ${Environment}-ClusterArn
AWS CDK
CDK Application Structure
Copy
// lib/app-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as rds from 'aws-cdk-lib/aws-rds';
import { Construct } from 'constructs';
interface AppStackProps extends cdk.StackProps {
environment: 'development' | 'staging' | 'production';
}
export class AppStack extends cdk.Stack {
public readonly cluster: ecs.Cluster;
public readonly service: ecs_patterns.ApplicationLoadBalancedFargateService;
constructor(scope: Construct, id: string, props: AppStackProps) {
super(scope, id, props);
const isProd = props.environment === 'production';
// VPC with public and private subnets
const vpc = new ec2.Vpc(this, 'VPC', {
maxAzs: isProd ? 3 : 2,
natGateways: isProd ? 3 : 1,
subnetConfiguration: [
{
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
cidrMask: 24,
},
{
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
cidrMask: 24,
},
{
name: 'Isolated',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
cidrMask: 24,
},
],
});
// ECS Cluster
this.cluster = new ecs.Cluster(this, 'Cluster', {
vpc,
containerInsights: isProd,
enableFargateCapacityProviders: true,
});
// RDS Database (production only)
const database = isProd
? new rds.DatabaseInstance(this, 'Database', {
engine: rds.DatabaseInstanceEngine.postgres({
version: rds.PostgresEngineVersion.VER_15,
}),
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.R6G,
ec2.InstanceSize.LARGE
),
vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
multiAz: true,
allocatedStorage: 100,
storageEncrypted: true,
deletionProtection: true,
})
: undefined;
// Fargate Service with ALB
this.service = new ecs_patterns.ApplicationLoadBalancedFargateService(
this,
'Service',
{
cluster: this.cluster,
cpu: isProd ? 1024 : 256,
memoryLimitMiB: isProd ? 2048 : 512,
desiredCount: isProd ? 3 : 1,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('nginx:latest'),
containerPort: 80,
environment: {
NODE_ENV: props.environment,
...(database && {
DB_HOST: database.instanceEndpoint.hostname,
}),
},
},
publicLoadBalancer: true,
circuitBreaker: { rollback: true },
capacityProviderStrategies: [
{
capacityProvider: isProd ? 'FARGATE' : 'FARGATE_SPOT',
weight: 1,
},
],
}
);
// Auto Scaling
const scaling = this.service.service.autoScaleTaskCount({
minCapacity: isProd ? 3 : 1,
maxCapacity: isProd ? 20 : 3,
});
scaling.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 70,
scaleInCooldown: cdk.Duration.seconds(60),
scaleOutCooldown: cdk.Duration.seconds(60),
});
scaling.scaleOnRequestCount('RequestScaling', {
requestsPerTarget: 1000,
targetGroup: this.service.targetGroup,
});
// Outputs
new cdk.CfnOutput(this, 'LoadBalancerDNS', {
value: this.service.loadBalancer.loadBalancerDnsName,
});
}
}
// bin/app.ts
import * as cdk from 'aws-cdk-lib';
import { AppStack } from '../lib/app-stack';
const app = new cdk.App();
// Development
new AppStack(app, 'AppDev', {
environment: 'development',
env: { account: '111111111111', region: 'us-east-1' },
});
// Production
new AppStack(app, 'AppProd', {
environment: 'production',
env: { account: '222222222222', region: 'us-east-1' },
});
CDK Pipeline
Copy
// lib/pipeline-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as pipelines from 'aws-cdk-lib/pipelines';
import { Construct } from 'constructs';
import { AppStack } from './app-stack';
export class PipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Self-mutating pipeline
const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
pipelineName: 'AppPipeline',
synth: new pipelines.ShellStep('Synth', {
input: pipelines.CodePipelineSource.gitHub('org/repo', 'main', {
authentication: cdk.SecretValue.secretsManager('github-token'),
}),
commands: [
'npm ci',
'npm run build',
'npm run test',
'npx cdk synth',
],
}),
dockerEnabledForSynth: true,
});
// Staging stage
const staging = pipeline.addStage(
new AppStage(this, 'Staging', {
environment: 'staging',
env: { account: '111111111111', region: 'us-east-1' },
}),
{
pre: [
new pipelines.ShellStep('IntegrationTests', {
commands: ['npm run test:integration'],
}),
],
post: [
new pipelines.ShellStep('SmokeTests', {
commands: ['curl -f https://staging.example.com/health'],
}),
],
}
);
// Production stage with approval
pipeline.addStage(
new AppStage(this, 'Production', {
environment: 'production',
env: { account: '222222222222', region: 'us-east-1' },
}),
{
pre: [
new pipelines.ManualApprovalStep('PromoteToProduction', {
comment: 'Approve production deployment',
}),
],
}
);
}
}
class AppStage extends cdk.Stage {
constructor(
scope: Construct,
id: string,
props: cdk.StageProps & { environment: string }
) {
super(scope, id, props);
new AppStack(this, 'App', { environment: props.environment as any });
}
}
๐ฏ Interview Questions
Q1: Explain blue-green vs canary deployments.
Q1: Explain blue-green vs canary deployments.
Blue-Green:
- Two identical environments
- Deploy to inactive (green)
- Switch all traffic at once
- Instant rollback (switch back)
- 2x resources during deployment
- Single environment, gradual rollout
- Send small % traffic to new version
- Monitor for errors, then increase
- Progressive validation
- Smaller blast radius
- Need instant rollback
- Database schema changes
- Complete environment validation
- Risk-averse, large user base
- Need gradual validation
- Cost-conscious
Q2: CloudFormation vs CDK - when to use each?
Q2: CloudFormation vs CDK - when to use each?
CloudFormation:
- Direct YAML/JSON templates
- Simpler for basic infrastructure
- No additional tooling needed
- Better for pure declarative IaC
- StackSets for multi-account
- Higher-level abstractions
- Full programming language power
- Better for complex, reusable constructs
- Unit testing infrastructure
- Compile-time type checking
- Generates CloudFormation
- L1: Direct CloudFormation (CfnXxx)
- L2: Curated with sensible defaults
- L3: Patterns (complete solutions)
Q3: How do you implement GitOps on AWS?
Q3: How do you implement GitOps on AWS?
GitOps principles:For Kubernetes (EKS):
- Git as single source of truth
- Declarative infrastructure
- Automated sync (pull-based)
Copy
Git Push โ CodePipeline โ
CodeBuild (synth CDK) โ
CloudFormation deploy
- ArgoCD or Flux for GitOps
- CodePipeline triggers image build
- ArgoCD detects manifest changes
- Pulls and applies to cluster
- Separate app and infra repos
- Use semantic versioning
- Implement drift detection
Q4: How do you handle secrets in CI/CD pipelines?
Q4: How do you handle secrets in CI/CD pipelines?
Never store in code!Options:Rotation:
- Secrets Manager: Runtime retrieval, rotation
- Parameter Store: Cost-effective, hierarchical
- CodeBuild env vars: Build-time secrets
Copy
# buildspec.yml
env:
secrets-manager:
API_KEY: prod/api-key:API_KEY
parameter-store:
DB_PASSWORD: /app/db/password
- Secrets Manager automatic rotation
- Lambda rotation function
- Applications must handle credential refresh
Q5: Design a multi-account CI/CD strategy.
Q5: Design a multi-account CI/CD strategy.
Account structure:Pipeline flow:
Copy
Management Account
โโโ Shared Services (CI/CD, artifacts)
โโโ Development Account
โโโ Staging Account
โโโ Production Account
- Pipeline in Shared Services account
- Cross-account IAM roles for deployment
- Artifact bucket with cross-account access
- CloudFormation StackSets for multi-account
- Single pipeline, multiple deployment targets
- Promotion through environments
- Separate production approval
- Centralized artifact storage
๐งช Hands-On Lab: Complete CI/CD Pipeline
1
Set Up CodeCommit/GitHub
Create repository with application code
2
Create CodeBuild Project
Build Docker image, run tests, push to ECR
3
Configure CodeDeploy
ECS blue-green deployment with canary
4
Build CodePipeline
Connect source โ build โ deploy stages
5
Add Manual Approval
Require approval before production
6
Configure Rollback
CloudWatch alarms trigger automatic rollback
Next Module
Well-Architected Framework
Review your architecture against AWS best practices