AWS Lambda Function
是轻量级的计算服务。优势是按需付费,专注于功能,服务本身如何构建暴露都有AWS
都不需要自己操心。
而按需付费基本就是服务使用时长和内存占用了,这个优化的话那妥妥的是Rust
的拿手好戏, 所以现在有好多Serverless
服务都用Rust
构建的Lambda Function
来搞。
今天简单看下如何用Rust
快速构建Lambda Function
(别担心没 aws 环境,往下看,有本地沙箱可尝试)
cargo-lambda
cargo-lambda
这个库可以用来构建Lambda Function
(也是官方推荐的工具)
如下代码安装:
brew tap cargo-lambda/cargo-lambda
brew install cargo-lambda
然后初始化一个 demo
cargo lambda new lambda-demo
> Is this function an HTTP function? Yes
会自动生成初始化项目,引入相关依赖及运行时:lambda-http
和tokio
依赖
功能部分代码如下,提供一个hello world
式请求处理:
use lambda_http::{run, service_fn, tracing, Body, Error, Request, RequestExt, Response};
async fn function_handler(event: Request) -> Result<Response<Body>, Error> {
let who = event
.query_string_parameters_ref()
.and_then(|params| params.first("name"))
.unwrap_or("world");
let message = format!("Hello {who}, this is an AWS Lambda HTTP request");
let resp = Response::builder()
.status(200)
.header("content-type", "text/html")
.body(message.into())
.map_err(Box::new)?;
Ok(resp)
}
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing::init_default_subscriber();
run(service_fn(function_handler)).await
}
题外话,有没有感觉这个service_fn
很眼熟?
这个接的handler
也要求实现Service trait
, 跟tower service
一样。为啥呢,用了hyper
库!都说hyper
基本就是Rust
服务框架的基石不假。
开发中用watch
就能本地运行调试,支持变更重编译
cargo lambda watch
# INFO invoke server listening on [::]:9000
也可以命令行调用
cargo lambda invoke lambda-demo --data-ascii "?name=newbmiao"
cargo lambda build --release --arm64
这样会将执行文件编译到./target/lambda/lambda-demo/bootstrap
(注意:如果是workspace
, 则需要去workspace
下target
目录找)
可执行文件压缩一下就可以用来部署了
zip bootstrap.zip bootstrap
(这部分会设计比较多 infrastructure,感兴趣的同学可以继续往下)
部署也很方便,不过难在不是所有人都有aws
账户啊。
也好解决,localstack
可以本地模拟aws
环境
用docker-compose up
起个localstack
version: "3.8"
services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}"
image: localstack/localstack
ports:
- "127.0.0.1:4566:4566" # LocalStack Gateway
- "127.0.0.1:4510-4559:4510-4559" # external services port range
environment:
# LocalStack configuration: https://docs.localstack.cloud/references/configuration/
- DEBUG=${DEBUG:-0}
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
然后用terraform
构建部署流程, 核心部分就是:
# 构建
resource "aws_lambda_function" "lambda_demo" {
filename = "bootstrap.zip"
function_name = "lambda_demo"
role = aws_iam_role.iam_for_lambda_tf.arn
handler = "bootstrap"
source_code_hash = filebase64sha256("bootstrap.zip")
runtime = "provided.al2"
architectures = ["arm64"]
}
剩下就是权限以及获取lambda function
地址
resource "aws_lambda_function_url" "lambda_demo_url" {
function_name = aws_lambda_function.lambda_demo.arn
authorization_type = "NONE"
}
output "function_url" {
description = "Function URL."
value = aws_lambda_function_url.lambda_demo_url.function_url
}
resource "aws_iam_role" "iam_for_lambda_tf" {
name = "iam_for_lambda_tf"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
这样从terraform apply
部署结果中能拿到访问地址, 比如
...
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
function_url = "http://h6v7ozz6ay3h6apr2hi5edsmnc0wpz80.lambda-url.us-east-1.localhost.localstack.cloud:4566/
想上手试下的话,详细代码见lambda-demo[1], build.sh
有详细打包流程
参考资料
[1]
lambda-demo: https://github.com/NewbMiao/rust-koan/tree/master/aws-lambda/lambda-demo