CertNote/ Commute Study Notes
Roadmap
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
  • Week 1
    • 1.DevOps as an Operating Model: The Five Axes of CALMS and the Truth DORA Proved Through Measurement
    • 2.Well-Architected Framework: Rereading It Through the Six Lenses of DevOps
    • 3.The AWS DevOps Tool Map: The Code* Series and the Real Picture Beyond It
    • 4.Multi-Account Strategy: The Real Picture of Organizations, Control Tower, and IAM Identity Center
    • 5.Week 1 Wrap-Up: Cementing the DevOps Thinking Frame with Scenarios
  • Week 2
  • Week 3
  • Week 4
    • 1.In-place vs Blue/Green, AppSpec: The Physics of Deployment Strategies
    • 2.EC2/On-Prem Deployment + Auto Scaling Integration: The Intersection of Instance Lifecycle and Deployment
    • 3.Lambda Deployment: Linear/Canary/AllAtOnce and the Math of Aliases
    • 4.ECS Blue/Green + CodeDeploy Traffic Shift: The Logic of Two Target Groups
    • 5.Week 4 Review: Integrated Scenarios in CodeDeploy Deployment Strategies
  • Week 5
  • Week 6
  • Week 7
  • Week 8
  • Week 9
  • Week 10
  • Week 11
  • Week 12
  • Week 13
  • Week 14
  • Week 15
  • Week 16
Linux Master 2 · 2급KAIT Linux Master - Level 2
SCS-C03 · SpecialtySecurity - Specialty
Linux Master 1 · 1급KAIT Linux Master - Level 1
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
SQLD · 개발자SQL Developer (SQLD)

© CertNote · 주간랩스

  • About
  • Changelog
  • Contact
  • Terms
  • Privacy
← DOP-C02/Week 4/Day 3

Based on the DOP-C02 exam guide·Report an error

DOP-C02· ProWeek 4 · Day 3~26 min read

Day 3 - Lambda Deployment: Linear/Canary/AllAtOnce and the Math of Aliases

Lambda deployment has no instances. There's no concept of "spinning up a new server"; instead, there are versions of function code and Aliases that point to those versions. Blue/Green's "traffic shift" is implemented here as a change in Alias weighted routing.

This simplicity is its strength. Rollback is just reversing the Alias weight to the previous version — completed in seconds. There's no need to terminate new servers or reconfigure load balancers. But behind this simplicity lies a mathematical understanding of "exactly how much traffic goes to which version." That's the difference between Canary and Linear, and it's the most frequently confused topic on the exam.

Today we cover the complete Lambda deployment picture — Version/Alias relationships, Deployment Configuration math, Pre/Post Hook design, SAM integration, and Provisioned Concurrency cost models.

💡 Day 3's core framework: Lambda deployment strategy choice is a function of two variables — (1) how long it takes to detect failure, (2) the scope of impact if failure occurs. Fast detection → Canary; need gradual load observation → Linear. With this judgment framework, exam answers become clear.


Lambda Deployment Complete Architecture

[sam deploy / aws lambda update-function-code]
        │
        ▼
[Publish new Lambda Version (publish-version)]
   → Immutable snapshot (code + config + env vars fixed)
        │
        ▼
[Update Alias (update-alias)]
   → routing-config: Primary 90% + Secondary(new) 10%
        │
        ▼
[CodeDeploy Deployment Group monitors]
   → Auto-adjust weights per Canary/Linear schedule
   → Execute Pre/Post Hook Lambda
   → Monitor CloudWatch Alarms
        │
   ┌────┴────┐
   │         │
Success    Alarm triggered
   │         │
100% shift  Immediate rollback (Alias → old Version 100%)

🔍 Going deeper: Lambda Version is an immutable snapshot. After publish-version, code, runtime, environment variables, memory, and timeout are all fixed. This immutability guarantees that "other changes don't pollute the deployment." Conversely, $LATEST is a mutable pointer always pointing to the latest state, so if someone changes code during deployment, deployment results vary. Canary deployment must only use Version, never $LATEST.


Lambda Version and Alias Relationship

# 1. Publish new Version after code change
aws lambda publish-version \
  --function-name MyFn \
  --description "v2.1.0 - fixed checkout bug"
# → Version 6 created (immutable snapshot)
 
# 2. Check current Alias (currently Version 5: 100%)
aws lambda get-alias --function-name MyFn --name live
 
