LoginSignup
9
1

More than 5 years have passed since last update.

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

Posted at

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がライブラリ化されれば一気にユースケースが広がりそうで、面白くなりそうです。
9
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1