Lambdaのcustom runtimeとALBのLambdaサポートが来たので組み合わせてみる

Lambdaのcustom runtimeとALBのLambdaサポートが来たので組み合わせてみる:

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ですね。


lambda2.png




lambda1.png




リクエストしてみる

lambda3.png

\(^o^)/



感想

  • custom runtimeでも問題なくALB連携出来ますね!
  • 安定したruntimeがライブラリ化されれば一気にユースケースが広がりそうで、面白くなりそうです。

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)