AWS: Lambda functions  —  an overview, and integration with AWS API Gateway

AWS Lambda functions overview - its features, create and update a function. AWS Lambda and AWS API Gateway integration

AWS: Lambda functions  —  an overview, and integration with AWS API Gateway

AWS Lambda allows running a code without the need to create and manage servers, also known as the serverless approach.

AWS Lambda will determine how much CPU and memory is needed to run a function, and when it’s necessary it will perform autoscaling.

A code to be running is organized in lambda functions and can be triggered with triggers. Results can be checked using CloudWatch Logs.

As a trigger, you can use almost any AWS service such as API Gateway, SQS, Application LoadBalancer, CloudFront, Kinesis, or an external event, for example, a webhook from GitHub.

In this post, we will create a simple AWS Lambda function, will check its control panel, available options, and features, and then will create an AWS API Gateway which will forward HTTP requests to an AWS Lambda function.

AWS Lambda — use cases

In general, Lambda in AWS can do really a lot of things. Such a “silver bullet”, allows us to do things that are not realized by the AWS Console itself.

Example use cases could be:

  • a website: a javascript-based frontend in AWS S3 with Static hosting, the frontend will receive requests via an AWS API Gateway to a database via a Lambda function

  • log analysis: a good example is AWS WAF Security Automations when all incoming HTTP requests are sent to the AWS Kinesis, it will forward them to the Lambda, it will perform some checks, and if needed will block a client’s IP

  • backups automation: AWS SNS can send an event, for example when too much disk space is used in an AWS S3 bucket, to a Lambda function, that will delete some old backups

  • data processing: for example, when a new file is uploaded to an AWS S3, it will generate an event that will trigger a Lambda function that will perform a video file encoding

  • serverless cronjobs: with CloudWatch Events generate an event by a schedule, that will trigger a Lambda function

Components and concepts

Let’s take a short overview of the AWS Lambda main concepts:

Creating a “Hello, World” Lambda function

First, let’s create the simplest Lambda function to see how it’s working and what we have there.

Create a function

Go to the AWS Lambda, and click on the Create function:

For now, let’s use an existing template. Choose the Use a blueprint, find a hello-world-python:

Click on the Configure:

Set a function’s name, for example, example-hello, and leave a default IAM role — it will allow our function to use CloudWatch Logs, and check the code that will be used:

Click on the Create function:

Switch to the Test tab:

Here, we can pass a JSON with data to be processed by our function.

Run it:

Now, let’s go to see what AWS Console suggests to use for Lambda function management.

Monitoring

The first thing is monitoring. Here we can use AWS CloudWatch metrics and logs, calls tracing with AWS X-Ray, Lambda insights, and AWS CodeGuru:

Configuration

General configuration

  • memory settings: a maximum RAM allowed to be used when running a function. Also, depending on the memory settings, Lambda will provide a CPU limit: for every 1769 MB, one vCPU will be. See Configuring function memory (console).

  • execution timeouts: maximum can be set to 900 seconds, after that, a function execution will be stopped. Remember, that this will affect costs. See Timeout.

  • IAM role: includes IAM policies with permissions to AWS resources

Triggers

Well, triggers that will trigger our function.

Can be almost any AWS service:

For example, we can create a trigger from an AWS Application LoadBalancer that will accept connections to a specific URI and will forward it to a Lambda function:

Permissions

Here, you can view and adjust an IAM role and policies that will configure a function’s permissions:

Destinations

Where to send a function’s execution results.

For example, can be an AWS SNS topic that will forward to Opsgenie which will send a message to a Slack channel:

Environment variables

Variables that can be used in our function. Sensitive data can be encrypted with AWS Key Management Service (KMS):

VPC

A function can be placed to a dedicated AWS Virtual Private Cloud to limit its network access:

Monitoring and operations tools

Monitoring settings, where you can enable or disable additional services such as AWS X-Ray, CloudWatch Lambda Insights, and Amazon CodeGuru Profiler:

In the Extentions, you can choose from a list of already existing solutions or create your own:

Concurrency

A maximum number of a function’s instances that can be run simultaneously. See Managing concurrency for a Lambda function.