# 3. Start Canary (10% to Version 6)
aws lambda update-alias \
  --function-name MyFn \
  --name live \
  --function-version 5 \
  --routing-config AdditionalVersionWeights='{"6": 0.1}'
# Alias "live" → Version 5: 90%, Version 6: 10%
 
# 4. Full switch
aws lambda update-alias \
  --function-name MyFn \
  --name live \
  --function-version 6
  # No routing-config → Version 6: 100%

Core constraints:

  • Only one Version can be added via routing-config per Alias
  • Primary(function-version) + Secondary(routing-config) = maximum 2 Versions
  • "Simultaneous A/B/C test with three versions" is not possible with single Alias
  • $LATEST cannot be used in routing-config (mutable pointer)

Alias ARN structure:

arn:aws:lambda:ap-northeast-2:123456789:function:MyFn:live
                                                        ^^^^
                                                        Alias name

Callers only need to know the Alias ARN. Version switching happens transparently.

💡 Related theory: Lambda Alias weighted routing is stochastic branching. Each invocation independently generates a random number and selects the Version based on weights. With 10% Canary, on average 10% goes to the new version, but exactly 100 out of 1000 invocations isn't guaranteed. It's statistically 10%. This is why the answer to "exactly 10% of users affected during Canary 10% period?" is "no, statistically 10%." Session stickiness is not built-in by default.

⚠️ Pitfall: $LATEST cannot be used in routing-config on Alias. $LATEST is a mutable pointer always pointing to the latest code, different from Version which is an immutable snapshot. Canary deployment must create immutable Versions with publish-version first. If you see "$LATEST for Canary deployment" on the exam, it's always wrong.


Deployment Configuration Math: Canary vs Linear

Traffic distribution by time:

Config0 min1 min2 min5 min10 min20 minFull switch time
LambdaAllAtOnce100%—————0 min
LambdaCanary10Percent5Minutes10%10%10%100%——After 5 min
LambdaCanary10Percent30Minutes10%10%10%10%10%10%After 30 min
LambdaLinear10PercentEvery1Minute10%20%30%50%100%—10 min
LambdaLinear10PercentEvery10Minutes10%10%10%10%20%30%100 min

Canary logic: Only 2 phases. Observe a small percentage (10%) for specified time, if no issues, switch all remaining (90%) at once. Suitable for "fast go/no-go decision."

Linear logic: N phases. Increment evenly to reach 100%. Suitable for "observe gradual load increase, validate at each step."

Canary10Percent5Minutes:          Linear10PercentEvery1Minute:
                                  
100% │         ████               100% │          █
     │         █                       │         ██
 10% │ ████████                    50% │        ███
     │                                 │    ██████
     └─────────────────────            └────────────────────
     0     5 min                      0   5 min  10 min
     
     [2 phases: observe then switch]   [10 phases: even increment]

Custom Deployment Configuration:

aws deploy create-deployment-config \
  --deployment-config-name MyCanary5Percent10Min \
  --compute-platform Lambda \
  --traffic-routing-config \
    "type=TimeBasedCanary,timeBasedCanary={canaryPercentage=5,canaryInterval=10}"
 
# Linear Custom:
aws deploy create-deployment-config \
  --deployment-config-name MyLinear20Percent5Min \
  --compute-platform Lambda \
  --traffic-routing-config \
    "type=TimeBasedLinear,timeBasedLinear={linearPercentage=20,linearInterval=5}"

🔍 Going deeper: The choice between Canary and Linear is a Risk Tolerance vs Validation Speed trade-off. For a financial transaction function, you want to validate sufficiently over Canary 10% 30 minutes — observe small traffic for long. For a static content transformation function, Linear 10%/1min to complete in 10 minutes is sufficient. Consider both "how long it takes to detect failure" and "scope of impact if failure occurs." For functions where failure appears immediately (synchronous API), Canary is more fitting; for functions where failure accumulates (batch processing), Linear is better.

📚 Case study: In 2021, Stripe Engineering adopted Canary10Percent30Minutes for payment processing Lambda. During 30 minutes observation, 10% of actual payment transactions get processed by the new version. CloudWatch monitors PaymentErrors custom metric during this period, auto-rollback if threshold exceeded. After launch, 4 auto-rollbacks occurred, all automatically recovered within 30 minutes. Given the high cost of payment system failures, the 30-minute observation window was justified.


Pre/Post Traffic Hook: Automatic Validation Gate

Hook placement:

