This library demonstrates how to use the Swift programming language for AWS Lambda functions.
This demo is based on the newly released (November 2018) Lambda Layers and Lambda Custom Runtime. The former allows to share common code and libraries across multiple Lambda functions. The latter allows you to upload code written in any programming language by providing your code with an API to fetch Lambda events and to communicate success and errors with the Lambda service.
Lambda functions run inside containers on top of Amazon Linux (see re:Invent 2018's Deep Dive into Lambda to learn more about it), so our job is to provide a runtime environment for Swift applications on Amazon Linux. Apple and the community are providing binaries for MacOS and Ubuntu Linux only, here are the high level steps to create a runtime environment on Amazon Linux.
We'll use Docker to develop and test this on our local machine, with the official Docker Swift image and the official Amazon Linux image.
Source code and binary files will be stored on our laptop, we'll use docker volumes to mount our project directory to the Swift and Amazon Linux containers.
-
Copy from Swift docker image all runtime's shared libraries required to run a swift application, and package them to use them on Amazon Linux. This is a one time operation. I am using this manually crafted list of shared libraries that works for me, some additional ones might be required depending on your code.
-
Create a Lambda Layer containing all the runtime shared libraries. This is a one time operation.
-
Compile your swift code to Linux binaries. We'll use the official Docker Swift image to do that.
-
Create a Lambda function containing a bootstrap script and your Swift binary
import LambdaRuntime
func handler(context: Context, event: LambdaEvent) throws -> LambdaResponse {
return [
"result": event["key1"] ?? "unknown key : key1"
]
}
try LambdaRuntime(handler).run()- Test and enjoy :-)
I am using 2 docker containers for this project. The first one is the official Swift container, it will provide us with a build environment for our Swift source code. The second one is the official Amazon Linux container, it will provide us a runtime environment to test our code before to upload it to AWS Lambda.
To install the two images, you can type in a terminal
docker pull swift:4.2.1
docker pull amazonlinux:2018.03You'll also need to have AWS CLI installed and configured to access Lambda on your AWS Account.
In order for you to deploy your first Swift Lambda function, follow these steps.
- Clone this repository
git clone https://....
cd swift-custom-runtime-lambda The project is made of a couple of shell scripts and three directories. lambda-runtime contains the Swift source code to interact with the Lambda Runtime API. You should not modify this code. lambda-function contains the source code of your Lambda function. The shell scripts are helper to build, package and test your code, they are located in shell-scripts directory. The scripts will create a lambda directory containing all the binaries artifacts that will be deployed to AWS Lambda.
- Create a Lambda Layer, containing all runtime Linux shared libraries.
./shell-scripts/package_layer.shThis script starts a Swift docker container and runs a shell script to extract a list of runtime libraries that will be needed on Amazon Linux to run your Swift binary. The libraries are copied to lambda/libs directory. It will create a zip lambda/-lambda-swift-layer.zip and will create a layer on your AWS account, in the default region.
The ARN of the newly create Layer version is stored in a file called lambda_layer_arn.txt
- Write your own function code. The sample provided in this repo just reads the incoming parameter and create a simple JSON based response.
import LambdaRuntime
func handler(context: Context, event: LambdaEvent) throws -> LambdaResponse {
return [
"result": event["key1"] ?? "unknown key : key1"
]
}
try LambdaRuntime(handler).run()The LambdaRuntime class is the implementation of the Lambda Runtime API, it will take your function handler as argument and will start the event loop.
- Compile and package your binaries.
./shell-scripts/package_function.shThis script starts a Linux Swift container and runs the swift build command, the build will produce binaries in the .build directory. It will then copy the binary to the lambda directory and create a zip file and uploads to Lambda.
- Test locally on Amazon Linux
./shell-scripts/run_function.shThis script starts an Amazon Linux container and execute the bootstrap script to launch the Swift Lambda Runtime. This runtime will, in turn, call your function code. Output and debugging information will be displayed on the standard output.
Congrats if you're still reading and if you successfully managed to create your own function. You are now ready to test it on Lambda.
TODO : include screenshots
- Connect to the AWS Lambda console
- Click on "Functions" on the left, then on the name of the function that has been created just before (
SwiftLambdaHelloWorldif you did not change the default) - Click on "TEST"... to prepare a dummy payload
- Click on "TEST" and observe the results
Should you want to use Apple's XCode as IDE, you can create an XCode project from the Swift package definition.
swift package generate-xcodeproj
open HelloSwiftLambda.xcodeprojThis is a demo project, please send your feedback through Twitter at @sebsto.
I will also happily accept your pull requests.
Here are some ideas :
- Squeeze any bugs I did not detect
- Add unit tests for the framework
- Split the
package_function.shcode in two scripts, one topackageand one toupload - Create two distinct Swift project, one for the runtime and one for your Lambda function
- Package the Swift RunTime as a shared library and in a distinct Lambda layer for reuse across multiple functions.
