hachiNote

勉強したことをメモします。

「初めてのサーバーレスアプリケーション開発」の記事を見て学んでみた

目的

私は現時点でクラウドサービスを使った開発について何も知らず、AWSも何も知らない状態です。でもなんか勉強してみないとなということで、ひとまずなんとなく目に入ったDynamoDBとやらについて学んで見ようと検索してみたところ、Developers IOの以下の記事が見つかりました。この記事はDynamoDBに関してのリンク集みたいな感じになっていてとても参考になります。

dev.classmethod.jp

その中にある「初めてのサーバーレスアプリケーション開発 ~DynamoDBにテーブルを作成する~」というのが手を動かして学べる感じになっていたので主にこちらの記事に則って学んでいくことにしました。全5回の記事です。

dev.classmethod.jp

この5つの記事をやってみて、ちょっとつまづいたところなどをメモします。

「初めてのサーバーレスアプリケーション開発 ~DynamoDBにテーブルを作成する~」をやってみたメモ

初めてのサーバーレスアプリケーション開発 ~DynamoDBにテーブルを作成する~ | DevelopersIO

感想

ひとまずテーブル名とプライマリキーさえ決めればテーブルは作れるようだ。プライマリキーとしてはパーティションキーというのが必須で、あとはソートキーというのも指定できるみたい。どちらのキーにも該当しないキーをテーブルにいきなり突っ込んでも問題ないようで、その辺はNoSQLだからなのかな。MongoDBでもそうっぽかったし。

つまづいたところ

手順的につまづいたところは特になかった。

「初めてのサーバーレスアプリケーション開発 ~LambdaでDynamoDBの値を取得する~」をやってみたメモ

初めてのサーバーレスアプリケーション開発 ~LambdaでDynamoDBの値を取得する~ | DevelopersIO

感想

Lambdaって断片的なコードを書いただけで後はリクエストがあったらそれが実行されるわけですが、「実行されるってどうやって? サーバや実行環境はどこにあってどうなっているのか?」と思ってました。最近Dockerをちょっと勉強していたんですが、もしかしてこういうのってコンテナ技術を使って都度実行を実現しているのかな。

使用する言語はてっきりNode.js一本かと思ったら、記事ではPython使ってました。PythonってAIのコード書くときに使うものだと思ってたんですが、サーバ側でも使うんですね。

つまづいたところ

手順的につまづいたところは特になかった。

「初めてのサーバーレスアプリケーション開発 ~API GatewayからLambdaを呼び出す~」をやってみたメモ

初めてのサーバーレスアプリケーション開発 ~API GatewayからLambdaを呼び出す~ | DevelopersIO

感想

LambdaとAPI Gatewayがなぜ別々になっているのか、一緒でもいいんじゃないかと思ったりしてましたが、Lambdaを実行するきっかけとしてはWeb API以外にもあるってことなのかな。APIごとにセキュリティ的な設定もできるみたいだし、確かに分かれていた方が設計的に汎用性が高そうです。「本文マッピングテンプレート追加」あたりは用語があまり理解できていない部分がありますが、とりあえず目的の動作はできました。

つまづいたところ

多分AWSのサービスが年々更新されていく事によって、記事内にある画面が今は違ってきているところがありましたが、よく見ればわかる程度で大丈夫でした。

「初めてのサーバーレスアプリケーション開発 ~Serverless Framework を使ってAWSリソースをデプロイする~」をやってみたメモ

初めてのサーバーレスアプリケーション開発 ~Serverless Framework を使ってAWSリソースをデプロイする~ | DevelopersIO

感想

Serverless Frameworkというフレームワークを使うことによって、これまで画面上で1つずつ作っていたAPI Gateway、Lambda、DynamoDBの設定をCLIベースでデプロイできる、つまり設定をコード化できる。ただ、急にCloudFormationという言葉が出てきたのでそこが少し混乱しました。デプロイしたらAPI Gateway、Lambda、DynamoDBにそれぞれ設定が出来上がるだけと思っていたら、CloudFormationってサービスのところにスタックというやつが現れて、API Gateway、Lambda、DynamoDBはスタックに紐づくリソース?という形になっているんですよね。ちょっとこのスタックというやつの概念はまだ理解できていません。ただ取りまとめているやつがいることで、それぞれのサービスをバラバラで管理するんじゃなくてアプリケーションの単位で管理できるし一括でremoveできるから便利だよねというのはわかります。

Cloud9というのはIDEがブラウザ上で使えるってだけじゃなくて、Linuxとかの環境ごとクラウドに用意して使うってことなんですね。なので、npm installしたりしたらそれがそのまま残っているので便利です。ただ環境作ってそのままにしておくとEC2の使用料金がかかってくるみたいです。後で消しておかないと。個人で開発するなら、自分のマシン上に環境作った方が良さそう。

