のーずいだんぷ

主に自分用メモですが、もしかしたら誰かの役に立つかもしれません

Python のサーバレスwebフレームワークのchaliceのconfig.jsonで設定できることをまとめた

chaliceとは?

AWSが製作したサーバレスwebフレームワーク。 コードベースはPythonで、フレームワークとしての作りはFlaskに近い。 主な特徴としては、高速にREST APIが製作可能なことで詳しく書くと以下のような感じ。

python系のwebフレームワークはデコレータでルーティングを設定するが、chaliceの場合はそれがAPIGatewayの設定となり、 APIGatewayやLambdaについて意識しなくても、webフレームワークとしても機能を書いていけば同時にアーキテクチャのコードを書いていることになる。 その他の利点としてはコードを解析してIAMロールを自動生成&アタッチまでしてくれるという神機能もある。

またCodeDeploy等の連携によって容易にCI環境を構築できることや、localサーバ機能もあるのでフロントエンドのようにテストをしながらインタラクティブな開発ができる。 (おそらく自動テストも可能なので、これもそのうち記事を書く)

chaliceは非常にシンプルなCLIを持っており、コードもflaskのように簡潔に書けて高速でデプロイできるのが特徴であるが、 一部API Gateway とLambdaに関して設定は設定ファイルを通して設定する必要があり、ドキュメント以外に言及している記事が見当たらなかったためまとめておく。 今回はchaliceでREST APIを作成しようする際の設定を意識して書く。

※注意書き 以下で紹介するコードはchaliceの公式リファレンスを出典としているものがある。 説明については原文は英語なのでそれっぽく翻訳している。

ざっくりまとめ

API Gateway とLambdaそれぞれ以下が設定可能


API Gateway
  • IAMロールの自動生成可否
  • ステージ
  • デプロイステージ
  • エンドポイントのタイプ

Lambda
  • メモリ
  • 同時実行数
  • Lambda Layer
  • VPC,subnet,security-group
  • IAMロール

正直どちらともまだまだ設定できることはあるので、完全に手放しでできるかというと微妙なところ。 シンプルさを売りにしている(と私は思っているので)ところはその通りで、これから記載する設定がなくてもとりあえずデプロイすることはかなり簡単にできる。 特にAPI Gatewayは初学者の方には複雑なので、一旦chaliceでデプロイして使えるAPIとAPIGatewayの設定を比較することで理解の助けになると考えている。

ディレクトリ構成(設定ファイルの場所)

以下はCLIchalice new-project時に生成される最小構成のディレクトリ。

$ tree -a
.
├── .chalice
│   └── config.json
├── app.py
└── requirements.txt

.chalice/config.jsonが目的の設定ファイル記述する。

設定内容

