はじめに
サーバーレスアプリケーション(以後SLA)の開発のためのフレームワークServerlessを使って、nodejsベースのAWS Lambda上で動く関数作成からデプロイまでやります。公式のQuick startが微妙だなと思ったので、備忘録として書いておきます。
なぜSLA開発にフレームワークを使うのか
コードの変更はローカルで、ビルドはEC2やDockerで、デプロイはS3で、ハンドラの設定はLambdaで、APIの設定はAPI Gatewayで、ログの確認はCloudWatchで、という開発プロセスは辛いので、自前で開発環境を整えるか、フレームワークを使ったほうが良いと思うからです。
小規模なアプリケーションだったり、一回書いておしまいということであれば、Lambdaのインラインエディタとテスト機能だけで用が済むかもしれません。しかし、アプリケーションが少し大きくなったり、少し手の込んだことをしようとするだけで、SLA開発の性質や、Lambdaの制限によって、CI/CDのコストが跳ね上がります。例えば、
- コード中で外部のパッケージを利用する場合、デプロイが辛くなる。関数ファイルと外部パッケージをzipしてLambdaにアップロードする必要がある
- その場合、Lambdaと開発環境をそろえようと思うと、EC2やDockerを利用することになる
- アップロードするzipファイルサイズが3MBを越えた場合、インラインエディタで編集できなくなる
- zipファイルサイズが10MBを越えた場合、コードを変更するたびにzipファイルをS3にアップロード -> S3からLambdaにインポートという手順を踏む必要がある
Serverlessを使うことによって、
-
sls deploy
コマンドだけでデプロイができる - 裏側でCloudFormationのスタックを利用することによって、S3とLambdaのコードの管理だけでなく、APIやデータベースの設定も一括してやってくれるので、開発に一貫性が生まれる
というメリットがあると思います。
流れ
- IAM Policyの作成
- IAM Userの作成
- .aws/credentialsの編集
- Serverlessのインストール
- serverless.ymlの編集
- デプロイ
まず、ServerlessのプロジェクトがAWS上のサービスを利用するための権限が必要です。必要な権限のセット(IAM Policy)を持ったAWSユーザー(IAM User)のcredentialをプロジェクトにひもづけてやる必要があります。これがIAM PoicyとIAM Userの作成にあたります。
次に、ひもづけるcredentialは、serverless.ymlの中にベタ書きしたくないので、ローカルの .aws/credentialsの中で管理します。
そして、serverless.ymlで.aws/credentials内の目的のcredentialを参照するよう設定します。その他、AWSリージョンや関数名、nodejsのバージョンの設定などを行い、デプロイします。
注意点
- 公式のQuick startにある設定動画は古いし、ちゃんとしてないのであてにならない
- AdministratorAccessを献上する必要はない
IAMでカスタムポリシーの作成
ServerlessのGithub上のQuick startでは、AdministratorAccessのポリシーを持ったIAMユーザーのcredentialをセットするように言われているのですが、AdministratorAccessを献上するのはあまり良い気分はしないですよね。別のところでは、公式にこう言われています。
In a production environment, we recommend reducing the permissions to the IAM User which the Framework uses. Unfortunately, the Framework's functionality is growing so fast, we can't yet offer you a finite set of permissions it needs (we're working on this). Consider using a separate AWS account in the interim, if you cannot get permission to your organization's primary AWS accounts.
(https://github.com/serverless/serverless/blob/master/docs/providers/aws/guide/credentials.md)
今回は、ガチガチに管理するわけでもないけど、AdministratroAccessよりは限定して、かつLambdaへのデプロイに十分なカスタムポリシーを作ります。AWSの他のサービスも使う場合は、それに応じてActionに追加します。
AWSのコンソールから、
IAM
-> Policies
-> Create policy
-> JSON
タブ
と進み、以下のような形に変更します。S3、Lambdaなど、サービスは限定しつつ、それぞれのサービスのアクションについてはワイルドカードにして限定しない形です。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt20180730",
"Effect": "Allow",
"Action": [
"s3:*",
"logs:*",
"iam:*",
"apigateway:*",
"lambda:*",
"cloudformation:*",
"events:*"
],
"Resource": [
"*"
]
}
]
}
"Sid"
は自分が識別しやすいように、任意のIDを入れます。ガチガチにしたいなら、"Action"
や"Resource"
をもっと限定します。でも個人使用では、これぐらいが手軽に管理しやすい落とし所のような気がします。
-> Review policy
-> Name
にServerlessFrameworkBasic
と入力
-> Create policy
で完了です。
IAM Userの作成
AWSコンソールで、
IAM
-> Users
-> User name
にmy-app-user
と入力
-> Programmatic access
にチェックを入れる
-> Next:Permissions
-> Attach existing policies directly
-> 先程作成したServerlessFrameworkBasic
をポリシーの中から検索してポリシー名左にチェックを入れる
-> Next:Review
-> Create user
-> Download .csv
でcredentialをダウンロードしておく
ここで表示されている Access key ID
とSecret access key
はあとで使います。
.aws/credentialsの編集
作成したIAM Userのcredentialをローカルの~/.aws/credential
にテキストエディタで追加します。なかったら作ります。 serverless
コマンドで入れることもできるようですが、コマンドの中に直接アクセスキーを入れるのはおすすめしないです。
[任意のプロファイル名]
aws_access_key_id = 先程のAccess key IDをここに入れる
aws_secret_access_key = 先程のSecret access keyをここに入れる
例えば、こんな感じになります。すでに他のcredentialがある場合は、それを上書きするのではなく追加します。
[default]
aws_access_key_id = ...
aws_secret_access_key = ...
[my-app-user]
aws_access_key_id = 1234567890ABCDEFGHIJ
aws_secret_access_key = 1234567890abcdefghijklmnopqrstuvwxyzABCD
[another-credential]
aws_access_key_id = ...
aws_secret_access_key = ...
ただし、AWS CLIを使っていて、ここで用いるプロファイルが、AWS CLIでデフォルトで使用されているものと異なる場合、後々お気をつけください。参考までに、公式ではこう言われています。
Be aware! Due to the way AWS IAM and the local environment works, if you invoke your lambda functions locally using the CLI command serverless invoke local -f ... the IAM role/profile could be (and probably is) different from the one set in the serverless.yml configuration file. Thus, most likely, a different set of permissions will be in place, altering the interaction between your lambda functions and other AWS resources.
Serverlessのインストールとプロジェクトの作成
nodejsは入っている前提です。2018/07/30現在、AWS Lambdaでサポートされているnodejsのバージョンは主に6.10と8.10なので、8.10を入れておくと、ちょっとしたことをnodeコンソールで試せて便利だと思います。今回serverlessはグローバルにインストール、プロジェクトのルートディレクトリはホームディレクトリ直下に作るとします。
npm i -g serverless
# cd ~ && sls create -t aws-nodejs -p プロジェクト名
cd ~ && sls create -t aws-nodejs -p my-app
プロジェクトのルート・ディレクトリを見ると、handler.js
とserverless.yml
ができているのが確認できると思います。
ls ~/my-app
# => handler.js serverless.yml
serverless.ymlの編集
最低限必要な記述はこんな感じです。serverless.ymlのリファレンスを見ると良いと思います。
service:
name: プロジェクト名
provider:
name: aws
runtime: nodejsのバージョン
profile: credentialのプロファイル名
region: リージョン
functions:
関数名:
handler: handler.関数名
例えば、
- プロジェクト名はmy-app
- 先程作成した my-app-user
のcredentialを使う
- Lambdaのnodejsのバージョンは8.10
- 以下の様なhandler.js
を持っている
'use strict';
module.exports.main = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
}),
};
callback(null, response);
};
とすると、serverless.yml
はこうなります。
service:
name: my-app
provider:
name: aws
runtime: nodejs8.10
profile: my-app-user
region: ap-northeast-1
functions:
main:
handler: handler.main
注意したいところは、
- stage
はdev
がデフォルト。デプロイ時にLambda上では関数名にstage名がsuffixされる。
- nodejsのバージョンは6.10
がデフォルトで記述されているので、8.10
を使用する場合は、見間違えずに変更する。
- region
はus-east-1
リージョンがデフォルト。デプロイ時にCloudFormationのStackがus-east-1で作成されるので、使用するリージョンがus-east-1でない場合はちゃんと指定しないとエラーが起きる可能性がある。
デプロイ
cd ~/my-app
sls deploy -v
いまのところ、v
(verbose)オプションの有無で出力があまり変わらないので、sls deploy
だけでも良いと思いますが、Starck Outputs
を確認したいときはつけても良いと思います。
参考
https://github.com/serverless/serverless
https://serverless.com/framework/docs/providers/aws/guide/serverless.yml/