Lambdaのcustom runtimeとALBのLambdaサポートが来たので組み合わせてみる
Lambdaのcustom runtimeとALBのLambdaサポートが来たので組み合わせてみる:
re:invent2018の発表みなさんご覧になりましたでしょうか。
個人的に面白い事出来そうだなーと思ったのがLambdaに関わる発表でした。
\(^o^)/
re:invent2018の発表みなさんご覧になりましたでしょうか。
個人的に面白い事出来そうだなーと思ったのがLambdaに関わる発表でした。
ALBのlambdaサポート
- http(s)リクエストをイベントとして動くわけで、じゃあハンドラーのevent objectに何が入ってくるんじゃという話ですが、Nodeで受け取って単純に表示してみると以下のようになります。
{ "requestContext":{ "elb":{ "targetGroupArn":"arn:aws:elasticloadbalancing:{himitsu}" } }, "httpMethod":"GET", "path":"/{albのpath}", "queryStringParameters":{}, "headers":{ "accept":"*/*", "host":"{albのhost名}", "user-agent":"curl/7.54.0", "x-amzn-trace-id":"{id}", "x-forwarded-for":"{ip.ip.ip.ip}", "x-forwarded-port":"80", "x-forwarded-proto":"http" }, "body":"", "isBase64Encoded":false }
- なるほどヘッダー情報やquery stringまでいい感じにパースして渡してくれるようです。
- 以下のようにstatusCodeやstatusDescriptionを詰めてobjectを返せばそれがresponseとなります。
{ statusCode: 200, statusDescription: "200 OK", isBase64Encoded: false, headers: { Content-Type: "application/json; charset=utf-8" }, body:"" }
lambdaのcustom runtime
- 任意のruntimeを作れるよという話です。シェルスクリプトでの実装例がドキュメントに上がっています(link)。bootstrapという実行可能ファイルが必要なのですね。
- 今回はRustで実装したかったのですが、awslabにもうmacro化したものがリファレンス実装として上がっていました(link)。コードを見て頂ければ分かるようにループでイベントを待ち受け、eventオブジェクトを登録されたコールバックファンクション(これがまさしくlambdaのhandlerにあたる物)に渡して実行しています。こちらを使わせてもらいましょう。
ALBとcustom runtimeのlambdaを組み合わせる
- コード例
#[macro_use] extern crate lambda_runtime as lambda; #[macro_use] extern crate serde_derive; #[macro_use] extern crate log; extern crate simple_logger; use lambda::error::HandlerError; use std::error::Error; #[derive(Deserialize, Clone)] struct CustomEvent { #[serde(rename = "requestContext")] request_context: Elb, #[serde(rename = "httpMethod")] http_method: String, path: String, #[serde(rename = "queryStringParameters")] query_string_parameters:QueryStringParameters } #[derive(Serialize, Clone)] struct Response { #[serde(rename = "statusCode")] status_code: i64, #[serde(rename = "statusDescription")] status_description: String, #[serde(rename = "isBase64Encoded")] is_base64encoded: bool, headers: ContentType, body: String, } #[derive(Deserialize, Clone)] struct Elb { elb: TargetGroupArn } #[derive(Deserialize, Clone)] struct TargetGroupArn { #[serde(rename = "targetGroupArn")] target_group_arn: String } #[derive(Deserialize, Clone)] struct QueryStringParameters { name: String } #[derive(Serialize, Clone)] struct ContentType { content_type: String } fn main() -> Result<(), Box<dyn Error>> { simple_logger::init_with_level(log::Level::Info)?; lambda!(my_handler); Ok(()) } fn my_handler(e: CustomEvent, c: lambda::Context) -> Result<Response, HandlerError> { if e.http_method == "" { error!("Empty http_method in request {}", c.aws_request_id); return Err(c.new_error("Empty")); } Ok(Response { status_code: 200, status_description: "200 OK".to_string(), is_base64encoded: false, headers: ContentType { content_type: "application/json".to_string() }, body: format!("Rust function invoked! Hello, {}\n", e.query_string_parameters.name) }) }
- requestイベントのeventオブジェクトの形は最初に書いたとおりだろうなーという事で、それをマッピング出来るように構造体を作ってみました。
- 以下をcargo.tomlに追記すればbootstrapという名前で実行可能なバイナリーを作成出来ますので、zipで固めてlambda関数としてアップロードします。
[[bin]] name = "bootstrap" path = "src/main.rs"
- あとはALBのターゲット設定でこの関数を指せばOKですね。
リクエストしてみる
\(^o^)/
感想
- custom runtimeでも問題なくALB連携出来ますね!
- 安定したruntimeがライブラリ化されれば一気にユースケースが広がりそうで、面白くなりそうです。
コメント
コメントを投稿