chaliceのconfig.jsonのスキーマは単純で、ステージを分けたりすることを考えなければ全部同じレベルで記載できる。 PRIVATEなエンドポイントタイプは使用したことがないので説明にちょっと不正確な可能性がある… 各項目について簡単に説明すると以下の示すとおり。


  • app_name:APIGatewayのリソースネームとして使用される。lambda関数名前のベースとしても使用される。(Chaliceインスタンスを生成したときにappに渡した名前でもあり、プロジェクト作成時にここは自動記入される。)

  • stages:APIGatewayのリソース単位を指す。APIGatewayの名前自体に変更はないが、lambda関数の名前の末尾に付加される。(ステージを分けるとコンソール上では一覧で同じ名前のAPIが2つ見えてしまう)

  • api_gateway_endpoint_type:API Gatewayのエンドポイントタイプ。REGIONAL|PRIVATE|EDGEのいずれかになる。国内での使用であればREGIONAL、SPA等の内部APIならPRIVATE、国外からもアクセスがあるなら、EDGEにすると良い。

  • api_gateway_endpoint_vpce:api_gateway_endpoint_typePRIVATEにしたときに設定する。VPCのリソースポリシーをendpointのIDの文字列もしくはその配列で指定する。

  • api_gateway_stage:AP Gateway内でデプロイするステージ名になる。API Gatewayデプロイ後自動的に生成されるURLに対してこの名前のパスをベースパスとして指定することで同一ステージ内のAPIへのリクエスト先を判別する。

  • api_gateway_policy_file:REST APIのためのIAMリソースポリシーを指す。api_gateway_endpoint_typePRIVATEのときにchaliceはファイルを自動生成する。このデフォルト値は.chaliceディレクトリに関連付けられている。

  • autogen-policy:booleanで指定する。値がtrueの場合、コードを解析して適切なIAMロールを作成、アタッチする。falseの場合、デフォルトでは.chalice/policy-<stage>.jsonを使用する。deployコマンドのオプションでも指定可能。自動IAMロール生成はchaliceの目玉のひとつなので、シンプルなDBアクセス等に使用するAPIならばこの項目はおそらくtrueにしておくのが普通。

  • environment_variables: lambda関数に使用する環境変数をmap型で設定する。

  • iam_policy_file:autogen_policyがfalseなら、デフォルトで.chalice/policy-<stage>.jsonを使用する。この項目を指定すると、読み込むpolicyファイルを指定することができる。

  • iam_role_name: manage_iam_role`がfalseの場合のときのみ使用され、既存のIAMロールのARNを必ず指定する必要がある。

  • lambda_memory_size:lambda関数のメモリをint型でしているdefault値は128MBで、値は64MBの倍数にする必要がある。

  • lambda_timeout: lambdaのタイムアウトまでの時間を秒で設定する。デフォルトは60秒で最大9000秒まで設定可能だが、REST APIとして使用する場合はAPIGatewayが29秒でタイムアウトするので実際はそこまでしか意味がない。

  • layer:lambda layerのARNを指定する。

  • manage_iam_role: IAMロールを新規作成するかどうかをbooleanで指定する。デフォルトはtrue。falseの場合はiam_role_nameを指定しないといけない。

  • minimum_compression_size: api gatewayの設定で、最小の圧縮サイズを示す。

  • reserved_concurency: lambdaの同時実行予約数の設定。この値が0の場合、lambdaは実行されなくなる。セットしなければデフォルト値の同時実行数は予約しない設定になる。

  • subnet_ids: VPCに配置してあるサブネットのうちどのサブネットを使用するか指定する。この値を有効にするにはsecurity_group_idsも設定する必要がある。autogen-policyがtrueの場合、chaliceは自動でENIの作成に必要な権限を作成(更新)する。

  • security_group_ids:VPC使用時の設定。subnets_ids`と一緒に有効にする必要がある。

  • tags:タグを指定する。マップ型で指定する。


設定を分ける方法

API Gatewayのstage毎に設定を分ける

設定はstage毎に作成することができる。 chaliceのstageを分けるということは、それらのAPIが別のドメインとなることを意味する(もしくはARNレベルで分割する) 具体的には以下のような具合だろう

{
  "version": "2.0",
  "app_name": "app",
  "stages": {
    "dev": {...},
    "prod":{...}
    }
  }
}

まず設定の基本として、 stages{}内に... 含める->個々のステージに個別の設定される 含めない->グローバルな設定(全ステージ共通設定)となる。 上記の例ではdevとprodがステージで、そこは個人で任意の名前にする。 基本的にすべての項目はグローバルとして設定でき、トップレベルとステージレベルの両方が設定されている場合、ステージレベルのほうが使用される。 ただし、環境やタグについてはマージされて、重複したキーのみがステージレベルで上書きされる。

またlambdaもステージと同様に、lambdaの設定に関する部分は個々のlambda関数ごとに設定できる。 (ただし、以下でも説明するがREST APIの作成時は、おそらく@app.routeといったルーティングデコレータを各関数に対してつけていくこととなるが、その場合生成されるlambda関数は1つのみなので大体ステージごとに設定を分けることで十分であると思う。)

Lambda関数ごとに設定を分ける

同設定ファイル内ではstageより更に細かいレベルとして、lambda関数毎に設定が可能。 例えば以下のようにする。

