AWS Lambdaに実行時パラメータを渡す手段としてエイリアスを利用する

2016.08.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
AWS Lambda、みなさん使っていますか?Lambdaへの機能要望として長年挙がっているものの一つとして、環境変数のサポートがあると思います。現状はLambdaの実行時パラメータを渡す手段が限られており、関数名や関数のDescriptionからの引用、言語のパラメータ読み込みの利用など皆さん工夫されているようです。 今回は、Lambda関数に設定するエイリアスを使ってみたいと思います。

エイリアス利用のメリット

エイリアスは、GitリポジトリのリリースタグのようにLambda関数のコードに紐付くバージョンのポインタを設定する機能です。本来の使用目的とは逸れますが、他の実行時パラメータを渡す手段に比べて以下の特徴があります。

  • contextオブジェクトから引用できるので、LambdaのAPIを呼ぶ必要が無い(関数のDescriptionとの比較)
  • 比較的文字数制限が緩い(128文字)(関数名との比較)
  • コードの内容/バージョンに依存しない(エイリアスのポイント先は変更できる)

ただしエイリアスは、利用できる文字種の制限が厳しい((?!^[0-9]+$)([a-zA-Z0-9-_]+))ため、JSONなど構造化したデータを入れるのには不向きです。また、Management Consoleのエイリアス作成画面では、なぜかエイリアス名の文字数が最大20字に制限されるため、20文字より多くしたい場合はCLIを利用しましょう

ユースケースと設定例

上記の特徴から、本番環境と開発/検証環境でのデータストアなどLambdaと連携するサービスのエンドポイントの使い分けあたりがユースケースとして適当かなと思います。

今回は、Amazon ES(Elasticsearch Service)のクラスタエンドポイントの可変部分(以下のクラスタ名-ランダム文字列部分)をエイリアスで指定してみました。

<クラスタ名>-<ランダム文字列>.<リージョン名>.es.amazonaws.com
^^^^^^^^^^^^^^^^^^^^^^^^^この部分

Lambda関数内では関数のARNの末尾にエイリアス名が含まれるため、Node.jsであれば以下のコードで参照できます。ただしARNの末尾は呼び出し元からの呼び出し方で可変のため、呼び出し元からエイリアス名を指定して呼び出すことに注意してください。

context.invokedFunctionArn.split(':').pop()

Amazon ESにevent.bodyをそのまま、AWS認証を付与してPOSTするコードを以下に示します。

var AWS = require('aws-sdk');
var path = require('path');

var esDomain = {
    region: 'ap-northeast-1',
    endpoint: null,
    index: 'device',
    doctype: 'sensor'
};
var creds = new AWS.EnvironmentCredentials('AWS');

exports.handler = function(event, context, callback) {
    esDomain.endpoint = context.invokedFunctionArn.split(':').pop() + '.ap-northeast-1.es.amazonaws.com';
    var body = JSON.parse(event.body);
    postToES(JSON.stringify(body), context, callback);
}

function postToES(doc, context, callback) {
    var endpoint = new AWS.Endpoint(esDomain.endpoint);
    var req = new AWS.HttpRequest(endpoint);

    req.method = 'POST';
    req.path = path.join('/', esDomain.index, esDomain.doctype);
    req.region = esDomain.region;
    req.headers['presigned-expires'] = false;
    req.headers['Host'] = endpoint.host;
    req.body = doc;

    var signer = new AWS.Signers.V4(req , 'es');  // es: service code
    signer.addAuthorization(creds, new Date());

    var send = new AWS.NodeHttpClient();
    send.handleRequest(req, null, function(httpResp) {
        var respBody = '';
        httpResp.on('data', function (chunk) {
            respBody += chunk;
        });
        httpResp.on('end', function (chunk) {
            console.log('Response: ' + respBody);
            callback(null, respBody);
        });
    }, function(err) {
        console.log('Error: ' + err);
        callback(err);
    });
}

続いて連携先のAmazon ESのクラスタを作成し、エンドポイントの可変部分を確認してLambda関数のエイリアスに設定します。今回はエンドポイントの可変部分はsearch-sakuraiot-XXXXXXXXXXXXXXXXXXXXとします。

$ aws lambda create-alias --name 'search-sakuraiot-XXXXXXXXXXXXXXXXXXXX' --function-version '$LATEST' --function-name sakuraiotes

関数のバージョンが設定済みであれば、$LATEST以外を指定してももちろん構いません。これでLambda側の準備はOKです。

今回はAPI Gatewayでリクエストを受け付けLambda関数を呼び出す構成なので、API Gatewayの統合リクエストでエイリアスを関数名の後ろに関数名:エイリアスの形式で指定します。

lambda-alias01

これでOKです。API GatewayのURLにアクセスしてAmazon ESまでの一連の連携が正常に動作することを確認しましょう。

まとめ

Lambdaに実行時パラメータを指定する方法として、Lambda関数に設定するエイリアスによる手法をご紹介しました。API Gateway+Lambdaの構成であれば、さらにAPI Gatewayのステージ変数とも組み合わせると、呼び分けがやりやすいのではと思います。

参考URL