Help us understand the problem. What is going on with this article?

AWS Application Load BalancerのターゲットにLambda(Python)を指定してみた

More than 1 year has passed since last update.

11月26日から開催されていますAWS re:Invent 2018で、Serverless系の新ネタが少ないと思ってましたが、ようやくきました。

アプリケーションロードバランサー(ALB)のターゲットにAWS Lambdaが選択可能になりました

これまでは、Lambdaを外部から呼び出す場合は、API Gatewayからが一般的だと想いますが、ALBから呼び出すことができるようになりました。
API Gatewayを利用して実装する場合、URL遷移させたいWebアプリの実装が難しかったと思います。しかし、ALB経由でLambdaを実行できるようになったことで、URL遷移のアプリ実装も簡単になると思います。

既に利用できるようになっていたので試してみました。

まずはパラメータ調査用Lambda関数を用意しました

どんなパラメータがLambda関数に渡ってくるのか調査するために、Cloudwatch logsで確認します。ブログに書かれていたソースを参考に以下のようにしました。

lambda_function.py
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

def lambda_handler(event, context):

    logger.debug( event )    

    response = {
        "statusCode": 200,
        "isBase64Encoded": False,
        "headers": {
            "Content-Type": "text/html; charset=utf-8"
        }
    }

    response['body'] = """<html>
    <head>
        <meta charset="UTF-8">
        <title>Hello World!</title>
    </head>
    <body>
    <p>Hello World!</p>
    </body>
    </html>"""

    return response

ALBを作成しました

Lambda関数を作成した後で、ALBの設定をしました。
ターゲットグループの作成画面に、これまではなかった、Lambda関数が指定できるようになってます。ここで、先程作成したLambda関数を選択します。
target.png
ターゲットグループ以外はこれまでのALB作成と変わらなかったと思います。

ALBにアクセスしてみました

ALB作成後、curl http://***.ap-northeast-1.elb.amazonaws.com/lambdatest/?a=b&c=dでアクセスし、Cloudwatch logsに出力されているeventパラメータを調べたみたところ、以下の出力がされていました(一部マスクしています)。
curlの出力は、HTMLが出力されていました。

{'requestContext': 
    {'elb': {
        'targetGroupArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:***:targetgroup/TestLoggingLambda/***'
        }
    }, 
    'httpMethod': 'GET', 
    'path': '/lambdatest/', 
    'queryStringParameters': {'a': 'b', 'c': 'd'}, 
    'headers': {
            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 
            'accept-encoding': 'gzip, deflate', 
            'accept-language': 'ja,en-US;q=0.9,en;q=0.8,th;q=0.7', 
            'connection': 'keep-alive', 
            'host': '***.ap-northeast-1.elb.amazonaws.com', 
            'upgrade-insecure-requests': '1', 
            'user-agent': '***', 
            'x-amzn-trace-id': '***'', 
            'x-forwarded-for': '***'', 
            'x-forwarded-port': '80', 
            'x-forwarded-proto': 'http'
    }, 
    'body': '', 
    'isBase64Encoded': False
}

GETパラメータは、queryStringParametersに格納されるようです。リクエストヘッダーも取得できていました。

POSTでアクセスしてみた

curl -F "hoge=fuga" -F "form2=テスト" http://***.ap-northeast-1.elb.amazonaws.com/lambdatest/でアクセスしてみたところ、body部分にbase64encodeされた状態でデータが格納されているようです。

{'requestContext': 
    {'elb': {
        'targetGroupArn': 'arn:aws:elasticloadbalancing:ap-northeast-1:***:targetgroup/TestLoggingLambda/***'
        }
    }, 
    'httpMethod': 'POST', 
    'path': '/lambdatest/', 
    'queryStringParameters': {}, 
    'headers': {
        'accept': '*/*', 
        'content-length': '246', 
        'content-type': 'multipart/form-data; boundary=------------------------66c2ae32e35a634a', 
        'expect': '100-continue', 
        'host': '***.ap-northeast-1.elb.amazonaws.com', 
        'user-agent': ''***'',', 
        'x-amzn-trace-id': ''***'',', 
        'x-forwarded-for': ''***'',', 
        'x-forwarded-port': '80', 
        'x-forwarded-proto': 'http'
    }, 
    'body':'LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS02NmMyYWUzMmUzNWE2MzRhDQpDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9ImhvZ2UiDQoNCmZ1Z2ENCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tNjZjMmFlMzJlMzVhNjM0YQ0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJmb3JtMiINCg0K44OG44K544OIDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTY2YzJhZTMyZTM1YTYzNGEtLQ0K', 
    'isBase64Encoded': True
}

GETとPOSTでパラメータを取得するサンプル

Lambda関数に渡ってくるパラメータがわかったので、GETとPOSTの場合でサンプルプログラムを書いてみました。POSTデータのデコードは面倒だったので、Pythonのcgiモジュールを使っています。

lambda_function.py
import base64
import io
import cgi


def lambda_handler(event, context):

    response = {
        "statusCode": 200,
        "isBase64Encoded": False,
        "headers": {
            "Content-Type": "text/html; charset=utf-8"
        }
    }

    response['body'] = """<html>
    <head>
        <meta charset="UTF-8">
        <title>Hello World!</title>
    </head>
    <body>
    <p>Hello World!</p>"""

    if event['httpMethod'] == "GET":
        for k,v in event['queryStringParameters'].items():
           response['body'] += "<p>" + k + " : " + v + "</p>"

    elif event['httpMethod'] == "POST":
        fp = io.BytesIO(base64.b64decode(event['body']))
        environ = {'REQUEST_METHOD': 'POST'}
        headers = {
            'content-type': event['headers']['content-type'],
            'content-length': event['headers']['content-length']
        }
        form = cgi.FieldStorage(fp=fp, environ=environ, headers=headers)

        for f in form.list:
            response['body'] += "<p>" + f.name + " : " + f.value + "</p>"

    response['body'] += """<p>ALBからLambdaを呼び出しています</p>
    </body>
    </html>"""

    return response

参考にさせていただいて記事:[Python] POSTされたmultipart/form-dataをFieldStorageでパースする

構成を考えてみると

これまでの結果、GETやPOSTでやり取りするページは作成できそうです。これを踏まえ、構成を考えてみると、静的ページは、CloudFront+S3で表示をさせ、動的処理が必要なページだけ、CloudFront+ALB+Lambda+(あとは必要なサービス)とすればEC2を利用しなくても大抵のサイトは作成できるような気がしてきました。図にしてみると、こんな感じです。
EC2が無くなることで運用負荷が激減すると思います。

スクリーンショット 2018-11-30 17.02.36.png

LambdaのruntimeにRubyやPHPも指定できるようになったようなので、これまでEC2上で動かしていた簡単なプログラムは、Lambdaに移行できるかもしれません。

運用で楽をしたいので、ブログを見て、取り急ぎテストした結果でした。

izanari
fork
株式会社フォークは、Webサイトの企画・制作・開発・サーバホスティング・コンタクトセンターを一社に集約したワンストップソリューションを展開する制作会社です。
https://www.fork.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした