はじめに
こんにちは、KUDs です。
先日、Lambda 関数で以下のようなエラーが発生しました。
[ERROR] Runtime.ImportModuleError: Unable to import module 'MODULE_NAME': cannot import name 'DEPRECATED_SERVICE_NAMES' from 'botocore.docs' (/opt/python/botocore/docs/__init__.py)
特に関数に手を加えたわけでもありません。
そう、ある日突然関数が正常に実行されなくなったのです。
今回の記事では、この事象の原因と解決策について解説します。
エラーの原因
概要
結論、原因はランタイムの自動更新によるものです。
もう少し言うと、以下のような流れで発生します。
- Lambda ランタイムが更新される
- 同梱の boto3 のバージョンが更新される
- 更新された boto3 とデプロイパッケージに含まれる botocore の互換性がなくなる
- エラー!
boto3 の GitHub に Issue も上がってました。
色んなケースがありますね。
「botocore のバージョンを 1.29.102 にすると解決した」という記述もあります。
自分の事象とも当てはめると、botocore のバージョンが古い (1.29.102 未満?) かつ、boto3 が新しい (1.26.102 以上?) 場合にエラーが起きてそうな気がします。
調査
手元で検証・調査する中で、ランタイムの更新に依るものであることがわかりました。
以下は実際の確認内容です。
ランタイムのバージョン確認
まず、エラーが発生した時の Lambda 関数ログからランタイムを確認しました。
INIT_START Runtime Version: python:3.8.v48 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:830ab1165f1cdc47b8ae1e516f3936d8a176aec50d0699efd25a8bfeabb797b4
ログから、エラー発生時のランタイムバージョンは python:3.8.v48 であることがわかります。
次に、以前正常に動作していた時のログを確認しました。
INIT_START Runtime Version: python:3.8.v43 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:b20481443932830049531ab20faaf09295061aff7a67a0b0f40496e5e1ddec59
ログから、正常動作時のランタイムバージョンは python:3.8.v43 であることがわかります。
同梱の boto3 / botocore バージョン確認
boto3 / botocore のバージョンを確認しましょう。
関数内で以下のように記述しバージョンをチェックしましょう。
response = {
'boto3 version is ': (boto3.__version__),
'botocore version is ': (botocore.__version__)
}
print でも大丈夫です。
まず、ランタイム python:3.8.v43 の同梱をチェックします。
INIT_START Runtime Version: python:3.8.v43 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:b20481443932830049531ab20faaf09295061aff7a67a0b0f40496e5e1ddec59
...
{'boto3 version is ': '1.26.90', 'botocore version is ': '1.29.90'}
次に、python:3.8.v48 の同梱をチェックします。
INIT_START Runtime Version: python:3.8.v48 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:830ab1165f1cdc47b8ae1e516f3936d8a176aec50d0699efd25a8bfeabb797b4
...
{'boto3 version is ': '1.34.42', 'botocore version is ': '1.34.42'}
バージョンが上がっていることが確認できます。
対応策
対策はいくつかあります。
以下では、暫定的な対応と恒久的な対応を記載します。
暫定対応
とにかく早く復旧する必要がある場合は、とりあえずロールバックしましょう。
特に、本番環境でエラーが発生している場合はまず復旧優先です。
手順としては先ほどと同じような調査の流れになります。
- CloudWatch Logs から 対象の Lambda 関数ログを選択
- INIT_START ログから正常動作時のランタイムバージョン ARN を確認
- 対象の Lambda 関数を選択
- 「ランタイム管理設定を編集」
- 「手動」を選択
- ランタイムバージョン ARN にて arn:aws:lambda:{region}::runtime:{id} を指定
ランタイムバージョンを固定したら、とりあえずは復旧できるはずです。
落ち着いたら、以下の恒久対応を行っていきましょう。(ランタイムを完全に固定するとセキュリティイシューに繋がりますので)
恒久対応
恒久対応は大きく二つあるかと思います。
デプロイパッケージ / Lambda レイヤーで boto3 / botocore のバージョンを固定
boto3 / botocore を問題なく動いていた時のバージョンで固定する方法です。
Lambda レイヤーは Linux 等で Zip ファイルを作成し、カスタムレイヤーとしてアップロードしましょう。
ざっくりとした手順は以下のような感じになります。
$ mkdir botocore-layer
$ cd botocore-layer
$ mkdir -p python/lib/python3.8/site-packages
$ pip install boto3==1.26.90 botocore==1.29.90 -t python/lib/python3.8/site-packages/
$ zip -r botocore-layer.zip python
※事前にランタイムに合わせて python, pip を準備しておきましょう
後は Lambda レイヤー作成でアップロードし、適応すれば完了です。
Lambda ランタイムが提供する boto3 / botocore のバージョンを使用
Lambda ランタイムが提供する boto3 / botocore を使用できればそもそもエラーは発生しません。
また、ランタイム更新に応じてバージョンも更新されるため、セキュリティイシューに繋がる懸念も減ります。
但し、デプロイパッケージや Lambda レイヤーから boto3 の依存関係を完全に除外する必要があります。
完全に人(関数)に依るので、手順はありません。
さいごに
本番環境の場合はランタイムバージョンの自動更新をオフにしておいた方がいいでしょう。
検証環境のみ自動更新にして、正常性確認のために定期実行しておくのもいいかもしれませんね。
マネージドサービスは自動アップデートしてくれるのはありがたいですが、こういう所は注意したいです。
以上です。
コメント