AWS AppConfig Lambda extensionでLambda関数の設定情報を取得する

#はじめに 
AWS Lambda extensionsのプレビューが発表されました。それに伴い、AWS AppConfigから利用可能なextensionが提供されLambda関数から利用することができます。本稿ではAWS AppConfig Lambda extensionをLambda関数から利用する方法について紹介します。

#AWS AppConfigとは
AWS AppConfigはAWS Systems Managerの機能の1つで、アプリケーション設定を作成、管理し、デプロイを可能にするサービスです。アプリケーションはAWS AppConfigのAPIをコールすることで、アプリケーション自体の再デプロイを行うことなく、外部設定を動的にデプロイすることができるようになります。また、AWS AppConfigは検証機能を提供しており、全ての設定変更について、アプリケーションに投入する前に安全にテストを行うことができます。AWS AppConfigについての詳細は[AWS AppConfig ユーザーガイド](https://docs.aws.amazon.com/ja_jp/appconfig/latest/userguide/what-is-appconfig.html)をご覧ください。

#AWS AppConfig Lambda extensionの動作
AWS AppConfig Lambda extensionの動作について説明します。AWS AppConfig Lambda extensionは、Lambda関数から見てAWS AppConfigのプロキシーの役割を果たします。

![AppConfig extensionの動作](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/1da4963c-25d8-457e-0232-9296ad82f1d0.png "AppConfig extensionの動作")

1. AWS AppConfig Lambda extensionをLambda関数のLayerとして構成します。

1. extensionはGetConfigurationリクエストをLambda関数から受け取り、ローカルキャッシュをチェックします。ローカルキャッシュの実態はローカルのHTTPサーバーです。

1. キャッシュが空なのでextensionはSDKコールの処理を実行してAWS AppConfigサービスを呼び出します。

1. サービスから設定情報を取得し、extensionは取得した設定情報をローカルキャッシュに保存した上で、Lambda関数に結果を返します。

1. extensionは後続のGetConfigurationへの呼び出しに対してローカルキャッシュの値を返します。AWS AppConfig Lambda extensionは設定情報のキャッシングと更新を管理し、Lambdaハンドラ実行をまたがって設定情報を保持します。設定情報が要求されると、Lambdaハンドラは
AWS AppConfigサービスを呼び出す代わりにAWS AppConfig Lambda extensionに対してリクエストを発行します。設定情報はローカルにキャッシュされているので、より高速にリターンし、AWS LambdaとAWS AppConfigのコストを削減することができます。

次にLambda関数が実行されたときに、extensionはAWS AppConfigから設定情報を取得してからの経過時間をチェックします。もし経過時間がポーリングの間隔よりも長ければ、extensionは最新の設定情報をAWS AppConfigから取得し、キャッシュを更新します。

AWS AppConfig Lambda extension自体に対する動作の設定はLambda関数に定義する以下の環境変数で行います。

|環境変数|詳細|デフォルト|
|:-:|:-:|:-:|
|AWS_APPCONFIG_EXTENSION_POLL_INTERVAL_SECONDS|extensionが設定情報を更新するためにAWS AppConfigをポーリングする間隔を秒数で指定|45|
|AWS_APPCONFIG_EXTENSION_POLL_TIMEOUT_MILLIS|extensionがキャッシュから設定情報を取得するときに待機する最大合計時間をミリ秒で指定|3000|
|AWS_APPCONFIG_EXTENSION_HTTP_PORT|extensionが実行するローカルHTTPサーバーのポート番号|2772|

#AWS AppConfig Lambda extensionの有効化
AWS AppConfig Lambda extensionを利用するにはLambda関数のLayerを追加し、LayerのARN(Amazon Resource Name)にAWS AppConfig Lambda extensionの対象リージョンのARNを指定します。AWS AppConfig Lambda extensionのリージョンごとのARNは以下のサイトで取得できます。

- [Adding the AWS AppConfig Lambda extension](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions.html#appconfig-integration-lambda-extensions-enabling)

#AWS AppConfig Lambda extensionの利用手順
それでは具体的にAWS AppConfig Lambda extensionの利用手順を説明します。

### Lambda関数の作成
まずはAWS AppConfig Lambda extensionを利用するLambda関数を作成します。
AWS Lambdaマネジメントコンソールで [Create function]ボタンをクリックします。
![Lambda関数の作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/1aace30d-ca3d-ffa7-c84e-0424a6d8a840.png "Lambda関数の作成")

Create functionのページで以下を実施します。

- [Author from scratch]を選択
-  Function nameに任意の名前を入力
- RuntimeにPython 3.8を選択
- [Create function]ボタンをクリック

![Lambda関数の作成入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/8f7a7847-c9b8-2b67-bcee-83a18a898071.png "Lambda関数の作成入力")

###Lambda Layerの追加
AWS AppConfig Lambda extensionはLambda Layerとして実行されます。Lambda関数がextensionを利用するためにLayerを追加します。作成したLambda関数のLambda ConfigurationタブでLayerを選択し、[Add a layer]ボタンをクリックします。
![Layerの追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/49b17c09-307c-9963-2e7e-03aa23e4e8eb.png "Layerの追加")

App layerのページで以下を実施します。

- Specify an ARNを選択
- [Adding the AWS AppConfig Lambda extension](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions.html#appconfig-integration-lambda-extensions-enabling) のサイトで対象リージョンのARNをコピーしSpecify an ARNに貼り付け
- [Add]ボタンをクリック

![Layerの追加入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/f8d3b79a-cf75-6139-9e74-db73f140bac1.png "Layerの追加入力") 

###Lambda実行ロールへ権限を追加
AWS AppConfig Lambda extensionがAWS AppConfigのGetConfiguration APIを呼び出すためにLambda関数の実行ロールにアクセス権限を追加する必要があります。そのため以下の手順でAWS AppConfigに対するアクセス権限を定義したポリシーを作成し、Lambda関数の実行ロールに作成したポリシーをアタッチします。

作成したLambda関数のPermissionsタブをクリックし、Execution roleのリンクをクリックします。

![実行ロールへの権限追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/98d429a7-3338-c77b-b29d-a48cd3b9f896.png "実行ロールへの権限追加")

IAM RoleのSummaryのページで[Attach policies]をクリックします。

![ポリシーを追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/25fe4b06-c01d-ef91-4ab9-6d31d4debe22.png "ポリシーを追加")

Add permissionsの画面で[Create policy]をクリックします。

![ポリシーを作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/8b7fbd33-17c3-64c2-af66-b6524ceb6623.png "ポリシーを作成")

AppConfigを選択します。

![AppConfigを選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/ffde6b91-18aa-cb5d-4286-edd97cb9baed.png "AppConfigを選択")

Actionsを開き、GetConfigurationをチェックします。

![アクションの指定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/a4261805-531b-93e0-55fd-06db6117c3d0.png "アクションの指定")

Resourceを開き、All resourceを選択して[Review policy]ボタンをクリックします。

![リソースの指定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/0da22e6b-a440-b1d4-f59d-fdc9ffe21939.png "リソースの指定")

Review PolicyのページでNameに任意のポリシー名を入力し[Create policy]ボタンをクリックします。

![ポリシーの作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/2e3d0af2-4b4e-d4be-95f5-d34aebba31a5.png "ポリシーの作成")

Add permissionsのページに戻ったら、作成したポリシーを選択し[Attach policy]ボタンをクリックします。

![ポリシーのアタッチ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/fc0c0ea4-d1db-2a2a-9b16-f97224ac702b.png "ポリシーのアタッチ")


#Lambda関数の実装
次にLambda関数を実装します。LambdaマネジメントコンソールのFunction codeの内容を以下のサンプルソースで置き換えます。

```python
import json
import urllib.request
import os

appConfigApplication = os.getenv("APPCONFIG_APPLICATION", "extension-demo-app")
appConfigEnvironment = os.getenv("APPCONFIG_ENVIRONMENT", "dev")
appConfigConfigProfile = os.getenv("APPCONFIG_CONFIGPROFILE", "demo-app-config")

def lambda_handler(event, context):
    rate = int(get_winning_rate() * 100)

    return f'current winning_rate {rate}%'

def get_winning_rate():
    try:
        url = f'http://localhost:2772/applications/{appConfigApplication}/environments/{appConfigEnvironment}/configurations/{appConfigConfigProfile}'
        config = json.loads(urllib.request.urlopen(url).read())
        print(config)
        return config.get("winning_rate", 0)
    except:
        return 0

```

このLambda関数はアプリケーションの設定情報から当選確率を取得して返すだけのシンプルな処理ですが、AWS AppConfig Lambda extensionの使い方が理解できるかと思います。サンプルソースの中のget_winning_rate関数内の以下のコードがextensionのローカルHTTPサーバーを呼び出している部分になります。

```Python
url = f'http://localhost:2772/applications/{appConfigApplication}/environments/{appConfigEnvironment}/configurations/{appConfigConfigProfile}'
config = json.loads(urllib.request.urlopen(url).read())
```


###環境変数の登録
コードの再利用を容易にするためにLambda関数が利用する環境変数を追加します。環境変数にAppConfigの情報を設定することで、AppConfig Lambda extensionを利用するアプリケーションでコードをそのまま利用できます。AppConfig Lambda extensionのローカルHTTPサーバーのポートを変更するなどのextensionに対する設定が必要な場合は、上の表に示した環境変数も追加します。

![環境変数の追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/783747bf-6d2c-f926-bc74-4068a82839c1.png "環境変数の追加")

#AWS AppConfigのアプリケーション設定情報の作成
それではアプリケーションの設定情報を保持するAWS AppConfigに設定情報を作成しましょう。AWS AppConfigはアプリケーションの設定情報をAmazon S3オブジェクト、AWS Systems Manager Document Storeのドキュメント、AWS Systems Manager Parameter Storeのパラメータ、AWS CodePipelineのソースとして保存することができますが、今回はAWS AppConfigのホストするストアに保存することにします。

AWS AppConfigのホストするストアには、YAML、JSON、テキストドキュメントが利用可能ですが、今回はJSONで設定情報を保存するようにします。

###AWS AppConfigのアプリケーション設定情報作成手順
AWS Systems Managerマネジメントコンソールの左側のペインでAppConfigを選択し、表示されたページの[Create application]ボタンをクリックします。

![アプリケーションの作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/7a7d258c-9e08-dd81-4870-4fa8d699f3f2.png "アプリケーションの作成")

Create applicationのページで、NameとオプションでDescriptionを入力し[Create application]ボタンをクリックします。

![アプリケーション作成入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/029bba34-74b9-6d2e-0b0f-b3de64b431b7.png "アプリケーション作成入力")

次に作成したアプリケーションのページで[Create environment]ボタンをクリックします。

![環境の作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/47db3f5f-51bc-6e2f-7693-69e31c8c928d.png "環境の作成")

Create environmentのページで、NameとオプションのDescriptionを入力し[Create environment]ボタンをクリックします。

![環境の作成入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/7f3d016e-a834-88bc-9284-228caa409f3c.png "環境の作成入力")

アプリケーションのページに戻り、[Configuration profile]タブをクリックし[Create configuration profile]ボタンをクリックします。

![設定プロファイルの作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/95345495-1324-2a15-1a7f-1226d41b2bb0.png)

Build configuration profileのページで以下を実施します。

- Nameを入力
- オプションでDescriptionを入力
- Configuration sourceでAWS AppConfig hostedを選択
- ContentでJSONを選択し以下の値を入力

```json
{
  "winning_rate": 0.1
}
```
- [Next]ボタンをクリック
- Add ValidatorページでJSON Schemaを選択
- 以下のJSONスキーマを入力

```json
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "winning_rate": {
      "type": "number",
      "minimum": 0,
      "maximum": 1
    }
  },
  "required": [
    "winning_rate"
  ]
}
```

- [Create configuration profile]ボタンをクリック

![設定プロファイルの作成入力1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/53ab7230-c35f-ced3-c96d-4a8114423a77.png "設定プロファイルの作成入力1")
![設定プロファイルの作成入力2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/69787aeb-f7c3-9731-6a50-2e5e31e3b40a.png "設定プロファイルの作成入力2")
![設定プロファイルの作成入力3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/c65168a9-c7f4-29ac-9072-cd0d39891678.png "設定プロファイルの作成入力3")

###AWS AppConfigのアプリケーション設定情報をデプロイ
作成したアプリケーション設定情報をデプロイします。右上の[Start deployment]ボタンをクリックします。

![デプロイの開始](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/ad46eccd-c6d6-4c09-7969-2a23fc3d8772.png "デプロイの開始")

Start deploymentページで以下を実施します。

- Environmentに作成した環境を指定
- Hosted configuration versionに１を指定
- Deployment strategyに[AppConfig.AllAtOnce(Quick)]を選択
- オプションでDeployment descriptionを入力
- [Start deployment]ボタンをクリック

![デプロイの開始入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/637a8d8d-f0de-23ae-8814-4a2818f8fd69.png "デプロイの開始入力")

デプロイが開始されます。

#設定情報の取得
Lambdaマネジメントコンソールに戻り、作成したLambda関数を選択します。[Test]ボタンをクリックし、最初に表示されるテスト用パラメータに任意の名前を入力し保存します。（このパラメータは利用しません）
[Test]ボタンをクリックしてLambda関数を実行し出力結果を確認します。

![Test実施1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/9b29b218-1ce4-f8b0-2fa5-b034b7e59cfb.png "Test実施1")
![Test実施2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/977efe5d-b25b-3cd5-4dd1-e1be5575a159.png "Test実施2")

###アプリケーション設定情報を変更し反映されることを確認
AWS AppConfigマネジメントコンソールに戻り、作成したConfiguration Profileを選択し、Hosted configuration versionsで[Create]ボタンをクリックします。アプリケーション設定情報の新しいバージョンを作成し、パラメータの値を設定します。

![新バージョン作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/aa5661a5-9644-6920-e6a6-699988977c8f.png "新バージョン作成")

ContentでJSONを選択し、パラメータの値を変更し、[Create hosted configuration version]ボタンをクリックします。

![バージョン作成入力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/a1f4d9a2-c2a3-49ec-eb55-7fdf9fa2258e.png "バージョン作成入力")

再度[Start deployment]をクリックしデプロイメントを再実行します。

![デプロイ再実行](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/46e78d2d-a795-11db-1891-6854a0456752.png "デプロイ再実行")

AWS Lambdaマネジメントコンソールに戻り[Test]ボタンをクリックしてLambda関数を実行し結果を確認します。AWS AppConfig Lambda Extensionが設定情報を更新するためにAWS AppConfigをポーリングする間隔はデフォルトで45秒なので値が更新されていない場合は少し待って再度実行してください。

![Functions_-_Lambda28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83238/9c15a217-eb96-2dab-9877-649fb7b48820.png)

#まとめ
AWS Lambda extensionsのプレビュー発表に伴って利用可能となったAWS AppConfig Lambda extensionの利用方法を紹介しました。AWS AppConfig Lambda extensionを利用するメリットの一つとしてアプリケーション設定情報をLambda関数と独立してデプロイできることが挙げられます。例えばLambda関数の環境変数を変更した場合はLambda関数が再度デプロイされてコールドスタートとなりますが、AWS AppConfig Lambda extensionを利用することでコールドスタートすることなくアプリケーションの設定情報を更新することができます。

またAWS AppConfigを利用する場合、GetConfiguration APIの呼び出し、及びその結果取得する設定情報に対して利用料金が発生します。AWS AppConfig Lambda extensionは、アプリケーション設定情報をローカルにキャッシュすることでAPI呼び出しの頻度を抑え、かつキャッシュから値を返すことで、Lambda関数の処理速度も向上し、Lambda関数の実行時間に対する料金も抑える効果が期待できます。

本稿がLambda関数を開発される開発者の皆さんにとって役立つものとなれば幸いです。