はじめに
以前、DjangoをLambdaで動かしたいと思ったのですがうまくいかず、諦める予定で下記の記事を書きました。
しかし、なんか悔しかったので動かしてやろうと思い、(無理やり?)動かすことができましたので記事にまとめました。もしよろしければ、上記の記事も見ていただけると嬉しいです。
目指す仕様
できるだけ維持費が安く済むシステムを目指すため、下記の要件を満たすこととします。
- Apacheなどは使わず、APIGateway + Lambdaで動かす
- データベースはSQLiteを使用
Djangoを解説しているサイト等を見ているとSQLiteは使うなというような記事を見かけるのですが、今回はプロトタイプを安く維持することを目標とするのでSQLiteを使います。
問題点と解決方法
さて、上記の条件でシステムを動かす上で、上記記事中でも挙げているのですが以下の問題があります。
問題点(1):Lambdaで動かすSQLiteのバージョンが低い
1点目はLambdaで提供されているVMにインストールされているSQLiteのバージョンが、3.7.17と非常に古いことです。
当初参考にしていた、@umihicoさんのDjangoをLambdaを使ってサーバレスにデプロイするの記事では、MySQLを使用する設定にすることによって、上記制約を回避し初期画面を表示させています。しかし、これをSQLiteを使用する設定にすると、エラーで初期画面にすらたどり着けません。
そこで、Dockerイメージを利用してLambdaをデプロイする手段を取りました。
Dockerイメージを使用しても、Amazonが提供するイメージではSQLiteバージョンが3.7.17となってしまうため、下記記事を参考にPython3.9のカスタムイメージを作成します。
最初、上記のブログを読んでも訳が分かりませんでしたが、Dockerのマルチステージビルドについて調べたり、@yohei7328さんの【AWS Lambda】独自のコンテナイメージを超シンプルに使用する方法を読んで理解できるようになりました。ただ、イメージはできるだけ小さくすべきだと思いますので、結局はAWSブログのコードをベースとしてDockerfile(GitHub)は作成しました。
問題点(2):Serverless Frameworkのプラグインが使えない
2点目は、LambdaのデプロイにDockerイメージを利用すると、Serverless Frameworkのプラグインが使えなくなる問題です。
DjangoをLambdaを使ってサーバレスにデプロイするの記事では、Serverless-WSGIというプラグインを使ってデプロイしているのですが、このプラグインは、Lambdaへのデプロイ時にファイルを追加することによって成り立っています。つまり、Dockerイメージでデプロイしてしまうとファイルを追加することができないため利用できません。
そこで、実際にデプロイされたファイルやGitHub上のコードを確認したところ、Werkzeug
をインストールした上で、.serverless-wsgi
、serverless_wsgi.py
、wsgi_handler.py
の3ファイルがあれば、該当動きそうであったため、この3ファイルを拝借して動かすことにします。(MITライセンスなので問題ない、よね?)
構成
ここまでで、WSGIアプリケーションとSQLiteを動かす準備は整ったので、全体構成を考えます。
まず、DjangoをApacheで動かす場合、以下記事の考え方がとても分かりやすいです。
Apacheからアクセスする部分を抜き出すと、以下のようになります。
Apache ─ Mod_wsgi ─ Wsgi.py ─ Django ─ RDBMS
└ Static file
これを、Lambda利用の今回のパターンに置き換えると、以下のようになります。
APIGateway ─ Lambda(Serverless-wsgi) ─ Lambda(Wsgi.py) ─ Django ─ EFS(SQLite)
└ S3(Static file)
これらのリソースを手作業で作るのは大変ですので、Serverless Frameworkを利用します。
成果物
今回作ったソースコードはGitHubで公開しています。
また、上記の方法でデプロイしたWebアプリも公開してあります。
デプロイしてみての感想
画像が何もないサイトにしては遅すぎると思います。ただ、意外にもGoogleのPageSpeed Insitesの結果は良かったので、ありなのかもしれません。
デプロイ当初はもっと遅かったのですが、EFSのスループットを上げるために1GB程度のファイルをEFS上に置いたところ若干改善しました。