LoginSignup
2
0

5xx台のStatusCodeを返すApplication Load BalancerのバックエンドをLambdaで作る

Last updated at Posted at 2023-12-19

この記事はAWS Community Builders Advent Calendar 2023、の13日目の記事をあとから埋めています。

NTTテクノクロス株式会社の渡邉 洋平です。コミュニティ活動ではwatany名義で活動することも多いです。

AWS Community BuilderのCloud Operationsとして2022年から選出されておりますが、専門分野詐欺になっているのが最近の悩みです。

発端

旧TwitterことX(以下Twitter)でこういった書き込みがありました。

Twitterリンク参照できない場合の引用

ALBのヘルスチェックには合格するけど、5xxエラーを返すWebサーバーを意図的に作る方法を考え中…
試しにCPUとメモリ負荷を上げてみたが、ALBのATWは異常検知しなかったな🤔

日本語話者が少なくなる一方の昨今、AWS Community Builderとして、このような身近な検証活動も残していく必要があると考えております。

ということで、この辺りの挙動の理解がはっきりしていなかったため、実際に手を動かして挙動を確認したいと思います。

検証1 ALBのバックエンドが5xxを返す構成

構成

今回は簡単のため、ALB+Lambdaの構成をとりたいと思います。

環境はAWS CDKでこのように表現されます。

import * as cdk from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
import * as elbv2Targets from "aws-cdk-lib/aws-elasticloadbalancingv2-targets";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";

import { Construct } from "constructs";

export class Error500Stack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc: ec2.Vpc = new ec2.Vpc(this, "VPC", {
      maxAzs: 2,
    });

    const lb = new elbv2.ApplicationLoadBalancer(this, "LB", {
      vpc,
      internetFacing: true,
    });

    const fn = new NodejsFunction(this, "HelloWorldFunction", {
      entry: "lib/lambda/index500.ts",
      functionName: "err-500",
      runtime: lambda.Runtime.NODEJS_20_X,
      vpc,
    });

    const listener = lb.addListener("Listener", { port: 80 });
    listener.addTargets("Targets", {
      targets: [new elbv2Targets.LambdaTarget(fn)],
      healthCheck: {
        enabled: true,
      },
    });
  }
}

Web Server

/の場合509を返し、/healthの場合200を返すサーバーです。記述はTypescriptとWeb FrameworkのHonoを利用しています。

index500.ts
import { Hono } from "hono";
import { handle } from "hono/aws-lambda";

const app = new Hono();

app.get("/health", (c) => {
  return c.text("ok!");
});

app.all("/", (c) => {
  return c.text("Opps!", 509, {
    "X-Custom": "for-debug",
  });
});

export const handler = handle(app);

検証結果

意図した結果が返ることがわかります。

# /health
curl -i http://Error5-LB8A1-jzY5dv8AjNDj-201391188.ap-northeast-1.elb.amazonaws.com/health
HTTP/1.1 200 OK
Server: awselb/2.0
Date: Mon, 18 Dec 2023 16:02:22 GMT
Content-Type: text/plain;charset=UTF-8
Content-Length: 3
Connection: keep-alive

ok!

# /
curl -i http://Error5-LB8A1-jzY5dv8AjNDj-201391188.ap-northeast-1.elb.amazonaws.com/
HTTP/1.1 509 
Server: awselb/2.0
Date: Mon, 18 Dec 2023 16:02:25 GMT
Content-Type: text/plain; charset=UTF-8
Content-Length: 5
Connection: keep-alive
x-custom: for-debug

検証2 ALBのバックエンドが5xxを返す構成 + 「/」にヘルスチェック

構成

検証1の構成を一部変更します。

    const listener = lb.addListener("Listener", { port: 80 });
    listener.addTargets("Targets", {
      targets: [new elbv2Targets.LambdaTarget(fn)],
+      healthCheck: {
+        enabled: true,
+      },
    });

結果

curlによるリクエストは成功しませんでした。コンソールを確認するとHealthCheckが失敗していたことが原因です。

failed_healthcheck.png

ちなみにHealthCheckのステータスコードは変更できますが、下記ドキュメントを見る限り500台は未対応であると明記されているため、ALB HealthCheckでの実現は難しいでしょう。

If the protocol version is HTTP/1.1 or HTTP/2, the possible values are from 200 to 499. You can specify multiple values (for example, "200,202") or a range of values (for example, "200-299"). The default value is 200.

検証3 ALBのバックエンドが5xxを返す構成 + 「/health」にヘルスチェック

構成

検証2の構成を一部変更し、Pathを追加します。

    const listener = lb.addListener("Listener", { port: 80 });
    listener.addTargets("Targets", {
      targets: [new elbv2Targets.LambdaTarget(fn)],
      healthCheck: {
        enabled: true,
+        path: "/health"
      },
    });

結果

これは成功しました! 特に仕様上も懸念はなさそうなのでこれで良さそうです。

ok_healthcheck.png

まとめ

  • ALBで5xx台のStatusCodeを返す場合、HealthCheckのエンドポイントを分けて運用する。
  • ALB - Lambda構成では、HealthCheckなしでも利用できるため、5xxを返すという目的自体は達成できる。

久々にALBを触ったのですが、CDKを使うことで効率よく進めることができました。それでは!

2
0
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
2
0