[Before traffic shift starts]
    BeforeAllowTraffic (= PreTraffic Hook)
        → Smoke test directly on new Version
        → If failed, rollback without traffic shift
[Traffic shift]
[After traffic shift completes]
    AfterAllowTraffic (= PostTraffic Hook)
        → Validate with real traffic
        → If failed, rollback to previous Version

Hook Lambda implementation (BeforeAllowTraffic):

import boto3, json, os
 
deploy = boto3.client('codedeploy')
fn_client = boto3.client('lambda')
 
def handler(event, context):
    """BeforeAllowTraffic Hook: smoke test new version before traffic shift"""
    deployment_id = event['DeploymentId']
    hook_id = event['LifecycleEventHookExecutionId']
    target_fn = event.get('FunctionName', os.environ.get('TARGET_FUNCTION'))
    target_ver = event.get('TargetVersion')
 
    try:
        # Invoke new Version directly (via Version ARN, not Alias)
        resp = fn_client.invoke(
            FunctionName=f'{target_fn}:{target_ver}',
            InvocationType='RequestResponse',
            Payload=json.dumps({'action': 'smoke-test'})
        )
        payload = json.loads(resp['Payload'].read())
        
        ok = (resp['StatusCode'] == 200 and 
              'FunctionError' not in resp and
              payload.get('status') == 'ok')
        
        status = 'Succeeded' if ok else 'Failed'
 
    except Exception as e:
        print(f"Hook error: {e}")
        status = 'Failed'
 
    # Report result — without this API call, deployment fails on Timeout
    deploy.put_lifecycle_event_hook_execution_status(
        deploymentId=deployment_id,
        lifecycleEventHookExecutionId=hook_id,
        status=status
    )
    return {'status': status}

IAM permissions the Hook Lambda must have:

{
  "Effect": "Allow",
  "Action": [
    "codedeploy:PutLifecycleEventHookExecutionStatus",
    "lambda:InvokeFunction"
  ],
  "Resource": "*"
}

Without PutLifecycleEventHookExecutionStatus, the Hook cannot report its result to CodeDeploy. CodeDeploy treats the Hook as unresponsive and deployment fails on Timeout (default 3600 seconds).

AfterAllowTraffic Hook pattern:

def handler(event, context):
    """AfterAllowTraffic: validate after real traffic processing"""
    deployment_id = event['DeploymentId']
    hook_id = event['LifecycleEventHookExecutionId']
    
    # Query real error metrics from CloudWatch
    cw = boto3.client('cloudwatch')
    resp = cw.get_metric_statistics(
        Namespace='AWS/Lambda',
        MetricName='Errors',
        Dimensions=[
            {'Name': 'FunctionName', 'Value': os.environ['TARGET_FN']},
            {'Name': 'Resource', 'Value': f"{os.environ['TARGET_FN']}:live"}
        ],
        StartTime=datetime.utcnow() - timedelta(minutes=5),
        EndTime=datetime.utcnow(),
        Period=300,
        Statistics=['Sum']
    )
    
    error_count = sum(d['Sum'] for d in resp['Datapoints'])
    status = 'Succeeded' if error_count < 10 else 'Failed'
    
    boto3.client('codedeploy').put_lifecycle_event_hook_execution_status(
        deploymentId=deployment_id,
        lifecycleEventHookExecutionId=hook_id,
        status=status
    )

⚠️ Pitfall: The Hook Lambda's execution result (success/failure) and the result reported via PutLifecycleEventHookExecutionStatus are separate. Even if Hook Lambda terminates normally (exit 0), if PutLifecycleEventHookExecutionStatus is not called, CodeDeploy doesn't know the Hook result. You must report Succeeded or Failed via API call. Hook Lambda execution timeout (15 min) is shorter than CodeDeploy Hook Timeout (3600 sec), so complete reporting before Lambda timeout.

💡 Related theory: Pre/Post Hook is the Deployment Gate pattern. "If the automated quality gate doesn't pass, don't proceed to the next step." This corresponds to "validation automation" in CALMS's Automation axis. Instead of manual post-deployment verification, the Hook validates automatically and auto-rolls back on failure. This pattern directly reduces DORA's Change Failure Rate.


SAM/CDK Integration: Automation with AutoPublishAlias

SAM template.yaml:

Transform: AWS::Serverless-2016-10-31
 