Can be one of two types:

  • reserved concurrency: reserve a number from the generally available for the whole account (1000 by default) and is applied to the whole function including all its versions and aliases

  • provisioned concurrency: will prepare an already initialized runtime environment so during scaling your function will not have to wait for it, applies to a specific version or an alias

Asynchronous invocation

Settings for the event queue — lifetime, number of retries in case of errors, error notifications, etc.

See Asynchronous invocation:

See also Synchronous invocation and Asynchronous invocation.

Database proxies

An Amazon RDS Proxy configuration to be used with your function. RDS Proxy used to decrease the number of connections to a database server:

File system

You can mount an AWS Elastic File System directory inside your function:

Aliases

An alias is a kind of pointer to a specific version of your function’s code that can be used in its ARN later.

Also, you can have a couple of aliases and distribute requests between them. See Lambda function aliases:

Versions

AWS Lambda allows using a code and part of settings versioning. Can be useful when testing a new code on a Dev environment, for example by creating a dedicated alias:

AWS Lambda, and AWS API Gateway — an integration example

So, we’ve checked what AWS Lambda is and what it has in its settings.

Now, let’s create an AWS API Gateway that will forward requests to an AWS Lambda function.

API Gateway will accept requests to the /test URI and will use its event to send them to our Lambda.

Create a Lambda function

At this time, choose Author from scratch, in the Runtime use Python:

Leave the default code:

Here, the lambda_handler() is a default function to be called when a function is called. It accepts two arguments:

  1. event: an API Gateway event, see Using AWS Lambda with other services

  2. context: allowed methods and parameters to run a function, see AWS Lambda context object in Python

Create an AWS API Gateway

Create a new gateway, and set its type to the HTTP API:

Add an integration:

Choose Lambda, an AWS Region, and a function to be called:

Set the URI as /test:

Leave the default stage:

In less than a minute your Gateway is ready. Copy its URL:

And try with the curl:

$ curl [https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test](https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test)
“Hello from Lambda!”

To check the full content of the event, print it with the json.dumps():

import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps(event)
    }

After making code changes, click Deploy:

Try it:

$ curl [https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test](https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test)
{“version”: “2.0”, “routeKey”: “ANY /test”, “rawPath”: “/test”, “rawQueryString”: “”, “headers”: {“accept”: “*/*”, “content-length”: “0”, “host”: “fwu399qo70.execute-api.us-east-2.amazonaws.com”, “user-agent”: “curl/7.78.0”, “x-amzn-trace-id”: “Root=1–611bbaa4–3cb7c28e4e3181dd647f1030”, “x-forwarded-for”: “194. ***.***.29”, “x-forwarded-port”: “443”, “x-forwarded-proto”: “https”}, “requestContext”: {“accountId”: “534 ***385”, “apiId”: “fwu399qo70”, “domainName”: “fwu399qo70.execute-api.us-east-2.amazonaws.com”, “domainPrefix”: “fwu399qo70”, “http”: {“method”: “GET”, “path”: “/test”, “protocol”: “HTTP/1.1”, “sourceIp”: “194.***.***.29”, “userAgent”: “curl/7.78.0”}, “requestId”: “ENoZriIrCYcEPWg=”, “routeKey”: “ANY /test”, “stage”: “$default”, “time”: “17/Aug/2021:13:33:24 +0000”, “timeEpoch”: 1629207204179}, “isBase64Encoded”: false}

Now, let’s see how we can use environment variables in the function.

Add a new one:

And print its value with the os.getenv():

import os
import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': os.getenv('Env')
    }

Check it:

$ curl [https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test](https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test)
test

Also, you can change the default handler.

Rename the lambda_handler to the main_handler:

import os
import json

def main_handler(event, context):
    return {
        'statusCode': 200,
        'body': os.getenv('Env')
    }

If you’ll try to access the function now, you’ll get the Internal Server Error :

$ curl [https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test](https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test)
{“message”:”Internal Server Error”}

Scroll down to the Runtime settings:

And change the Handler:

Run it again:

$ curl [https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test](https://fwu399qo70.execute-api.us-east-2.amazonaws.com/test)
test

Done.

Originally published at RTFM: Linux, DevOps, and system administration.