つまづいたところ

記事内でデプロイコマンドとして sls deploy -v と書かれていましたが、これだとバージョン表示されるだけでデプロイできませんでした。 -v なしでいけました。

それから、 sls invoke -f hello としてLambdaファンクションを実行できるんですが、これはデプロイされたクラウド上にあるやつが実行されるのか、Cloud9上で動いているだけなのかいまいちよくわからなかった。 こちらの記事によると、ローカルで実行するには sls invoke local コマンドを使うようなのでクラウド上のやつが実行されてことは間違いないとは思います。ただ本当にクラウド上で実行されたことの確証というかログみたいなのが見つけられなかったのでちょっと心残り。 今から始めるServerless Frameworkで簡単Lambda開発環境の構築 | DevelopersIO

後は sls invoke -f hello などを実行したときに

1 deprecation found: run 'serverless doctor' for more details

と表示されることがあり、ちょっと気になってました。言われるがままに serverless doctor コマンドを打ってみる。

Administrator:~/environment/demo-service $ severless doctor
bash: severless: command not found
Administrator:~/environment/demo-service $ serverless doctor
1 deprecation triggered in the last command:

Starting with version 4.0.0, following property will be replaced:
  "provider.iamRoleStatements" -> "provider.iam.role.statements"
More info: https://serverless.com/framework/docs/deprecations/#PROVIDER_IAM_SETTINGS_V3

どうもserverless.ymlの書き方が変わりますよということみたい。最初に生成されたserverless.ymlにはコメントとして書き方の例があり、その書き方に合わせるとこの警告は出なくなった。

初めてのサーバーレスアプリケーション開発 ~Serverless Framework と Codeシリーズを連携させる~

初めてのサーバーレスアプリケーション開発 ~Serverless Framework と Codeシリーズを連携させる~ | DevelopersIO

感想

前回の記事で「serverless.ymlとかはどうやってコード管理するんだろうな」と思ってたんですが、その回答がこの記事に書いてありました。さらにコードのpushをトリガーにして自動ビルド&デプロイを行う方法が書いてあります。この辺は、GitHubGitHub Actionsに該当する機能なんですね。

手順的につまづいたところ

CodeBuildの設定画面がかなり違ってきている。 記事では、「環境イメージ」の設定で「Dockerイメージの指定」を選び、「環境タイプ」としてLinux、「カスタムイメージタイプ」としてその他を選び、「カスタムイメージID」は aws/codebuild/eb-nodejs-4.4.6-amazonlinux-64:2.1.3 とあるが、今の画面で「カスタムイメージ」を選択して「環境タイプ」でLinuxを選択するとイメージレジストリを選択するような画面になり、カスタムイメージIDを入れられるような画面はない。

結果として以下のような感じで環境イメージなどを選んでみた。

CodeBuildの「環境」の設定

「イメージのバージョン」は「このランタイムバージョンには常に最新のイメージを使用してください」のままで通ったので、多分勝手に最新のものが選ばれたのかもしれない。

個人的なミスでつまづいたところ

コードを書いてpushするとCodePipelineが動きCodeBuildのビルドが成功した。しかしログをよく見てみると、BuildのフェーズでWarnが出ている。

[Container] 2022/05/03 10:45:00 Entering phase BUILD
[Container] 2022/05/03 10:45:00 Running command echo Build started on `date`
Build started on Tue May 3 10:45:00 UTC 2022

[Container] 2022/05/03 10:45:00 Running command cd demo-cicd-service && sls deploy

Warning: Invalid configuration encountered
  at 'functions.hello.events.0': unsupported function event

Learn more about configuration validation here: http://slss.io/configuration-validation

Deploying demo-cicd-service to stage dev (us-east-2)

✔ Service deployed to stack demo-cicd-service-dev (82s)

functions:
  hello: demo-cicd-service-dev-hello (347 B)

1 deprecation found: run 'serverless doctor' for more details

[Container] 2022/05/03 10:46:27 Phase complete: BUILD State: SUCCEEDED

functionのところだから、Lambdaのところがうまくいっていないのかな? どうすれば確認できるだろう? Server FrameworkでデプロイするとCloudFormationのところにスタックというのができてたと思うから、そちらを見てみる。 スタックからリソースを確認すると、demo-cicd-service-dev-helloという関数はできているし、DynamoDBもできているので不審な点はなさそう。とりあえず動作確認を続けてみる。