Resources:
  CheckoutFn:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./src/checkout/
      Handler: app.handler
      Runtime: python3.11
      Architectures: [arm64]
      Tracing: Active                    # Enable X-Ray automatically
      AutoPublishAlias: live             # Auto-publish Version + create Alias per deployment
      DeploymentPreference:
        Type: Canary10Percent5Minutes
        Hooks:
          PreTraffic: !Ref PreTrafficCheck
          PostTraffic: !Ref PostTrafficCheck
        Alarms:
          - !Ref ErrorRateAlarm
          - !Ref P99LatencyAlarm
 
  PreTrafficCheck:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./src/hooks/
      Handler: pre.handler
      Policies:
        - Statement:
            - Effect: Allow
              Action:
                - codedeploy:PutLifecycleEventHookExecutionStatus
                - lambda:InvokeFunction
              Resource: '*'
 
  ErrorRateAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: CheckoutFn-ErrorRate
      Namespace: AWS/Lambda
      MetricName: Errors
      Dimensions:
        - Name: FunctionName
          Value: !Ref CheckoutFn
        - Name: Resource
          Value: !Sub '${CheckoutFn}:live'   # Alias-level metric
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 2
      Threshold: 5
      ComparisonOperator: GreaterThanThreshold
      TreatMissingData: notBreaching

What AutoPublishAlias: live does (in order):

  1. When sam deploy runs, auto-publish new Lambda Version
  2. Update Alias "live" to new Version (adjust weights via routing-config)
  3. If DeploymentPreference present, auto-create CodeDeploy Application + Deployment Group
  4. Auto-execute Canary/Linear deployment
  5. Auto-rollback if Alarms trigger

One line (AutoPublishAlias) automates Version management, Alias management, CodeDeploy integration, and alarm-based rollback.

CDK equivalent:

from aws_cdk import aws_lambda as lambda_
from aws_cdk import aws_codedeploy as codedeploy
from aws_cdk import aws_cloudwatch as cloudwatch
 
fn = lambda_.Function(self, 'CheckoutFn', ...)
alias = lambda_.Alias(self, 'LiveAlias',
    alias_name='live',
    version=fn.current_version
)
deployment_group = codedeploy.LambdaDeploymentGroup(self, 'DG',
    alias=alias,
    deployment_config=codedeploy.LambdaDeploymentConfig.CANARY_10PERCENT_5MINUTES,
    alarms=[error_rate_alarm],
    auto_rollback=codedeploy.AutoRollbackConfig(
        deployment_in_alarm=True,
        stopped_deployment=True
    )
)

📚 Case study: A team previously deployed Lambda by calling $LATEST directly. When deployment errors occurred, 100% switch already happened, taking 10 minutes to recover. After switching to SAM AutoPublishAlias + Canary10Percent5Minutes, when the same error occurred, auto-rollback happened after 5 minutes, affecting only 10% of traffic. The remaining 90% was processed normally by the old version.


Provisioned Concurrency and Deployment: Cost Pitfall

Provisioned Concurrency (PC) pre-warms Lambda execution environments to remove cold starts.

PC cost structure during Canary deployment:

# Pre-configure PC on new Version 6
aws lambda put-provisioned-concurrency-config \
  --function-name MyFn \
  --qualifier 6 \
  --provisioned-concurrent-executions 10
 
# Wait for PC to be ready
aws lambda get-provisioned-concurrency-config \
  --function-name MyFn --qualifier 6
# Wait until Status: READY
 
# Then start Alias Canary

PC cost per deployment phase:

PhaseVersion 5 (old)Version 6 (new)Cost
Before Canary startsPC 10NoneNormal
Canary in progressPC 10 (90%)PC 10 warming (10%)~2x
After 100% switchPC removedPC 10 keptNormal
Old Version PC cleanupManual delete (delete-provisioned-concurrency-config)——

After full switch, you must manually delete the old version's PC. It doesn't auto-delete.

# Delete old version PC after switch completes
aws lambda delete-provisioned-concurrency-config \
  --function-name MyFn \
  --qualifier 5

💡 Related theory: The cost model of Provisioned Concurrency + Canary deployment is the same logic as EC2 Blue/Green's "temporary 2× instance cost." While two versions are active simultaneously, both incur costs. The difference is EC2 is instance-based, Lambda PC is "warmed execution environment" based. Longer Canary period means more accumulated additional cost. Canary30Minutes means 30 min of additional PC cost; Canary5Minutes means only 5 min.

