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からエラーを吐いていた。

当時のエラー再現⼿順

【1】ローカル環境で、zipファイルを作成する。

  1. 以下コマンドで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】テスト

  1. 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⽉上旬より発⽣していることを確認
  • 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ファイルを作成する。

  1. pipコマンド実⾏時に、requestsライブラリがurllib2以上3未満を参照するよう定義ファイル作成
vim requirements.txt
  1. 2⾏を追記
requests
urllib3<2
  1. 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を使ってたら、エラーになった話」でした。

ありがとうございました。