2023年5⽉24⽇ お昼ころ
Lambda関数をPython3.9でカキカキ…
「あ、Slackに通知を⾶ばしたいな〜」
調査…
「おお、import requestsと書いて…LambdaのLayerという機能でrequestsを含むライブラリをzip化して
格納する? フムフム…なるほどなるほど」
実装…
「あれ、Slackに通知が来ないし。Lambdaからエラーがでているな」
"errorMessage": "Unable to import module 'lambda_function': cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_' (/opt/python/urllib3/util/ssl_.py)",
まずは安定のエラー⽂を翻訳…
「フムフム…
“errorMessage “を⾒ろと⾔っているな。
‘lambda_function’: という名前モジュールのインポートができないよ
‘urllib3.util.ssl_’. という名前もインポートできませんよ
なるほど〜わからない。⼿詰まりだな。」
と⾒事にドハマリしました。
その後解決に⾄りましたので、事象の共有をしたいと思います!
最後までよろしくお願いいたします!
背景
- Lambda関数をPython3.9ランタイムで書いていた。
↓
- SlackのWebhook URLを参照し、Lambda関数から通知を⾶ばしたい。
↓
- 機能実装にはPython3.9でも提供されている、HTTPリクエストが送信可能なライブラリであるrequestsが必要でした。
- requestsとは、HTTP通信⽤のPythonのライブラリです。
↓
- LambdaのPython3.9ランタイムでは、requestsライブラリが含まれていない。
↓
- requestsライブラリをローカルで.zip化して、Lambda Layerにアップロードする。 その後、Lambda関数でLayerを参照できるように実装が必要だった。
- Lambda Layerとは、追加のコードやデータを含める事ができる.zipファイルアーカイブです。
LambdaからLayerを参照することができます。
- Lambda Layerとは、追加のコードやデータを含める事ができる.zipファイルアーカイブです。
↓
実装した所Lambdaからエラーを吐いていた。
当時のエラー再現⼿順
【1】ローカル環境で、zipファイルを作成する。
- 以下コマンドでzipファイルを作成する。(ディレクトリ名は、各Lambdaランタイムのレイヤーパスと同名のpythonとする。)
mkdir python pip install -t python requests zip -r9 layer.zip python
【2】Lambda Layerへアップロードする。
1.AWSコンソールのLambda画⾯より、「Layerの作成」をクリックする。
2.レイヤー名を⼊⼒し、ローカル環境で作成しzip化したファイルをアップロードする。
3.作成ボタンをクリックし、完了画⾯ではARNをコピペしておくこと。
4.対象のLambda関数下部分から、先程作成したLayerを追加する。(ARNは前述⼿順3で使⽤したもの)
【3】テスト
- requestsの動作を記載したLambda関数をデプロイし、テストする。
【4】エラーが発⽣する。
"errorMessage": "Unable to import module 'lambda_function': cannot import name 'DEFAULT_CIPHERS' from 'urllib3.util.ssl_' (/opt/python/urllib3/util/ssl_.py)",
エラーの原因
requestsのバージョンを指定せず(=2023年5⽉24⽇時点の最新版 2.3.0)初回インストールすると、urllib3v2.0.2もインストールされエラーが発⽣していた。
urllib3の公式ドキュメント
ImportError: cannot import name ‘DEFAULT_CIPHERS’ from ‘urllib3.util.ssl_’について
- 似た事象が2023年5⽉上旬より発⽣していることを確認
- 特に、このGithubで議論している件は同じ事象だった。
- requests2.30.0ではurllib3 v2.0を参照する事が判明
- 結論:最新のrequests(2.30.0以降)をpipで初回インストールする場合
urllib3のv1系のバージョンを参照するようにしたら解決するようです。
エラー発⽣の組み合わせ表
エラー発⽣の有無 | requests(=2023年5⽉24⽇時点の最新版 2.3.0) | urllib3 |
---|---|---|
発⽣する | 2.3.0 | v2.0.2(v2系だと現状エラーとなりました) |
発⽣しない | 2.3.0 | v1.26.16(v1系であれば動作するようです) |
ImportError: cannot import name ‘DEFAULT_CIPHERS’ from ‘urllib3.util.ssl_’を参照し、urllib3のv1.26.16(v1系)を初回インストールする⼿順を実施しました。
エラー解消した⼿順
注意点
※すでに⼀度ローカル環境で作成したpythonディレクトリやrequestsがある場合は、⼀度削除してから以降の⼿順実施を推奨します。
rm -rf python
理由:エラーが発⽣した既存のpythonディレクトリに対し、後続⼿順を実施してもurllib3 v2.0(v2系)を参照し続けるため解消しません。
【1】ローカル環境で、zipファイルを作成する。
- pipコマンド実⾏時に、requestsライブラリがurllib2以上3未満を参照するよう定義ファイル作成
vim requirements.txt
- 2⾏を追記
requests urllib3<2
- escキー+:wq! で閉じる。
2.以下コマンドでzipファイルを作成する。(ディレクトリ名は、各Lambdaランタイムのレイヤーパスと同名のpythonとする。)
mkdir python pip install -r requirements.txt -t ./python zip -r9 layer.zip python
【2】Lambda Layerへアップロードする。
1.AWSコンソールのLambda画⾯より、「Layerの作成」をクリックする。
2.レイヤー名を⼊⼒し、ローカル環境で作成しzip化したファイルをアップロードする。
3.作成ボタンをクリックし、完了画⾯ではARNをコピペしておくこと。
4.対象のLambda関数下部分から、先程作成したLayerを追加する。(ARNは前述⼿順3で使⽤したもの)
【3】テスト
1.requestsの動作を記載したLambda関数をデプロイし、テストする。
【4】エラー解消した事を確認する。
まとめ
Lambda+Python+requestsとても便利ですよね。
- 簡単にPythonコードをデプロイできるLambda しかもサーバーリソースを常に管理稼働させなくても⾮常に便利。
しかし、使⽤しているPythonランタイムのverによっては格納されているorいないライブラリが多かったりしますので、予め調査しておくことをおすすめします。
またライブラリが格納されていない時は、Lambda Layerで問題も解消可能ですので、ぜひ使って⾒てください!
今回はみんな⼤好きな「Lambda+Python3.9ランタイム環境でrequestsを使ってたら、エラーになった話」でした。
ありがとうございました。