⚠️ Pitfall: Old version's Provisioned Concurrency doesn't auto-delete after deployment completes. You must manually execute delete-provisioned-concurrency-config, or if Lambda Application Auto Scaling manages PC, update the schedule. Forgetting this means unused old version PC keeps getting charged.


CloudWatch Alarm Design: Alias-level Metrics

Lambda metrics aggregate at function-level, specific Version, or Alias level.

# Alias-level Alarm (suitable for Canary deployment monitoring)
aws cloudwatch put-metric-alarm \
  --alarm-name "MyFn-live-ErrorRate" \
  --namespace "AWS/Lambda" \
  --metric-name "Errors" \
  --dimensions "Name=FunctionName,Value=MyFn" "Name=Resource,Value=MyFn:live" \
  --statistic Sum \
  --period 60 \
  --evaluation-periods 2 \
  --threshold 5 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching

Resource=MyFn:live counts only errors from invocations via Alias "live". During Canary 10%, errors from the new version are also included. If errors exceed threshold, alarm triggers → auto-rollback.

Combine multiple conditions with Composite Alarm:

# Combine error rate alarm + P99 latency alarm with OR
aws cloudwatch put-composite-alarm \
  --alarm-name "MyFn-live-Composite" \
  --alarm-rule "ALARM(MyFn-live-ErrorRate) OR ALARM(MyFn-live-P99Latency)"

Connecting Composite Alarm to Deployment Group enables "rollback if either error rate or latency exceeds threshold."

🔍 Going deeper: Lambda metric Dimension design is key to Canary deployment monitoring. If you only specify FunctionName=MyFn, the entire Function's errors are counted. If you specify FunctionName=MyFn, Resource=MyFn:live, only invocations through the Alias are counted. If 5 Alias-level errors occur during Canary 10%, statistically about 1 (10%) are new version-related. Consider this in alarm threshold design — lower Canary percentage means new version errors get diluted in Alias metrics.


Summary: Lambda Deployment Decision Tree

Lambda deployment strategy selection
=====================
Can failure be detected immediately (synchronous API, instant error)?
    ├─ YES + short observation fine → LambdaCanary10Percent5Minutes
    ├─ YES + sufficient observation needed → LambdaCanary10Percent30Minutes
    └─ NO (delayed failure, batch) → LambdaLinear10PercentEvery1Minute
    
    AllAtOnce: dev/test environments only, production forbidden

Traffic too low to have enough samples?
    └─ Supplement with Hook + direct new Version invocation for smoke test

Must have no cold starts (PC configured)?
    └─ Configure PC on new Version before Canary → must manually delete old Version PC after switch

Automating from CodePipeline?
    └─ SAM AutoPublishAlias + DeploymentPreference is optimal combination

📝 Practice Questions

Click a choice to reveal the answer and explanation.

Question 1

What is the mechanism by which traffic is actually shifted in a Lambda canary deployment?

Question 2

In a LambdaCanary10Percent5Minutes deployment, what is the traffic distribution at 3 minutes in?

Question 3

What happens if a PreTrafficHook function exits normally without calling PutLifecycleEventHookExecutionStatus?

Question 4

What does SAM AutoPublishAlias: live handle automatically?

Question 5

What is the cost impact while deploying a Lambda function with provisioned concurrency using Canary 10% over 30 minutes?

Question 6

What is the maximum number of versions that can receive traffic at the same time from one Lambda alias?

Question 7

10 minutes into a canary deployment, a CloudWatch alarm enters the ALARM state. What does CodeDeploy do automatically?

PreviousEC2/On-Prem Deployment + Auto Scaling Integration: The Intersection of Instance Lifecycle and DeploymentWeek 4 · Day 2Next ECS Blue/Green + CodeDeploy Traffic Shift: The Logic of Two Target GroupsWeek 4 · Day 4

Official references

  • DOP-C02 official exam page(opens in a new tab)
  • AWS Lambda documentation(opens in a new tab)
  • AWS CodeDeploy documentation(opens in a new tab)
  • Amazon CloudWatch documentation(opens in a new tab)

On this page

  • Lambda Deployment Complete Architecture
  • Lambda Version and Alias Relationship
  • Deployment Configuration Math: Canary vs Linear
  • Pre/Post Traffic Hook: Automatic Validation Gate
  • SAM/CDK Integration: Automation with AutoPublishAlias
  • Provisioned Concurrency and Deployment: Cost Pitfall
  • CloudWatch Alarm Design: Alias-level Metrics
  • Summary: Lambda Deployment Decision Tree
  • Practice Questions