概要
Lambdaにアップするソース(zip)の中に、ローカル端末上でインストールしたdjangoのパッケージをそのまま格納してアップロード。
Lambda関数は指定のDBに対してdjango migrationを行うコードです。
しかし、実施すると以下のエラーになってしまいました。
{"statusCode": 500, "body": "{"error": "Migration failed", "details": "(1060, \"Duplicate column name 'type'\")", "makemigrations": "No changes detected\n", "traceback": "Traceback (most recent call
前提
少し前提を説明します。
実際に稼働しているDBからdumpした最新データファイルをそのまま対象のRDSにrestoreしました。
その際にエラーは無し。
稼働してるDBと比べて、django_migrationsテーブルの中身も一致、最新migrationが適用されていることも確認しました。
しかしLambda関数を叩くと上述のエラー。
エラーメッセージにある「type」カラムはすでに反映済み、そのmigrationファイルも適用済みでした。
Lambda関数の中にパッケージとして入れていたdjangoのバージョンは下記。
Django==4.2.11
django-cors-headers==3.10.0
PyMySQL==1.1.2
mysqlclient==2.2.7
原因
Lambda関数のzipに含めたDjangoのバージョン(4.2.11)が、本番環境のDjangoバージョン(5.1)と一致していなかったことが原因だったと思います。
- Django 5.1で動いていた本番DBをダンプして復元したため、django_migrationsテーブルにはDjango5.1のマイグレーション記録が含まれていた
- しかしDjango 4.2.11のマイグレーションファイルで実行しようとしたため、マイグレーション状態に不整合が発生した
- "Duplicate column name 'type'" エラーは、Django 5.1で既に適用済みのマイグレーションを、Django 4.2.11が再度適用しようとしたために発生した
解決方法
以下のパッケージをLambdaLayerにアップロード、Lambda関数からこちらを参照する形としました。
Django==5.1
django-cors-headers==3.10.0
PyMySQL==1.1.2
mysqlclient==2.2.7
これでDjangoのバージョンを本番環境と一致し、
正常にマイグレーションができるようになったのだと思われます。
Lambda環境でのパッケージ検索順序
Djangoは以下の順序でマイグレーションを検出します。
- sys.path の各ディレクトリから /migrations/ を探す
- /var/task/ が最初に検索される(カレントディレクトリ)
- /opt/python/ はその後(Lambda Layer)
解決後の構成
- /var/task/ にはアプリケーションのマイグレーションのみ
- /opt/python/ にDjango 5.1(本番と同じバージョン)を配置
- Lambda関数のzipからはDjangoパッケージを削除
- アプリケーションコードとライブラリを明確に分離
これにより、バージョンが一致し、正常に動作するようになりました。
今回はちょっと検証してみたくて触っていただけだったので、簡単に実験できるようことを重視して、Djangoのバージョン違いなどあまり気にせず実施してしまっていました。
バージョンやLambdaLayerを使うことなど、実際に稼働しているものと同じ条件にするとエラーの原因がわかりますね。
参考
mysqlclientをLambdaLayerで扱う際にはちょっと注意が必要です。
以前以下の記事でも紹介したのでご参考までに。