いろいろ確認してみた結果、 functions.hello.events の下のインデントがずれていた。なるほど、YAMLだからインデントのズレは受け入れられないんですね。そのほかにも閉じクォーテーション忘れとか細かい入力ミスがあったので合わせて直してgit pushし直す。

すると次はビルドに失敗している模様。

[Container] 2022/05/07 06:24:34 Running command cd demo-cicd-service && sls deploy
Deploying demo-cicd-service to stage dev (us-east-2)

× Stack demo-cicd-service-dev failed to deploy (11s)
Environment: linux, node 12.22.2, framework 3.16.0, plugin 6.2.2, SDK 4.3.2
Docs:        docs.serverless.com
Support:     forum.serverless.com
Bugs:        github.com/serverless/serverless/issues
Error:
UPDATE_FAILED: DemoDynamoDbTable (AWS::DynamoDB::Table)
CloudFormation cannot update a stack when a custom-named resource requires replacing. Rename demo-sls-person and update the stack again.

View the full error: https://us-east-2.console.aws.amazon.com/cloudformation/home?region=us-east-2#/stack/detail?stackId=xxx

[Container] 2022/05/07 06:24:50 Command did not exit successfully cd demo-cicd-service && sls deploy exit status 1
[Container] 2022/05/07 06:24:50 Phase complete: BUILD State: FAILED
[Container] 2022/05/07 06:24:50 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: cd demo-cicd-service && sls deploy. Reason: exit status 1
[Container] 2022/05/07 06:24:50 Entering phase POST_BUILD
[Container] 2022/05/07 06:24:50 Running command echo Build completed on `date`
Build completed on Sat May 7 06:24:50 UTC 2022

[Container] 2022/05/07 06:24:50 Phase complete: POST_BUILD State: SUCCEEDED
[Container] 2022/05/07 06:24:50 Phase context status code:  Message: 

リネームせよと言っている「demo-sls-person」はDynamoDBのテーブル名として設定した名前。あれ、でもこの直前に学んだ記事

初めてのサーバーレスアプリケーション開発 ~Serverless Framework を使ってAWSリソースをデプロイする~ | DevelopersIO

では、serverless.ymlなどのコードを修正してsls deployしなおしても特に何も言われなかったけどな……。何か違うのかしら。

こちらの記事を見ながら考えてみた。

CloudFormation内のDynamoDBリソース更新でハマった話 - Qiita

なるほど、わかってきたぞ。さっきserverless.ymlの修正した時、DynamoDBのパーティションキーが誤記っていることに気がついてスペルを直したんだった。それでそのままでは更新できないと言っているんですね。

こういう時はどうしたらいいのか……。他の記事も見ながら考えてみる。

AWS Cloudformation カスタム名つきリソースの置換 - 行けたら行く

ちゃんとやるなら、serverless.ymlに新しい名前のDynamoDBの定義を書いて一時的に2つある状態にして、データを移行させてから古い方を消すとかなのかな。でもそれだとそれやるたびに名前どんどん変わっていってしまう?

現状としてはDBに何もデータ入れていないし、今あんまり細かいところまで突っ込んで調べる段階でもないと思うので、 sls remove 相当のことをやって一旦スタックごと消してしまった方が早いのかな。ただ、今 sls deploy しているのはCodeBuildの中なわけで、Cloud9環境のかなから sls remove を打つのはなんかちょっと違うかなと思い、CloudFormationのサービス画面からスタックを削除できそうだったのでやってみた。

すると DELETE_FAILED になった。「状況の理由」には

The following resource(s) failed to delete: [ServerlessDeploymentBucket]. 

と表示されている。なんだろうこれは。リソースをよく見てみると「ServerlessDeploymentBucket」という論理IDでAWS::S3::Bucketタイプのものが削除に失敗していることがわかる。このServerlessDeploymentBucketという名前に見覚えはなかったし、これまでの手順でS3なんて使ってたっけ?と思ったが、S3の中身を見てみたらなんとなくわかった。デプロイ時にserverless.ymlとかの情報を一旦置いておく場所っぽい。

S3にある当該のバケットを直接削除し、その後CloudFormationに戻ってもう一度スタックの削除をしてみる。すると今後はこんなダイアログが表示された。もしかしてS3バケットを直接手で削除しなくてもこの手順踏めば勝手に削除してくれたのかもしれない。 ともあれ、これでスタックが削除することができた。この後もう一度git pushしてみるとCodeBuildによるデプロイは成功した。よかった。

全体の感想

なるほど、なんとなく雰囲気はわかった気がする。今後の課題としては、Lambdaのファンクションはどうやって何を書くべきのかはまだまだわかっていないのでその辺を勉強してみたい。あとせっかくなので連動して動くフロントエンドも作ってみたいところ。