AWS for DevOps — Lambda Basics

2 minute read

9.1 — Lambda Basics

AWS Lambda runs your code without provisioning or managing servers. Upload your code, configure a trigger, and Lambda handles everything — scaling, high availability, and patching.

How Lambda Works

  Event (API call, S3 upload, schedule)
       │
       ▼
  Lambda Service
  ┌──────────────────────────┐
  │  Provisions a container  │
  │  Loads your code         │
  │  Runs the handler        │
  │  Returns response        │
  │  Container stays warm    │ ◀── reused for next invocation
  └──────────────────────────┘
       │
       ▼
  Result (response, logs to CloudWatch)

Creating a Lambda Function

handler.py:

import json

def lambda_handler(event, context):
    """
    event  — the input data (JSON)
    context — runtime info (function name, memory, timeout remaining)
    """
    name = event.get('name', 'World')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'message': f'Hello, {name}!'
        })
    }
# Zip the code
$ zip function.zip handler.py

# Create the function
$ aws lambda create-function \
    --function-name hello-world \
    --runtime python3.12 \
    --handler handler.lambda_handler \
    --role arn:aws:iam::123456789012:role/LambdaExecutionRole \
    --zip-file fileb://function.zip \
    --timeout 30 \
    --memory-size 256
{
    "FunctionName": "hello-world",
    "FunctionArn": "arn:aws:lambda:ap-south-1:123456789012:function:hello-world",
    "Runtime": "python3.12",
    "Handler": "handler.lambda_handler"
}

Invoking a Function

# Synchronous invocation
$ aws lambda invoke \
    --function-name hello-world \
    --payload '{"name": "DevOps Engineer"}' \
    --cli-binary-format raw-in-base64-out \
    output.json

$ cat output.json
{"statusCode": 200, "body": "{\"message\": \"Hello, DevOps Engineer!\"}"}

Lambda Configuration

Setting Default Max Notes
Memory 128 MB 10,240 MB CPU scales proportionally with memory
Timeout 3 seconds 900 seconds (15 min) Function killed if exceeded
Ephemeral storage 512 MB 10,240 MB /tmp directory
Concurrency 1,000 Account limit (request increase) Concurrent executions
Package size — 50 MB (zip), 250 MB (unzipped) Use layers for large dependencies

Environment Variables

$ aws lambda update-function-configuration \
    --function-name hello-world \
    --environment 'Variables={DB_HOST=mydb.abc.rds.amazonaws.com,LOG_LEVEL=info}'

For secrets, use SSM Parameter Store or Secrets Manager with the Lambda Powertools library — never store secrets as plaintext environment variables.

Lambda Layers

Layers let you share code and dependencies across multiple functions:

# Create a layer from a zip (must follow directory structure)
# python/lib/python3.12/site-packages/<your packages>
$ zip -r my-layer.zip python/

$ aws lambda publish-layer-version \
    --layer-name my-shared-libs \
    --compatible-runtimes python3.12 \
    --zip-file fileb://my-layer.zip

# Attach layer to a function
$ aws lambda update-function-configuration \
    --function-name hello-world \
    --layers arn:aws:lambda:ap-south-1:123456789012:layer:my-shared-libs:1

Versions and Aliases

# Publish a version (immutable snapshot)
$ aws lambda publish-version --function-name hello-world
{
    "Version": "1",
    "FunctionArn": "arn:aws:lambda:ap-south-1:123456789012:function:hello-world:1"
}

# Create an alias pointing to version 1
$ aws lambda create-alias \
    --function-name hello-world \
    --name production \
    --function-version 1

# Shift traffic: 90% to v1, 10% to v2 (canary)
$ aws lambda update-alias \
    --function-name hello-world \
    --name production \
    --function-version 2 \
    --routing-config AdditionalVersionWeights={"1"=0.9}

Cold Starts

Aspect Detail
What First invocation spins up a new container (~100ms to 2s)
When After idle period, or when scaling out new instances
Mitigation Provisioned Concurrency, smaller packages, choose fast runtimes
# Provisioned Concurrency — keep N containers warm
$ aws lambda put-provisioned-concurrency-config \
    --function-name hello-world \
    --qualifier production \
    --provisioned-concurrent-executions 5

Common Mistakes

Mistake Why It Hurts Fix
Timeout too short Function killed mid-execution Set timeout based on actual execution time + buffer
Too little memory Slow execution (CPU scales with memory) Increase memory — often cheaper overall
Huge deployment package Slow cold starts Use layers, exclude dev dependencies
No dead letter queue Failed async invocations lost Configure DLQ (SQS or SNS)

Quick Reference

Task Command
Create function aws lambda create-function --function-name NAME --runtime python3.12 --handler handler.lambda_handler --role ROLE --zip-file fileb://code.zip
Invoke aws lambda invoke --function-name NAME --payload '{}' output.json
Update code aws lambda update-function-code --function-name NAME --zip-file fileb://code.zip
Update config aws lambda update-function-configuration --function-name NAME --memory-size 512
View logs aws logs tail /aws/lambda/NAME --follow

Next → API Gateway

Updated: