Skip to content

ql4b/lambda-shell-runtime

Repository files navigation

lambda-shell-runtime

License: MIT Docker AWS Lambda

Turn shell scripts into serverless functions in minutes

Custom AWS Lambda runtime for executing Bash functions as serverless applications. Deploy shell scripts directly to AWS Lambda with full access to common CLI tools like jq, curl, and AWS CLI.

Features

  • 🚀 Zero-config deployment - Just write Bash, deploy to Lambda
  • 📦 Three optimized variants - Choose the right tools for your use case
  • 🔧 Built-in utilities - jq, curl, http-cli, and optional AWS CLI
  • 🏗️ Multi-platform support - ARM64 and x86_64 architectures
  • 🧪 Local testing - Full Lambda Runtime Interface Emulator support
  • 📋 Production ready - Based on official AWS Lambda base images

Quick Start

  1. Create your handler function:
# handler.sh
main () {
    local event="$1"
    echo '{"message": "Hello from Bash Lambda!", "input": '"$event"'}'
}
  1. Create your Dockerfile:
FROM ghcr.io/ql4b/lambda-shell-runtime:tiny
COPY handler.sh .
  1. Deploy to AWS Lambda using container images

Runtime Variants

Choose the variant that matches your requirements:

Variant Size Tools Included Best For
tiny ~132MB jq, curl, http-cli HTTP APIs, JSON processing
micro ~221MB tiny + awscurl AWS API calls without full CLI
full ~417MB tiny + AWS CLI Complete AWS operations

Available Images

# From GitHub Container Registry
ghcr.io/ql4b/lambda-shell-runtime:tiny
ghcr.io/ql4b/lambda-shell-runtime:micro  
ghcr.io/ql4b/lambda-shell-runtime:full

# From AWS Public ECR
public.ecr.aws/j5r7n1v7/lambda-shell-runtime:tiny
public.ecr.aws/j5r7n1v7/lambda-shell-runtime:micro
public.ecr.aws/j5r7n1v7/lambda-shell-runtime:full

Examples

HTTP API with JSON Processing

# handler.sh
api_handler() {
    local event="$1"
    local name=$(echo "$event" | jq -r '.queryStringParameters.name // "World"')
    
    echo '{
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": '{"greeting": "Hello, '"$name"'!"}'
    }'
}

AWS API Integration

