Для чего нужна данная статья? :
- Создать AWS Lambda на Rust.
- Развернуть приложение в AWS с помощью Terraform.
Зачем Вам это уметь? :
- Собрать воедино разные компоненты системы из разных облачных сред.
Пример.
aws sts get-caller-identity --profile <your_profile>
cargo new rust-aws-lambda
cd rust-aws-lambda
src/main.rs
fn say_hello(name: Option<&str>) -> String {
match name {
Some(name) => format!("Hello, {}!", name),
None => "Hello, stranger!".to_string(), }
}
fn main() {
let response = say_hello(Some("world"));
println!("{}", response);
}
Среда выполнения Rust для Lambda выглядит следующим образом: лучше всего взаимодействовать с помощью Cargo Lambda.
Этот инструмент позволит вам собрать и запустить функцию локально. Его также можно использовать для начальной загрузки лямбды или ее развертывания.
Rust AWS SDK не реализует sso_session пока. Поддержка может появиться в ближайшее время.
Ознакомьтесь с установкой :
pip3 install cargo-lambda
Среда выполнения Lambda ожидает асинхронную функцию, которая принимает в качестве параметра a и возвращает некоторый JSON.
cargo add lambda_runtime tokio serde_json
async fn run_lambda(event: LambdaEvent<Value>) -> Result<Value, Error> { let (event, _context) = event.into_parts();
let name = match event["name"].as_str() {
Some(name) => name,
None => return Err(Error::new(ErrorKind::InvalidInput, "Name is required")),
};
let result = say_hello(name);
Ok(json!(result))
}
Главная функция должна быть обновлена для запуска обёртки, которая требует, чтобы она была асинхронной и возвращала Result.
#[tokio::main] async fn main() -> Result<(), Error> { lambda_runtime::run(service_fn(run_lambda)).await?;
Ok(())
}
cargo lambda watch
cargo lambda invoke rust-aws-lambda --data-ascii '{}'
cargo lambda invoke rust-aws-lambda --data-ascii '{ "name": "world" }'
Для того чтобы основная функция возвращала структуру, которая может быть сериализована в JSON, добавим код.
cargo add serde
#[derive(Debug, PartialEq, serde::Serialize)] struct HelloResponse {
message: String, }
fn say_hello(name: Option<&str>) -> HelloResponse {
let name = match name { Some(name) => name,
None => "stranger", };
HelloResponse { message: format!("Hello, {name}!"), }
}
Добавим трассировку.
cargo add tracing --features log
cargo add tracing-subscriber --features fmt,env-filter
async fn main() -> Result<(), Error> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.with_ansi(false) // no colors as they look messed up in Cloudwatch
.init()?;
// [...]
Ok(())
}
Создадим диапазон для каждого вызова лямбды и любого события журнала, отправленного из в рамках этой функции будет назначена соответствующему диапазону.
#[tracing::instrument()]
async fn run_lambda(event: LambdaEvent<Value>) -> Result<Value, Error> {
let (event, context) = event.into_parts();
tracing::info!(event = ?event, context = ?context);
// [...]
Ok(())
}
Создадим файл terraform.
module "lambda_function" {
source = "terraform-aws-modules/lambda/aws"
function_name = "rust-aws-lambda"
description = "AWS Lambda in Rust with Terraform" runtime = "provided.al2" architectures = ["arm64"]
handler = "bootstrap"
create_package = false
local_existing_package = "../target/lambda/rust-aws-lambda/bootstrap.zip"}
cargo lambda build --release --arm64 --output-format zip
terraform -chdir=infra init AWS_PROFILE=<your_profile>
terraform -chdir=infra plan
AWS_PROFILE=<your_profile> terraform -chdir=infra apply