AWS

Lambda Overview

Andrii Chykharivskyi

What is AWS Lambda?

Lambda is a compute service that lets you run code without provisioning or managing servers.

What is serverless?

Serverless is a cloud-native development model that allows developers to build and run applications without having to manage servers.

Advantages of Serverless architecture

only the execution time is paid

no need to manage infrastructure manually

don’t need to worry about infrastructure security

focus on writing codes

effortless efficiency

reduced software complexity

infinitely scalable

Limitations of Serverless architecture

response latency due to function "cold start"

long-running workloads will be more costly

you will be dependent on your providers

debugging is more difficult

Why AWS Lambda?

- Excellent and easy integration with other AWS services

- Free Tier: 1 million requests per month, 400.000 GB-seconds of compute time per month

- $0.20 per 1 million requests thereafter, or $0.0000002 per request

- supports  Nodejs, Python, Ruby, Java8, C#, Power shell, and more(you can use any language)

What we knew before using:

Why AWS Lambda?

- Converting JSON to Metro2 (Ruby) 

- Image resizing (Python + ImageMagick tool)

- Converting HTML to PDF (Python + Wkhtmltopdf tool)

What tasks we solved with the help of Lambda:

- Converting XLSX to PDF (Python + Libreoffice tool)

- PDF editing (Python)

- PDF page removing (Python)

Why AWS Lambda?

How much did we pay for using Lambda for production?

For 2 years of using AWS Lambda  tenantcloud.com only now approached the excess of the free limit.

Why AWS Lambda?

What did it give us?

We no longer need to keep in the main project:

- Wkhtmltopdf tool for html-to-pdf converting

- Libreoffice xlsx-to-pdf converting

- Ghostscript for pdf editing

- Ghostscript for pdf editing

- Ghostscript for pdf editing

Why AWS Lambda?

Security case from our project

We had a problem with Wkhtmltopdf tool. Compromising environment information was written to the content of the file, which was then given to the user.

After we put this functionality on the lambda, we are 100% sure that no information from the environment of the dashboard project can get into the file because in an isolated Lambda environment, this information does not exist physically.

Before using

Code providing options:

- Author from scratch(inline editing or .zip file uploading or S3 file location)

- Use a blueprint (examples, that allowing inline code editing)

- Browse serverless app repository (applications from AWS Serverless Application Repository)

- Container image (image from Amazon ACR)

Before using

Simple one-file functions or functions from .zip

Advantages:

Disadvantages:

- Easy for begginers

- Easy to deploy (just upload a file)

- Hard maintaining

- Impossibility to test the function without the Internet

- Impossible to use packages without installing them only in Lambda environment

- 250MB size limit

Before using

Container images

- Deployment package is immutable across your different environments, including desktop, the CI/CD process, and the Lambda execution environment

Before using

Container images

- Container images up to 10 GB are supported, as opposite to the previous hard limit of 250 MB of unzipped files.

Console editor

3 MB

Direct .zip upload

50 MB

250 MB

Unzipped, including layers

10 GB

Image

Before using

Container images

- Using custom OS and custom runtime versions to match requirements and standard practices in a given company.

- Reusing existing base images to bring reliable and battle-tested implementations from the broad community or domain-specific scenarios.

- Applying centralized container image building and packaging governance and security requirements to AWS Lambda deployments. This provides Enterprise customers with a higher level of control.

Before using

Container images

AWS Lambda supports any image that conforms to one of next image manifest formats:

  • Docker image V2, schema 2 (used with Docker version 1.10 and newer)

  • Open Container Initiative (OCI) Specifications (v1.0.0 and up)

Before using

Container images

FROM public.ecr.aws/lambda/python:3.8

# Copy function code
COPY src/app.py ${LAMBDA_TASK_ROOT}

# Install the function's dependencies using file requirements.txt
# from your project folder.
COPY requirements.txt  .
RUN  pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}"
ADD . .

# Set the CMD to your handler (could also be done as a parameter override outside
# of the Dockerfile)
CMD [ "app.handler" ]

Dockerfile example for Python Lambda function

Before using

Container images. Entrypoint

You can override your function entrypoint.

This mean, that Lambda will search function handler inside app.py file

Before using

Container images. Files

  • The container image must be able to run on a read-only file system. Your function code can access a writable /tmp directory with 512 MB of storage.

Before using

Container images. Files

  • The container image must be able to run on a read-only file system. Your function code can access a writable /tmp directory with 512 MB of storage.

One time I forgot and instead of '/tmp' I just use 'tmp'. It cost me half an hour of error debugging.

Creating

What we need to create simple function?

  • Register AWS account and add virtual credit card to unblock most AWS Services
  • In top search input type "Lambda" and open service

