Rust Serverless (2021)

Page content

CAUTION (2022)

The first virsion of this post was created in Apri 2021, but as of 2022, AWS officially released their SDK. This post (note) should be updated. Still there is no native run environment for Rust on AWS Lambda as of Jan.18.2022, so we still need to create a bootstrap executable.

Getting started

I followed the link. In this page, the author wrote details and it’s very educational. To remind the procedure, I left memo.

I really appreciate you, Chuma Umenze :)

Hello world code

cargo new rust_lambda

Cargo.toml:

[package]
// --- snip ---
autobins = false

[dependencies]
lambda_runtime = "0.2.1"
serde = { version = "^1.0", features = ["derive"] }

[[bin]]
name = "bootstrap"
path = "src/main.rs"

src/main.rs:

use lambda_runtime::{error::HandlerError, lambda, Context};
use serde::{Deserialize, Serialize};
use std::error::Error;

#[derive(Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
struct LambdaRequest {
    full_name: String,
    message: Option<String>,
}

#[derive(Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
struct LambdaResponse {
    lambda_request: LambdaRequest,
}

fn main() -> Result<(), Box<dyn Error>> {
    lambda!(lambda_handler);
    Ok(())
}

fn lambda_handler(e: LambdaRequest, _c: Context) -> Result<LambdaResponse, HandlerError> {
    let mut e = e.clone();
    e.full_name = format!("Hello {name}!", name = e.full_name);
    let msg = match e.message {
        Some(msg) => format!("Your message is '{msg}'.", msg = msg),
        None => format!("You have no message."),
    };
    e.message = Some(msg);
    Ok(LambdaResponse { lambda_request: e })
}

Build for Lambda environment

rustup target add x86_64-unknown-linux-musl
cargo install cross
echo '
[target.x86_64-unknown-linux-gnu]
image = "lambci/lambda:build-provided"

[target.x86_64-unknown-linux-musl]
image = "lambci/lambda:build-provided"
' >> Cross.toml

cross build --target x86_64-unknown-linux-musl --release
cross build --target x86_64-unknown-linux-gnu --release

Deploy on AWS Lambda

zip -r9 -j bootstrap.zip ./target/x86_64-unknown-linux-gnu/release/bootstrap

aws iam create-role \
--role-name lambda-basic-execution \
--assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
        {
        "Effect": "Allow",
        "Principal": {
            "Service": "lambda.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
        }
    ]
}'

aws iam attach-role-policy \
--role-name lambda-basic-execution \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

AWS_ACCOUNT_ID=`aws sts get-caller-identity --query Account --output text` && \
aws lambda create-function \
--function-name rust_lambda \
--runtime provided \
--role arn:aws:iam::$AWS_ACCOUNT_ID:role/lambda-basic-execution \
--zip-file fileb://bootstrap.zip \
--description "Simple Rust function" \
--timeout 5 \
--handler main

Done!

Test

$ aws lambda invoke \
--function-name=rust_lambda \
--invocation-type=RequestResponse \
--payload $(echo '{"fullName": "Martin Luther", "message": null}' | base64 ) \
output.json
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

The response is saved as output.json.

$ cat output.json
{"lambdaRequest":{"fullName":"Hello Martin Luther!","message":"You have no message."}}

At AWS Lambda console, go the function rust_lambda and Test with

  • New event
  • Template: hello-world
  • Name: MyEventTest
  • Data: {"fullName": "Im atlex00", "message": "See you Lambda!"}

Review

Note: Failed 2018 post

https://aws.amazon.com/blogs/opensource/rust-runtime-for-aws-lambda/

error: linker `x86_64-linux-musl-gcc` not found