# handler.sh (using micro variant)
list_buckets() {
    local buckets=$(awscurl --service s3 https://s3.amazonaws.com/ | jq '.ListAllMyBucketsResult.Buckets')
    echo '{"buckets": '"$buckets"'}'
}

File Processing with AWS CLI

# handler.sh (using full variant)
process_s3_file() {
    local event="$1"
    local bucket=$(echo "$event" | jq -r '.Records[0].s3.bucket.name')
    local key=$(echo "$event" | jq -r '.Records[0].s3.object.key')
    
    aws s3 cp "s3://$bucket/$key" /tmp/input.json
    local result=$(jq '.data | length' /tmp/input.json)
    
    echo '{"processed": true, "count": '"$result"'}'
}

Function Handler Format

Your handler functions receive the Lambda event as the first argument:

# handler.sh
my_function() {
    local event="$1"          # Lambda event JSON
    local context="$2"        # Lambda context (optional)
    
    # Process the event
    local result=$(echo "$event" | jq '.key')
    
    # Return JSON response
    echo '{"result": '"$result"'}'
}

Handler naming: Set your Lambda handler to handler.my_function (filename.function_name)

Deployment

Using AWS CLI

# Build and push your image
docker build -t my-lambda .
docker tag my-lambda:latest 123456789012.dkr.ecr.region.amazonaws.com/my-lambda:latest
docker push 123456789012.dkr.ecr.region.amazonaws.com/my-lambda:latest

# Create/update Lambda function
aws lambda create-function \
  --function-name my-bash-function \
  --code ImageUri=123456789012.dkr.ecr.region.amazonaws.com/my-lambda:latest \
  --role arn:aws:iam::123456789012:role/lambda-execution-role \
  --package-type Image \
  --architectures arm64 \
  --timeout 30

Using Terraform

resource "aws_lambda_function" "bash_function" {
  function_name = "my-bash-function"
  role         = aws_iam_role.lambda_role.arn
  package_type = "Image"
  image_uri    = "123456789012.dkr.ecr.region.amazonaws.com/my-lambda:latest"
  timeout      = 30
}

Local Testing

Using Lambda Runtime Interface Emulator

https://github.com/aws/aws-lambda-runtime-interface-emulator/

The emulator is already available on the image, you just need to override the entrypoint to run test your lambda locally

# Run your function locally
docker run --rm -p 9000:8080 \
  --env _HANDLER="handler.hello" \
  --entrypoint /aws-lambda/aws-lambda-rie \
  my-lambda:latest /var/runtime/bootstrap

# Test your function
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" \
  -d '{"name": "World"}'

Building from Source

# Clone the repository
git clone https://github.com/ql4b/lambda-shell-runtime.git
cd lambda-shell-runtime

# Build specific variant
./build --platform linux/arm64 --tag my-runtime --load tiny

# Build and push to registry
./build --platform linux/arm64 --tag my-registry/lambda-shell --push micro

Build Options

  • --platform: Target platform (default: linux/arm64)
  • --tag: Image tag prefix
  • --load: Load image locally (default)
  • --push: Push to registry
  • --secret: Inject build secrets (e.g., GitHub token)

Performance & Limitations

  • Cold start: ~100-300ms depending on variant
  • Memory usage: 64MB minimum recommended
  • Timeout: Standard Lambda limits apply (15 minutes max)
  • Package size: Varies by variant (132MB-417MB)
  • Concurrent executions: Standard Lambda limits

Size Comparison with Official AWS Lambda Runtimes

Runtime Size Notes
AWS Python 3.12 534MB Official Python runtime
lambda-shell-runtime:full 417MB 22% smaller with complete AWS CLI
AWS Node.js 20 410MB Official Node.js runtime
lambda-shell-runtime:micro 221MB 46% smaller with AWS API access
lambda-shell-runtime:tiny 132MB 75% smaller with essential tools
AWS provided 128MB Bare custom runtime base

The shell runtime is highly competitive with official runtimes while providing the simplicity and power of Bash scripting.

Troubleshooting

Common Issues

Function not found:

# Ensure your function is defined and you override 
# the CMD hander.my_function

Permission errors:

# Ensure Lambda execution role has required permissions
# For AWS API calls, add appropriate IAM policies

Timeout issues:

# Increase Lambda timeout setting
# Optimize shell script performance

Updating http-cli Version

The runtime includes http-cli for simplified HTTP operations. To update to a newer version:

  1. Update version in all configuration files:

    • .github/workflows/build-and-release.yml (2 locations)
    • .github/workflows/build-base.yml
    • .github/workflows/build-installers.yml
    • Dockerfile (ARG HTTP_CLI_VERSION)
    • build-enhanced script (default value)
  2. Trigger a new build:

    # Push changes to trigger GitHub Actions
    git add .
    git commit -m "Update http-cli to vX.X.X"
    git push origin develop
  3. Or build locally:

    HTTP_CLI_VERSION=v1.2.0 ./build-enhanced --load tiny

Contributing

We welcome contributions! Please see our contributing guidelines for details.

Development Setup

git clone https://github.com/ql4b/lambda-shell-runtime.git
cd lambda-shell-runtime
./build --load tiny  # Build and test locally

Project Structure

lambda-shell-runtime/
├── runtime/          # Custom bootstrap and runtime logic
├── task/            # Helper functions and example handlers  
├── test/            # Test functions and runners
├── scripts/         # Build and publishing utilities
├── Dockerfile       # Multi-stage build definitions
└── build           # Build script for all variants

License

MIT License - see LICENSE file for details.

About

Custom AWS Lambda runtime for shell/bash functions.

Topics

Resources

License

Stars

Watchers

Forks

Packages