

# チュートリアル: カスタムランタイムの構築
<a name="runtimes-walkthrough"></a>

このチュートリアルでは、カスタムランタイムで Lambda 関数を使用します。まず、ランタイムを関数のデプロイパッケージに含めます。次に、それを関数とは別に管理するレイヤーに移行します。最後に、リソースベースのアクセス許可ポリシーを更新して、ランタイムレイヤーを世界と共有します。

## 前提条件
<a name="runtimes-walkthrough-prereqs"></a>

このチュートリアルでは、基本的な Lambda オペレーションと Lambda コンソールについてある程度の知識があることを前提としています。初めての方は、[コンソールで Lambda の関数の作成](getting-started.md#getting-started-create-function) の手順に従って最初の Lambda 関数を作成してください。

以下の手順を完了するには、[AWS CLI バージョン 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) が必要です。コマンドと予想される出力は、別々のブロックにリストされます。

```
aws --version
```

次のような出力が表示されます。

```
aws-cli/2.13.27 Python/3.11.6 Linux/4.14.328-248.540.amzn2.x86_64 exe/x86_64.amzn.2
```

コマンドが長い場合、コマンドを複数行に分割するためにエスケープ文字 (`\`) が使用されます。

Linux および macOS では、任意のシェルとパッケージマネージャーを使用します。

**注記**  
Windows では、Lambda でよく使用される一部の Bash CLI コマンド (`zip` など) が、オペレーティングシステムの組み込みターミナルでサポートされていません。Ubuntu および Bash の Windows 統合バージョンを取得するには、[Windows Subsystem for Linux をインストール](https://docs.microsoft.com/en-us/windows/wsl/install-win10)します。このガイドの CLI コマンドの例では、Linux フォーマットを使用しています。Windows CLI を使用している場合、インライン JSON ドキュメントを含むコマンドを再フォーマットする必要があります。

Lambda 関数を作成するには IAM ロールが必要です。ロールには、ログを CloudWatch Logs に送信し、関数で使用される AWS のサービスにアクセスするためのアクセス許可が必要です。関数開発用の実行ロールをお持ちでない場合は、ここで作成します。

**実行ロールを作成するには**

1. IAM コンソールの [[ロールページ](https://console.aws.amazon.com/iam/home#/roles)] を開きます。

1. [**ロールの作成**] を選択します。

1. 次のプロパティでロールを作成します。
   + **信頼されたエンティティ** – **Lambda**。
   + **アクセス許可** – **AWSLambdaBasicExecutionRole**。
   + **ロール名** – **lambda-role**。

   **AWSLambdaBasicExecutionRole** ポリシーには、ログを CloudWatch Logs に書き込むために関数が必要とするアクセス許可があります。

## 関数の作成
<a name="runtimes-walkthrough-function"></a>

カスタムランタイムで Lambda 関数を作成します。この例には、ランタイム `bootstrap` ファイルと関数ハンドラーの 2 つのファイルが含まれています。いずれのファイルも Bash で実装されています。

1. プロジェクト用のディレクトリを作成し、そのディレクトリに切り替えます。

   ```
   mkdir runtime-tutorial
   cd runtime-tutorial
   ```

1. `bootstrap` という名前の新しいファイルを作成します。これはカスタムランタイムです。  
**Example bootstrap**  

   ```
   #!/bin/sh
   
   set -euo pipefail
   
   # Initialization - load function handler
   source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh"
   
   # Processing
   while true
   do
     HEADERS="$(mktemp)"
     # Get an event. The HTTP request will block until one is received
     EVENT_DATA=$(curl -sS -LD "$HEADERS" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
   
     # Extract request ID by scraping response headers received above
     REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)
   
     # Run the handler function from the script
     RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA")
   
     # Send the response
     curl "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
   done
   ```

   ランタイムは、デプロイパッケージから関数スクリプトを読み込みます。2 つの変数を使用して、スクリプトを見つけます。`LAMBDA_TASK_ROOT` は、パッケージが抽出された場所を変数に伝え、`_HANDLER` には、そのスクリプトの名前が含まれます。

   ランタイムは関数スクリプトをロードした後、ランタイム API を使用して Lambda から呼び出しイベントを取得し、そのイベントをハンドラーに渡して、レスポンスを Lambda に戻します。リクエスト ID を取得するには、API レスポンスのヘッダーを一時ファイルに保存し、ファイルから `Lambda-Runtime-Aws-Request-Id` ヘッダーを読み込みます。
**注記**  
ランタイムは、他にもエラーの処理などに使用され、コンテキスト情報をハンドラに提供します。詳細については、「[要件](runtimes-custom.md#runtimes-custom-build)」を参照してください。

1. 関数のためのスクリプトを作成します。以下のスクリプト例は、イベントデータを取得するハンドラー関数を定義し、それを `stderr` にログ記録して返します。  
**Example function.sh**  

   ```
   function handler () {
     EVENT_DATA=$1
     echo "$EVENT_DATA" 1>&2;
     RESPONSE="Echoing request: '$EVENT_DATA'"
   
     echo $RESPONSE
   }
   ```

   `runtime-tutorial` ディレクトリは以下のようになります。

   ```
   runtime-tutorial
   ├ bootstrap
   └ function.sh
   ```

1. ファイルを実行可能にして .zip アーカイブに追加します。これがデプロイパッケージです。

   ```
   chmod 755 function.sh bootstrap
   zip function.zip function.sh bootstrap
   ```

1. `bash-runtime`という名前の関数を作成します。`--role` には、Lambda [実行ロール](lambda-intro-execution-role.md)の ARN を入力します。

   ```
   aws lambda create-function --function-name bash-runtime \
   --zip-file fileb://function.zip --handler function.handler --runtime provided.al2023 \
   --role arn:aws:iam::123456789012:role/lambda-role
   ```

1. 関数を呼び出します。

   ```
   aws lambda invoke --function-name bash-runtime --payload '{"text":"Hello"}' response.txt --cli-binary-format raw-in-base64-out
   ```

   AWS CLI バージョン 2 を使用している場合、**cli-binary-format** オプションは必須です。これをデフォルト設定にするには、`aws configure set cli-binary-format raw-in-base64-out` を実行します。詳細については、バージョン 2 の AWS Command Line Interface ユーザーガイドの「[AWS CLI でサポートされているグローバルコマンドラインオプション](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)」を参照してください。

   次のような結果が表示されます。

   ```
   {
       "StatusCode": 200,
       "ExecutedVersion": "$LATEST"
   }
   ```

1. レスポンスを確認してください。

   ```
   cat response.txt
   ```

   次のような結果が表示されます。

   ```
   Echoing request: '{"text":"Hello"}'
   ```

## レイヤーの作成
<a name="runtimes-walkthrough-layer"></a>

ランタイムコードと関数コードを区別するには、ランタイムのみを含むレイヤーを作成します。レイヤーを使用すると、関数の依存関係を個別に開発することができ、複数の関数で同じレイヤーを使用する場合には、ストレージの使用量を抑えることができます。詳細については、「[レイヤーによる Lambda 依存関係の管理](chapter-layers.md)」を参照してください。

1. `bootstrap` ファイルを含む .zip ファイルを作成します。

   ```
   zip runtime.zip bootstrap
   ```

1. [publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html?highlight=nodejs16%20x) コマンドを使用してレイヤーを作成します。

   ```
   aws lambda publish-layer-version --layer-name bash-runtime --zip-file fileb://runtime.zip
   ```

   これにより、最初のバージョンのレイヤーが作成されます。

## 関数の更新
<a name="runtimes-walkthrough-update"></a>

関数でランタイムレイヤーを使用するには、レイヤーを使用するように関数を設定し、関数からランタイムコードを削除します。

1. 関数設定を更新して、レイヤーに取り込みます。

   ```
   aws lambda update-function-configuration --function-name bash-runtime \
   --layers arn:aws:lambda:us-east-1:123456789012:layer:bash-runtime:1
   ```

   これにより、ランタイムが `/opt` ディレクトリの関数に追加されます。Lambda がレイヤーのランタイムを使用するようにするには、次の 2 つのステップに示すように、関数のデプロイパッケージから `boostrap` を削除する必要があります。

1. 関数コードを含む .zip ファイルを作成します。

   ```
   zip function-only.zip function.sh
   ```

1. ハンドラスクリプトのみ含まれるように関数コードを更新します。

   ```
   aws lambda update-function-code --function-name bash-runtime --zip-file fileb://function-only.zip
   ```

1. 関数を呼び出し、ランタイムレイヤーで正常に動作することを確認します。

   ```
   aws lambda invoke --function-name bash-runtime --payload '{"text":"Hello"}' response.txt --cli-binary-format raw-in-base64-out
   ```

   AWS CLI バージョン 2 を使用している場合、**cli-binary-format** オプションは必須です。これをデフォルト設定にするには、`aws configure set cli-binary-format raw-in-base64-out` を実行します。詳細については、バージョン 2 の AWS Command Line Interface ユーザーガイドの「[AWS CLI でサポートされているグローバルコマンドラインオプション](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)」を参照してください。

   次のような結果が表示されます。

   ```
   {
       "StatusCode": 200,
       "ExecutedVersion": "$LATEST"
   }
   ```

1. レスポンスを確認してください。

   ```
   cat response.txt
   ```

   次のような結果が表示されます。

   ```
   Echoing request: '{"text":"Hello"}'
   ```

## ランタイムの更新
<a name="runtimes-walkthrough-runtime"></a>

1. 実行環境に関する情報をログ記録するには、環境変数が出力されるようにランタイムスクリプトを更新します。  
**Example bootstrap**  

   ```
   #!/bin/sh
   
   set -euo pipefail
   
   # Configure runtime to output environment variables
   echo "##  Environment variables:"
   env
   
   # Load function handler
   source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh"
   
   # Processing
   while true
   do
     HEADERS="$(mktemp)"
     # Get an event. The HTTP request will block until one is received
     EVENT_DATA=$(curl -sS -LD "$HEADERS" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
   
     # Extract request ID by scraping response headers received above
     REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)
   
     # Run the handler function from the script
     RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA")
   
     # Send the response
     curl "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
   done
   ```

1. `bootstrap` ファイルの新しいバージョンを含む .zip ファイルを作成します。

   ```
   zip runtime.zip bootstrap
   ```

1. `bash-runtime` レイヤーの新しいバージョンを作成します。

   ```
   aws lambda publish-layer-version --layer-name bash-runtime --zip-file fileb://runtime.zip
   ```

1. 新しいバージョンのレイヤーを使用するように関数を設定します。

   ```
   aws lambda update-function-configuration --function-name bash-runtime \
   --layers arn:aws:lambda:us-east-1:123456789012:layer:bash-runtime:2
   ```

## レイヤーを共有する
<a name="runtimes-walkthrough-share"></a>

レイヤーを別の と共有するにはAWS アカウント、レイヤーの[リソースベースのポリシー](access-control-resource-based.md) にクロスアカウントアクセス許可ステートメントを追加します。[add-layer-version-permission](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/add-layer-version-permission.html) コマンドを実行し、アカウント ID を として指定します`principal`。アクセス許可は、各ステートメントで、1 つのアカウント、すべてのアカウント、または [AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_introduction.html) 内の組織に付与することができます。

以下の例では、アカウント 111122223333 に `bash-runtime` レイヤーのバージョン 2 へのアクセス許可を付与します。

```
aws lambda add-layer-version-permission \
  --layer-name bash-runtime \
  --version-number 2 \  
  --statement-id xaccount \
  --action lambda:GetLayerVersion \
  --principal 111122223333 \
  --output text
```

次のような出力が表示されます。

```
{"Sid":"xaccount","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::111122223333:root"},"Action":"lambda:GetLayerVersion","Resource":"arn:aws:lambda:us-east-1:123456789012:layer:bash-runtime:2"}
```

アクセス許可は、単一レイヤーバージョンにのみ適用されます。新しいレイヤーバージョンを作成するたびに、このプロセスを繰り返します。

## クリーンアップ
<a name="runtimes-walkthrough-cleanup"></a>

各バージョンのレイヤーを削除します。

```
aws lambda delete-layer-version --layer-name bash-runtime --version-number 1
aws lambda delete-layer-version --layer-name bash-runtime --version-number 2
```

バージョン 2 のレイヤーへの参照が関数で保持されているため、現在も Lambda に存在します。関数は引き続き動作しますが、削除したバージョンが使用されるように、参照を設定することはできません。関数のレイヤーのリストを変更する場合は、新しいバージョンを指定するか、削除したレイヤーを除外する必要があります。

[delete-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/delete-function.html) コマンドを使用して関数を削除します。

```
aws lambda delete-function --function-name bash-runtime
```