{
  "version": "2.0",
  "app_name": "app",
  "stages": {
    "dev": {
      "lambda_functions": {
        "foo": {
          "lambda_timeout": 120
        }
      }
    }
  }

この場合lambda_functionキーで指定されたlambda関数に対して設定が個別に設定が適用される。(この場合はfooがlambda関数の名前) デプロイするステージに共通のlambdaステージとして設定する場合は、トップレベルに当該キーを設定する。

{
  "version": "2.0",
  "app_name": "app",
  "lambda_functions": {
    "foo": {
      "lambda_timeout": 120
    }
  }
}

以下が、 当該キー内で設定できる属性となる。

  • autogen_policy
  • environment_variables
  • iam_policy_file
  • iam_role_arn
  • lambda_memory_size
  • lambda_timeout
  • layers
  • manage_iam_role
  • reserved_concurrency
  • security_group_ids
  • subnet_ids
  • tags

例外としてREST APIのlambda関数は名前が決まっている

どういうことか? 先程の例のlambda関数は、以下のようにしてchaliceアプリ内で作成することを指示できす。

@app.lambda_function()
def foo(event, context):
    pass

しかし、例外として@app.route()を使用した場合は、単一のlambdaをAPIGatewayを指定させてデプロイさせることができる。

@app.route('/')
def index(): pass

@app.route('/foo/bar')
def other_handler(): pass

上記の例外の場合の設定は、以下のようにapi_handerをキーとして設定する。

{
   "lambda_functions": {
     "api_handler": {
       "subnet_ids": ["sn-1", "sn-2"],
       "security_group_ids": ["sg-10", "sg-11"],
       "layers": ["layer-arn-1", "layer-arn-2"],
     }
   }
 }

簡単な例

REST APIを作ってみて、こんな設定が必要になった。

{
  "version": "2.0",
  "app_name": "sample-api",
  "stages": {
    "dev": {
      "api_gateway_endpoint_type": "REGIONAL",
      "api_gateway_stage": "dev",
      "autogen_policy": false,
      "iam_policy_file": "iam_policy_file_common.json",
      "lambda_memory_size": 1024,
      "lambda_timeout": 30,
      "manage_iam_role": true,
      "tags": {
        "project": "chalice-sample"
      }
    },
  }
}

上記はdev環境の設定のみで、リージョナルなAPIを使用した。 先程説明した自動IAMロール生成機能はfalseにしているが、これは@app.routeをつけなかったboto3(Python3のAWS-SDK)を使用した関数のIAMポリシーに関しては付与されなかったため、自分であらかじめIAMを作成している。 なお、iam_policy_fileに指定しているIAMポリシーのjsonファイルは上記でも説明しているが、.chalice/ディレクトリに保存するのが良い。 他にも公式リファレンスで説明されている例を紹介する。

IAMの設定方法3種類

{
  "version": "2.0",
  "app_name": "app",
  "stages": {
    "dev": {
      "autogen_policy": true,
      "api_gateway_stage": "dev"
    },
    "beta": {
      "autogen_policy": false,
      "iam_policy_file": "beta-app-policy.json"
    },
    "prod": {
      "manage_iam_role": false,
      "iam_role_arn": "arn:aws:iam::...:role/prod-role"
    }
  }
}

上記の例では3種類のステージdev,beta,prodを設定しているがそれぞれの設定は以下のようになる。

  • dev -> コードを解析してIAMポリシーを自動で生成される。
  • beta -> IAMロールの自動生成はしない。iam_policy_jsonに指定したpolicy設定で新しくIAMロールを生成する。
  • prod -> IAMロールをそもそも新規作成せず、既に作成済みのIAMロールを使用する。

環境変数の設定例

{
  "version": "2.0",
  "app_name": "app",
  "environment_variables": {
    "SHARED_CONFIG": "foo",
    "OTHER_CONFIG": "from-top"
  },
  "stages": {
    "dev": {
      "environment_variables": {
        "TABLE_NAME": "dev-table",
        "OTHER_CONFIG": "dev-value"
      }
    },
    "prod": {
      "environment_variables": {
        "TABLE_NAME": "prod-table",
        "OTHER_CONFIG": "prod-value"
      }
    }
  }
}

上記のような設定の時、dev/prodそれぞれの環境変数は…

//dev
{
  "SHARED_CONFIG": "foo",
  "TABLE_NAME": "dev-table",
  "OTHER_CONFIG": "dev-value",
}
//prod
{
  "SHARED_CONFIG": "foo",
  "TABLE_NAME": "prod-table",
  "OTHER_CONFIG": "prod-value",
}

見て分かる通り SHARED_CONFIG -> 重複していないのでトップレベルの値が使用されている。 TABLE_NAMEOTHER_CONFIG -> 各ステージで定義した値が使用されている。

これから色々試してまた補足しようと思う。 誤り等あればご連絡いただきたい。

近いうちchaliceで作成するSPAの記事書きます!!

参考

chalice.readthedocs.io