『Python サーバレスアプリ 開発入門』備忘録

『Python サーバレスアプリ 開発入門』ではFlaskをLambdaで動かす手法を学べます。一通り写経を終えたので、つまづいた点を書き留めておきます。

版：初版第1刷
環境：MacBookAir2020 BigSur11.6
本書での環境とちょっと違いvenvを使って仮想環境を作っています。

__(追記)まずは、公式githubをみて！！！__
[「動かして学ぶ！Pythonサーバレスアプリ開発入門」 サンプルコード](https://github.com/chaingng/shoeisha_serverless_python_tutorial#readme)
大体ここで述べられています。途中から気づきました。

=======================

__公式サイトで掲載されている誤植__

2022/4/27現在公式サイトに掲載されている通り、p93に1文字だけ間違いがあります。

```:誤
AWS_ACCESS_KEY_ID = 'AWS_ACEESS_KEY_ID'
```
```:正
AWS_ACCESS_KEY_ID = 'AWS_ACCESS_KEY_ID'
```

正誤表にはありませんが同様の間違い（というか全部共通で間違ってますので、原文通りでも動くでしょう）がp147、p148、p160、p161、p163にもあります。

__正誤表に載っていない箇所__


・Chapter10の誤植
p195で各種ライブラリをインストールしています。バージョンを合わせるためにpⅥの一覧を見ていたのですが、
flask-sessionstoreのバージョンが4.1.3とある記述があります。これは、oauth2clientの間違いでしょう。

・p98
本書では変更点を毎回丁寧に解説してくださっているのですが、逆にその解説を頼りに写経していて、一箇所つまづいたところがありました。
p98の解説では「リスト6.11」→「リスト7.3」の変更点が一箇所、記述が抜け落ちています。
```リスト7.3 : flask_blog/views/entries.py
from flask_blog.models.entries import Entry
```
これを書かないと、p109で起動した際にエラーになります。
```
NameError
NameError: name 'Entry' is not defined
```

__Flask,MarkupSafeのバージョン__

本書ではFlaskのバージョンを指定せずにインストールしています。

```:p30
pipenv install Flask
```

ただ、このやり方では本記事執筆時点でFlask2.0がインストールされてしまいます。
<!-- 
メジャーアップデートのため、後半、DBとの連携が始まるところでエラーが起こってきます。
```:p108
% python manage.py init_db
```

```
(前略)
AttributeError: As of v1.0 PynamoDB Models must have a table_name
Model: flask_blog.models.entries.Entry
See https://pynamodb.readthedocs.io/en/latest/release_notes.html
```
-->
Flaskのバージョンを1.1.4に変更します。（なお自分は仮想環境をpipenvではなくvenvで設定していますのでpipになっています）

```
% pip uninstall flask
% pip install flask==1.1.4
```
また、MarkupSafeのバージョンも指定した方がいいようです。自分は以下のエラーにハマりました。

```:p108
% python manage.py init_db
```

```
（前略）
File "/Users/username/Library/application/env/lib/python3.9/site-packages/jinja2/filters.py", line 13, in <module>
    from markupsafe import soft_unicode
ImportError: cannot import name 'soft_unicode' from 'markupsafe' (/Users/username/Library/application/env/lib/python3.9/site-packages/markupsafe/__init__.py)
```

MarkupSafeのバージョンも変更します。
```
$ pip install MarkupSafe==2.0.1
```
参考：[Flaskが急に使えなくなった時の対処法](https://yuaha.org/flask_importerror/)

__Pythonのバージョンは3.8で__
```:p172
% zappa init
Traceback (most recent call last):
  File "/Users/username/Library/application/env/bin/zappa", line 5, in <module>
    from zappa.cli import handle
  File "/Users/username/Library/application/env/lib/python3.9/site-packages/zappa/__init__.py", line 9, in <module>
    raise RuntimeError(err_msg)
RuntimeError: This version of Python (3.9) is not supported!
Zappa (and AWS Lambda) support the following versions of Python: ['3.6', '3.7', '3.8']
```
これは書籍通り、3.8で進めることでクリアできるものです。チャプター9の途中まで3.9で問題なかったのですが、ここでダメになりました。

Python3.8で環境を構築し直して。。。

```:p172
% zappa init

███████╗ █████╗ ██████╗ ██████╗  █████╗
╚══███╔╝██╔══██╗██╔══██╗██╔══██╗██╔══██╗
  ███╔╝ ███████║██████╔╝██████╔╝███████║
 ███╔╝  ██╔══██║██╔═══╝ ██╔═══╝ ██╔══██║
███████╗██║  ██║██║     ██║     ██║  ██║
╚══════╝╚═╝  ╚═╝╚═╝     ╚═╝     ╚═╝  ╚═╝

Welcome to Zappa!

Zappa is a system for running server-less Python web applications on AWS Lambda and AWS API Gateway.
This `init` command will help you create and configure your new Zappa deployment.
Let's get started!

Your Zappa configuration can support multiple production stages, like 'dev', 'staging', and 'production'.
What do you want to call this environment (default 'dev'): 
```


__ZAPPAでのデプロイ時にエラー__
```
% zappa deploy dev
Important! A new version of Zappa is available!
Upgrade with: pip install zappa --upgrade
Visit the project page on GitHub to see the latest changes: https://github.com/Miserlou/Zappa
Calling deploy for stage dev..
Creating application-ap-dev-ZappaLambdaExecutionRole IAM Role..
Creating zappa-permissions policy on application-ap-dev-ZappaLambdaExecutionRole IAM Role.
Downloading and installing dependencies..
 - markupsafe==2.0.1: Downloading
100%|███████████████████████████████████████████████████████| 30.6k/30.6k [00:00<00:00, 11.3MB/s]
Packaging project as zip.
Uploading application-ap-dev-1651078347.zip (48.9MiB)..
100%|████████████████████████████████████████████████████████| 51.2M/51.2M [01:47<00:00, 479kB/s]
Scheduling..
Scheduled application-ap-dev-zappa-keep-warm-handler.keep_warm_callback with expression rate(4 minutes)!
Oh no! An error occurred! :(

==============

Traceback (most recent call last):
  File "/Users/username/Library/application/env/lib/python3.8/site-packages/zappa/cli.py", line 2778, in handle
    sys.exit(cli.handle())
  File "/Users/username/Library/application/env/lib/python3.8/site-packages/zappa/cli.py", line 512, in handle
    self.dispatch_command(self.command, stage)
  File "/Users/username/Library/application/env/lib/python3.8/site-packages/zappa/cli.py", line 549, in dispatch_command
    self.deploy(self.vargs['zip'])
  File "/Users/username/Library/application/env/lib/python3.8/site-packages/zappa/cli.py", line 806, in deploy
    template = self.zappa.create_stack_template(
  File "/Users/username/Library/application/env/lib/python3.8/site-packages/zappa/core.py", line 2138, in create_stack_template
    self.cf_template.add_description('Automatically generated with Zappa')
AttributeError: 'Template' object has no attribute 'add_description'

==============

Need help? Found a bug? Let us know! :D
File bug reports on GitHub here: https://github.com/Miserlou/Zappa
And join our Slack channel here: https://zappateam.slack.com
Love!,
 ~ Team Zappa!
```
こちら、公式githubで解決策が示されていました。というかここまで書いてきた各ポイントについてもほとんど全部言及されていました。もっと早く見ればよかった。(本記事冒頭へ追記)

[「動かして学ぶ！Pythonサーバレスアプリ開発入門」 サンプルコード](https://github.com/chaingng/shoeisha_serverless_python_tutorial#readme)

```
% zappa undeploy dev
% pip install "troposphere==2.7.1"
% zappa deploy dev
```
気を取り直して再度デプロイ。次のエラーはこちら。
```
Oh no! An error occurred! :(

==============

Traceback (most recent call last):
(略)
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the CreateStack operation: User: arn:aws:iam::********5552:user/zappa-exec-user is not authorized to perform: cloudformation:CreateStack on resource: arn:aws:cloudformation:ap-northeast-1:********5552:stack/application-dev/* because no identity-based policy allows the cloudformation:CreateStack action


 because no identity-based policy allows the cloudformation:CreateStack action
```

AWSで権限を付与しました。
![スクリーンショット 2022-04-28 2.21.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/0d5136d1-a073-7296-b0cd-082d91c404ef.png)

参考：[AWS CLIエラー：”no identity-based policy allows the cloudformation:DescribeStacks action”を解決したい](https://qiita.com/zetzetn/questions/36aafdc9762de829cd3f)

```
% zappa undeploy dev
% zappa deploy dev
```
これで動きました。（本当はIAMロールをちゃんと作り直した方がいい）



__p206 デプロイでWarning__
```:p206
zappa deploy dev
```

```
(略)
Deploying API Gateway..
Error: Warning! Status check on the deployed lambda failed. A GET request to '/' yielded a 500 response code.
```
一晩調べてしまったんですが、本文 p206の下段に、ちゃんと書いてありました！

_ここではWebアプリケーションをデプロイしないため、Error: Warning! Status check on the deployed lambda failed. A GET request to '/' yielded a 500 response code.と表示されますが問題ありません_

読み落としていました。

__最後のSlackBotの変更後のデプロイ__
```:p223
% zappa update dev
```
```
(略)
    raise error_class(parsed_response, operation_name)
botocore.errorfactory.ResourceConflictException: An error occurred (ResourceConflictException) when calling the UpdateFunctionConfiguration operation: The operation cannot be performed at this time. An update is in progress for resource: arn:aws:lambda:ap-northeast-1:********5552:function:serverlesapp-dev
```
試したこと
zappasetting.jsonへの
```
"lambda_description": "aws:states:opt-out"
```
の追記
参考：[Lambda update fails with ResourceConflictException #1041](https://github.com/zappa/Zappa/issues/1041)
→直らず。2022/2以降は効かなくなったみたいですね。
[Coming soon: Expansion of AWS Lambda states to all functions](
https://aws.amazon.com/jp/blogs/compute/coming-soon-expansion-of-aws-lambda-states-to-all-functions/)

こちらですが、zappa 0.54.0で解決されていました。
https://github.com/zappa/Zappa/issues/1058#issuecomment-975776848
```
% pip install zappa==0.54.0
```

これで解決しました。

__その他気をつけたいこと__

Flask特有のコメントアウトのルールがあります。
HTML部分は普通の記法と同じく
```
<!--  -->
```
でコメントアウトできます。しかし、テンプレートを含む場合には
```
{# #}
```
で囲む必要があります。
原因不明のエラーが出続けて、かなり悩んだ結果わかったのが、コメントアウトしたと思ったところができていなかった、というものでした。