Creating

What we need to create simple function?

  • Click "Create function"

Creating

What we need to create simple function?

Creating

What we need to create simple function?

def lambda_handler(event, context):
    lower = 2
    upper = 50000
    print("Prime numbers between", lower, "and", upper)
    
    for num in range(lower, upper + 1):
        prime = True
        for i in range(2, num):
            if (num % i == 0):
                prime = False
                break
        if prime:
            print(num)
    return {
    	'statusCode': 200,
        'body': json.dumps("Function executed successfully")
    }

Paste the following Python code inside our editor

Creating

What we need to create simple function?

Deploy our function

Creating

Configuration. Basic settings

Creating

Configuration. Basic settings

  • If a function logic is CPU intensive, add memory to reduce the execution time. It not only saves cost but also reduces timeout errors.
  • Add memory to bring execution time below the nearest 100 – AWS charges for Lambda usage in increments of 100ms. For example, if average execution is 110ms, increase memory to bring it below 100ms, or you’ll be charged for 200ms.

Creating

Configuration. Allocated memory  explanation

def lambda_handler(event, context):
    lower = 2
    upper = 50000
    print("Prime numbers between", lower, "and", upper)
    
    for num in range(lower, upper + 1):
        prime = True
        for i in range(2, num):
            if (num % i == 0):
                prime = False
                break
        if prime:
            print (num)
    return {
    	'statusCode': 200,
        'body': json.dumps("Function executed successfully")
    }

Function, that print prime numbers

Creating

Configuration. Allocated memory  explanation

Allocated Memory (MB) Max memory used (MB) Execution time (secs)
128 48 139
256 48 68.7
512 48 33.9
1024 48 17.7

Creating

Configuration. Allocated memory  explanation

Allocated Memory (MB) Execution time (ms) Cost in USD per month
128 139000 28.98
256 68700 28.65
512 33900 28.28
1024 17700 29.53

Sum for 100000 months executions (without free tier)

Creating

Configuration. Permissions

A Lambda function's execution role is an AWS Identity and Access Management (IAM) role that grants the function permission to access AWS services and resources.

Creating

Configuration. Environment variables

Using WEB interface:

Creating

Configuration. Environment variables

Using API:

aws lambda update-function-configuration --function-name my-function \
    --environment "Variables={BUCKET=local,GREETING=hello}"

Creating

Configuration. Environment variables

If you want to see all reserved environment variables keys, please follow the link.

We are interested in the keys that were important for our cases:

AWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY

Creating

Configuration. Environment variables

Firstly we use our custom access keys and code looks like this:

import boto3
import os

# Custom keys
bucket_name = os.getenv('AWS_S3_BUCKET_NAME')
bucket_region_name = os.getenv('AWS_S3_BUCKET_REGION_NAME')
bucket_access_key_id = os.getenv('AWS_S3_BUCKET_ACCESS_KEY_ID')
bucket_secret_access_key = os.getenv('AWS_S3_BUCKET_SECRET_ACCESS_KEY')

bucket_endpoint_url = os.getenv('AWS_S3_ENDPOINT_URL')

def get_client():
    return boto3.resource(
        endpoint_url= bucket_endpoint_url if bucket_endpoint_url else None,
        service_name='s3',
        region_name=bucket_region_name,
        aws_access_key_id=bucket_access_key_id,
        aws_secret_access_key=bucket_secret_access_key
    ).Bucket(bucket_name)
    

Creating

Configuration. Environment variables

Disadvantages of this approach:

  • hard to configure .env variables for production/staging/testlinks
  • variables naming is not standartized

Creating

Configuration. Environment variables

Disadvantages of this approach:

  • hard to configure .env variables for production/staging/testlinks
  • variables naming is not standartized

Advantages of this approach:

Creating

Configuration. Environment variables

Correct approach is using predefined environment keys:

  • AWS_ACCESS_KEY
  • AWS_SECRET_ACCESS_KEY

The access keys obtained from the function's execution role.

import boto3

def get_client():
    return boto3.resource('s3').bucket('BUCKET_NAME')

Invoking

Ways to invoke AWS Lambda function:

  • Lambda console
  • function URL HTTPS endpoint
  • Lambda API
  • AWS SDK
  • AWS Command Line Interface

Invoking

How it works:

Invoking

Invoke handler. Python example

def handler(event, context):
    argument = event['key']

    return {
    	'statusCode': 200,
    	'result': argument * 2,
    	'functionVersion': context.function_version,
    }

As you see we can pass some parameters for every function call

Invoking

Test invoking

Invoking

Test invoking

To be continued...

Andrii Chykharivskyi