How to Run a Docker Container in AWS Lambda: Complete Guide
By Braincuber Team
Published on March 2, 2026
A D2C brand we work with was paying $387/month for a t3.medium EC2 instance running a single Python script that processed returns once a day. The instance sat idle 23 hours and 45 minutes out of every 24. We moved it to Lambda with a Docker container image. Their bill dropped to $1.20/month. That's not a typo. This beginner guide is the complete tutorial for taking any Docker container and running it on AWS Lambda — no servers to manage, no idle charges, just pay-per-invocation. Step by step, from local build to production deployment.
What You'll Learn:
- How to write a Lambda-compatible Dockerfile using AWS base images
- Building, running, and testing your container image locally on port 8080
- Creating an ECR repository and pushing your image via AWS CLI
- Deploying the container image as a Lambda function
- Testing invocations with custom JSON payloads
- When Docker-on-Lambda makes sense vs. ECS Fargate or plain zip packages
- Cleanup steps so you don't get surprise-billed
Why Docker + Lambda (Instead of ECS, EKS, or Plain Zip)
Lambda supports two deployment formats: zip packages (up to 250 MB unzipped) and container images (up to 10 GB). Most people default to zip. But the moment your dependencies exceed 250 MB, or you need system-level libraries that don't exist in the Lambda runtime, Docker is the only option. And it's cheaper than running ECS or EKS for workloads that don't need to be always-on.
Pay Only When It Runs
Lambda bills per invocation + duration + memory. A function that runs once a day for 30 seconds at 512 MB costs fractions of a penny. Compare that to an EC2 instance burning $8.50/month running 24/7 doing nothing 99% of the time.
10 GB Image Limit
Container images on Lambda support up to 10 GB — enough for ML models, heavy Python/R libraries like pandas + scipy + scikit-learn, or custom C/C++ binaries. Zip packages cap at 250 MB unzipped. That's the cutoff where Docker becomes mandatory.
No Server Management
No OS patching, no SSH access to worry about, no security groups to misconfigure. Lambda handles infrastructure, scaling, and compute isolation. Your container runs in a sandboxed environment with no attack surface beyond your function code.
Same Dockerfile Everywhere
Test locally with docker run, deploy to Lambda, or move to ECS later — same image. No vendor lock-in on the container itself. The only Lambda-specific part is the base image (public.ecr.aws/lambda/python:3.12) and the handler entrypoint.
Lambda vs. ECS vs. EKS — When to Use What
Don't overthink this. Here's the decision tree we use with every client.
| Factor | Lambda (Container) | ECS Fargate | EKS |
|---|---|---|---|
| Max runtime | 15 minutes | Unlimited | Unlimited |
| Idle cost | $0 | ~$14/month (Fargate) | ~$73/month (cluster) |
| Image size limit | 10 GB | No limit | No limit |
| Cold start | Yes (1-10 sec) | No (always running) | No |
| Best for | Event-driven, batch jobs, APIs under 15 min | Long-running services, web apps | Multi-service microservices at scale |
The 8-Step Deployment Walkthrough
We're deploying a Python function that takes a name and returns a greeting. Simple — but the exact same process works for ML inference, data processing, PDF generation, or any workload that fits within Lambda's 15-minute timeout.
Write Your Lambda Handler Function
Create lambda_function.py with a lambda_handler(event, context) function. The event parameter receives the JSON payload from each invocation. Return a dict with statusCode and body. For this tutorial, the function extracts a name field from the event and returns "Hello, {name}!". Wrap the logic in a try/except so errors return a 400 instead of crashing the function.
Create a Lambda-Compatible Dockerfile
Use FROM public.ecr.aws/lambda/python:3.12 as your base image. This is the official AWS Lambda Python runtime image — it includes the Lambda Runtime Interface Client that handles invocation requests. Copy your lambda_function.py into ${LAMBDA_TASK_ROOT} (which resolves to /var/task). Set the CMD to lambda_function.lambda_handler. That's it — 3 lines. If you have pip dependencies, add a RUN pip install -r requirements.txt before the COPY.
Build the Docker Image Locally
Run docker build -t lambda-docker:1.0.0 . from your project root. Docker pulls the AWS Lambda base image (~300 MB), copies your function code, and creates the image. Verify it exists with docker images | grep lambda-docker. If you're on an M1/M2 Mac, add --platform linux/amd64 to the build command — Lambda runs on x86_64 by default. Skip this and you'll get a cryptic "exec format error" at runtime.
Run and Test the Container Locally
Run docker run -it --rm -p 8080:8080 lambda-docker:1.0.0. Port 8080 is the Lambda Runtime Interface Emulator port — it simulates the Lambda invocation API locally. Send a test request: curl -X POST http://localhost:8080/2015-03-31/functions/function/invocations -d '{"name":"Janet"}'. You should get {"statusCode":200,"body":"Hello, Janet!"}. Fix any errors here — debugging locally is 10x faster than debugging in AWS CloudWatch.
Create an ECR Repository via AWS CLI
Set your environment variables: AWS_REGION, ACCOUNT_ID (from aws sts get-caller-identity), REPO_NAME=lambda-docker, TAG=1.0.0. Run aws ecr create-repository --repository-name "$REPO_NAME" --region "$AWS_REGION". This creates a private container registry where Lambda will pull your image from. ECR is the only registry Lambda supports for container images — you can't use Docker Hub or GitHub Container Registry directly.
Authenticate, Tag, and Push to ECR
Authenticate Docker to ECR: aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com". Tag your image: docker tag lambda-docker:1.0.0 $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/lambda-docker:1.0.0. Push: docker push that tagged URI. The auth token expires after 12 hours — if you get a "denied" error later, re-run the login command.
Create the Lambda Function from Your Container Image
Go to Lambda > Create function > Container image. Name your function, browse for your ECR repository, select the image you just pushed. Leave architecture as x86_64 (unless you built for ARM). Leave other settings as default. Click Create. Lambda pulls the image from ECR and provisions the execution environment. This takes 30-60 seconds. You can also do this via CLI with aws lambda create-function --package-type Image --code ImageUri=....
Test the Deployment and Clean Up
In the Lambda console, click the Test tab. Create a test event with {"name": "Janet"} as the payload. Run it. You should see {"statusCode":200,"body":"Hello, Janet!"}. If you want HTTP access, add API Gateway as a trigger — Lambda creates a public URL you can call from anywhere. When you're done testing, delete the Lambda function and ECR repository to avoid charges. ECR charges $0.10/GB/month for stored images.
The Dockerfile and Handler Code
Three files. That's the entire project. Copy these and you're deploying in under 10 minutes.
def lambda_handler(event, context):
name = event["name"]
message = f"Hello, {name}!"
try:
return {
"statusCode": 200,
"body": message
}
except Exception as e:
return {
"statusCode": 400,
"body": {"error": str(e)}
}
FROM public.ecr.aws/lambda/python:3.12
COPY lambda_function.py ${LAMBDA_TASK_ROOT}
CMD ["lambda_function.lambda_handler"]
# 1. Set variables
AWS_REGION=us-east-1
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REPO_NAME=lambda-docker
TAG=1.0.0
# 2. Build the image
docker build -t $REPO_NAME:$TAG .
# 3. Test locally
docker run -it --rm -p 8080:8080 $REPO_NAME:$TAG
# 4. Create ECR repo
aws ecr create-repository --repository-name "$REPO_NAME" --region "$AWS_REGION"
# 5. Authenticate to ECR
aws ecr get-login-password --region "$AWS_REGION" \
| docker login --username AWS \
--password-stdin "$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
# 6. Tag and push
docker tag $REPO_NAME:$TAG \
$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPO_NAME:$TAG
docker push $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPO_NAME:$TAG
# 7. Create Lambda function
aws lambda create-function \
--function-name my-docker-lambda \
--package-type Image \
--code ImageUri=$ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPO_NAME:$TAG \
--role arn:aws:iam::$ACCOUNT_ID:role/lambda-execution-role
# 8. Test invocation
aws lambda invoke --function-name my-docker-lambda \
--payload '{"name":"Janet"}' response.json
cat response.json
The M1/M2 Mac Trap
If you're building on an Apple Silicon Mac, you must add --platform linux/amd64 to your docker build command. Otherwise Docker builds an ARM64 image. Lambda defaults to x86_64. You'll push successfully, create the function successfully, then get a cryptic "exec format error" at invocation time. We've seen this burn 2+ hours of debugging.
ECR Auth Tokens Expire After 12 Hours
The aws ecr get-login-password token is valid for 12 hours. If you come back the next day and try to push an updated image, you'll get an "authorization token has expired" or "denied" error. Re-run the login command. We've seen devs waste 45 minutes thinking their IAM permissions are broken when it's just an expired token.
Frequently Asked Questions
Can I use any Docker image with AWS Lambda?
No. The image must implement the Lambda Runtime API. The easiest way is to use an AWS-provided base image (like public.ecr.aws/lambda/python:3.12) which includes the Runtime Interface Client. You can use custom base images, but you must add the Lambda Runtime Interface Client manually.
What is the maximum container image size for Lambda?
10 GB. This is significantly larger than the 250 MB limit for zip-packaged Lambda functions. The 10 GB limit makes Docker images ideal for ML workloads, heavy data processing libraries, or applications with many binary dependencies.
Can I push a Docker image to Docker Hub and use it with Lambda?
No. Lambda only pulls container images from Amazon ECR (Elastic Container Registry) in the same AWS account and region as the function. You must push your image to ECR before creating or updating the Lambda function.
How does cold start affect Docker containers on Lambda?
Container images have longer cold starts than zip packages — typically 1-10 seconds depending on image size. AWS caches image layers in the execution environment, so subsequent invocations are faster. Use Provisioned Concurrency to eliminate cold starts for latency-sensitive functions.
How do I make my Lambda Docker function accessible via HTTP?
Add an API Gateway trigger to your Lambda function. API Gateway creates a public HTTPS endpoint that forwards requests to your Lambda function. You can also use Lambda Function URLs for simpler use cases — these provide a dedicated HTTPS endpoint without API Gateway.
Still Running Idle EC2 Instances for Batch Jobs?
We've migrated 23 always-on EC2 workloads to Lambda containers for D2C brands — cutting monthly compute bills by 87% on average. If your script runs less than 15 minutes and doesn't need to run 24/7, you're burning money on servers. Let us audit your AWS bill and show you exactly what to move.
