

# AWS Lambda 用カスタムランタイムの構築
<a name="runtimes-custom"></a>

AWS Lambda ランタイムは、どのプログラミング言語でも実装できます。ランタイムは、関数が呼び出されたときに Lambda 関数のハンドラメソッドを実行するプログラムです。ランタイムは、関数のデプロイパッケージに含めるか、または[レイヤー](chapter-layers.md)で配信することができます。Lambda 関数を作成するときは、[OS 専用ランタイム (`provided` ランタイムファミリー](runtimes-provided.md)) を選択します。

**注記**  
カスタムランタイムの作成は高度なユースケースです。ネイティブバイナリへのコンパイルやサードパーティの既製のランタイムの使用に関する情報をお探しの場合は、「[Lambda の OS 専用ランタイムを使用する状況](runtimes-provided.md)」を参照してください。

カスタムランタイムデプロイの手順については、「[チュートリアル: カスタムランタイムの構築](runtimes-walkthrough.md)」を参照してください。

**Topics**
+ [要件](#runtimes-custom-build)
+ [カスタムランタイムでのレスポンスストリーミングの実装](#runtimes-custom-response-streaming)
+ [Lambda マネージドインスタンスのカスタムランタイムの構築](#runtimes-custom-managed-instances)

## 要件
<a name="runtimes-custom-build"></a>

カスタムランタイムでは、特定の初期化タスクと処理タスクを完了する必要があります。ランタイムは、関数のセットアップコードの実行、環境変数からのハンドラ名の読み取り、Lambda ランタイム API からの呼び出しイベントの読み取りを行います。ランタイムは、イベントデータを関数ハンドラに渡し、ハンドラからのレスポンスを Lambda に戻します。

### 初期化タスク
<a name="runtimes-custom-initialization"></a>

初期化タスクは、呼び出しを処理する環境を準備するために、[関数のインスタンスごとに](lambda-runtime-environment.md) 1 回実行されます。
+ **設定の取得** – 関数と環境に関する詳細を取得するには、環境変数を参照してください。
  + `_HANDLER` – 関数の設定からハンドラへの場所。標準形式は、`file.method` です。ここで、`file` は、拡張子のないファイル名、`method` は、ファイルで定義されているメソッドまたは関数の名前を表します。
  + `LAMBDA_TASK_ROOT` – 関数コードを含むディレクトリ。
  + `AWS_LAMBDA_RUNTIME_API` – ランタイム API のホストおよびポート。

  使用可能な変数の完全なリストについては、「[定義されたランタイム環境変数](configuration-envvars.md#configuration-envvars-runtime)」を参照してください。
+ **関数の初期化** – ハンドラファイルをロードし、ハンドラファイルに含まれているグローバルコードまたは静的コードを実行します。関数は、SDK クライアントやデータベース接続などの静的リソースを一度作成し、複数の呼び出しに再利用します。
+ **ハンドラエラー** – エラーが発生した場合は、[初期化エラー](runtimes-api.md#runtimes-api-initerror) API を呼び出し、すぐに終了します。

初期化は請求された実行時間とタイムアウトの対象です。実行によって関数の新しいインスタンスの初期化がトリガーされると、ログと [AWS X-Ray トレース](services-xray.md)に初期化時間が表示されます。

**Example ログ**  

```
REPORT RequestId: f8ac1208... Init Duration: 48.26 ms   Duration: 237.17 ms   Billed Duration: 300 ms   Memory Size: 128 MB   Max Memory Used: 26 MB
```

### 処理タスク
<a name="runtimes-custom-processing"></a>

実行されている間、ランタイムは [Lambda ランタイムインターフェイス](runtimes-api.md)を使用して、受信イベントの管理とエラーのレポートを行います。初期化タスクが完了したら、ランタイムは、受信イベントをループで処理します。ランタイムコードで、次のステップを順に実行します。
+ **イベントの取得** – [次の呼び出し](runtimes-api.md#runtimes-api-next) API を呼び出して、次のイベントを取得します。レスポンス本文には、イベントデータが含まれます。レスポンスヘッダーには、リクエスト ID などの情報が含まれます。
+ **トレースヘッダーの伝播** – X-Ray トレースヘッダーを API レスポンスの`Lambda-Runtime-Trace-Id`ヘッダーから取得します。`_X_AMZN_TRACE_ID` 環境変数をローカルで同じ値に設定します。X-Ray SDK はこの値を使用して、サービス間でトレースデータを接続します。
+ **コンテキストオブジェクトの作成** – 環境変数のコンテキスト情報および API レスポンスのヘッダーでオブジェクトを作成します。
+ **関数ハンドラの呼び出し** – イベントおよびコンテキストオブジェクトをハンドラに渡します。
+ **レスポンスの処理** – [呼び出しレスポンス](runtimes-api.md#runtimes-api-response) API を呼び出し、レスポンスをハンドラから投稿します。
+ **ハンドラエラー** – エラーが発生した場合は、[呼び出しエラー](runtimes-api.md#runtimes-api-invokeerror) API を呼び出します。
+ **クリーンアップ** – 不要なリソースの解放、他のサービスへのデータ送信、次のイベント取得前の追加タスクの実行を行います。

### エントリポイント
<a name="runtimes-custom-bootstrap"></a>

カスタムランタイムのエンドポイントは、`bootstrap` という名前の実行可能ファイルです。ブートストラップファイルをランタイムにするか、ランタイムを作成する別のファイルを呼び出す場合があります。デプロイパッケージのルートに `bootstrap` という名前のファイルが含まれていない場合、Lambda は関数のレイヤーでファイルを検索します。`bootstrap` ファイルが存在しないか、実行可能でない場合、関数は呼び出し時に `Runtime.InvalidEntrypoint` エラーを返します。

`bootstrap` ファイルによる例では、バンドルされた Node.js バージョンを使用して、`runtime.js` という別のファイルで JavaScript ランタイムを実行します。

**Example bootstrap**  

```
#!/bin/sh
    cd $LAMBDA_TASK_ROOT
    ./node-v11.1.0-linux-x64/bin/node runtime.js
```

## カスタムランタイムでのレスポンスストリーミングの実装
<a name="runtimes-custom-response-streaming"></a>

[レスポンスストリーミング関数](configuration-response-streaming.md)については、`response` および `error` エンドポイントは、ランタイムが部分的なレスポンスをクライアントにストリーミングし、ペイロードをチャンクで返すことができるように動作が若干変更されています。特定の動作の詳細については、以下を参照してください。
+ `/runtime/invocation/AwsRequestId/response` – ランタイムからの `Content-Type` ヘッダーを伝播して、クライアントに送信します。Lambda は、HTTP/1.1 チャンク転送エンコーディングを介して、レスポンスペイロードをチャンクで返します。Lambda にレスポンスをストリーミングするには、ランタイムが以下を実行する必要があります。
  + `Lambda-Runtime-Function-Response-Mode` HTTP ヘッダーを `streaming` に設定する。
  + `Transfer-Encoding` ヘッダーを `chunked` に設定します。
  + HTTP/1.1 チャンク転送エンコーディング仕様に従ったレスポンスを書き込む
  + レスポンスを正常に書き込んだ後、基盤となる接続を閉じます。
+ `/runtime/invocation/AwsRequestId/error` – ランタイムはこのエンドポイントを使用して、関数またはランタイムのエラーを Lambda に報告できます。Lambda は `Transfer-Encoding` ヘッダーも受け入れます。このエンドポイントを呼び出せるのは、ランタイムが呼び出しレスポンスの送信を開始する前だけです。
+ `/runtime/invocation/AwsRequestId/response` でエラー トレーラーを使用して中間エラーを報告 - ランタイムが呼び出しレスポンスの書き込みを開始した後に発生したエラーを報告するために、ランタイムはオプションで `Lambda-Runtime-Function-Error-Type` および `Lambda-Runtime-Function-Error-Body` という名前の HTTP 末尾ヘッダーをアタッチすることができます。Lambda はこれを正常なレスポンスとして扱い、ランタイムが提供するエラーメタデータをクライアントに転送します。
**注記**  
末尾ヘッダーをアタッチするには、ランタイムが HTTP リクエストの先頭に `Trailer` ヘッダー値を設定する必要があります。これは、HTTP/1.1 チャンク転送エンコーディング仕様によって義務付けられています。
  + `Lambda-Runtime-Function-Error-Type` – ランタイムで発生したエラータイプ。このヘッダーは、文字列値で構成されています。Lambda はどのような文字列でも受け入れますが、形式は *<category.reason>* にすることが推奨されます。例えば、`Runtime.APIKeyNotFound`。
  + `Lambda-Runtime-Function-Error-Body` – Base64-encoded でのエラーに関する情報。

## Lambda マネージドインスタンスのカスタムランタイムの構築
<a name="runtimes-custom-managed-instances"></a>

Lambda マネージドインスタンスは、Lambda (デフォルト) 関数と同じランタイム API を使用します。ただし、マネージドインスタンスの同時実行モデルをサポートするためにカスタムランタイムを実装する方法には大きな違いがあります。

### 同時リクエスト処理
<a name="runtimes-custom-managed-instances-concurrency"></a>

マネージドインスタンスのカスタムランタイムを構築する際の主な違いは、同時呼び出しのサポートです。ランタイムが一度に 1 つの呼び出しを処理する Lambda (デフォルト) 関数とは異なり、マネージドインスタンスは 1 つの実行環境内で複数の呼び出しを同時に処理できます。

カスタムランタイムは次の条件を満たす必要があります。
+ **同時 `/next` リクエストをサポートする** – ランタイムは、`AWS_LAMBDA_MAX_CONCURRENCY` 環境変数で指定された制限まで、[次の呼び出し](runtimes-api.md#runtimes-api-next) API を複数回同時に呼び出すことができます。
+ **同時 `/response` リクエストを処理する** – 複数の呼び出しが[呼び出しレスポンス](runtimes-api.md#runtimes-api-response) API を同時に呼び出すことができます。
+ **スレッドセーフなリクエスト処理を実装する** – 共有リソースと状態を適切に管理することで、同時呼び出しが相互に干渉しないようにします。
+ **一意のリクエスト ID を使用する** – `Lambda-Runtime-Aws-Request-Id` ヘッダーを使用して各呼び出しを個別に追跡し、レスポンスを対応するリクエストと照合します。

### 実装パターン
<a name="runtimes-custom-managed-instances-implementation"></a>

マネージドインスタンスランタイムの一般的な実装パターンには、同時呼び出しを処理するワーカースレッドまたはプロセスの作成が含まれます。

1. **同時実行数の制限を読み取る** – 初期化時に、`AWS_LAMBDA_MAX_CONCURRENCY` 環境変数を読み取って、サポートする同時呼び出しの数を決定します。

1. **ワーカープールを作成する** – 同時実行数の制限と等しいワーカー (スレッド、プロセス、または非同期タスク) のプールを初期化します。

1. **ワーカー処理ループ** – 各ワーカーは個別に以下を行います。
   + 呼び出しイベントを取得するために `/runtime/invocation/next` を呼び出す
   + イベントデータを使用して関数ハンドラーを呼び出す
   + レスポンスを `/runtime/invocation/AwsRequestId/response` に投稿する
   + ループを繰り返す

### その他の考慮事項
<a name="runtimes-custom-managed-instances-considerations"></a>
+ **ログ記録形式** – マネージドインスタンスは JSON ログ形式のみをサポートします。ランタイムが `AWS_LAMBDA_LOG_FORMAT` 環境変数を尊重し、JSON 形式のみを使用していることを確認します。詳細については、「[JSON とプレーンテキストのログフォーマットの設定](monitoring-cloudwatchlogs-logformat.md)」を参照してください。
+ **共有リソース** – `/tmp` ディレクトリなどの共有リソースを同時呼び出しで使用する場合は注意してください。競合状態を防ぐために、適切なロックメカニズムを実装します。

Lambda マネージドインスタンスの実行環境の詳細については、「[Lambda マネージドインスタンスの実行環境について理解する](lambda-managed-instances-execution-environment.md)」を参照してください。