AWS Lambda 上で Rust のコードを実行しようとして結構頑張った話
短く
OpenSSL はやはり鬼門
というわけでできたー。下が成果物。
概要
最近 Lambda 上で GC が走らない言語動かしてこれやりたかったなー、という変な実装をしたことがありまして。
できるか調査を始めてみた次第です。Rust なのは完全に趣味。
ライブラリ
使ったライブラリは下のもので、CPython を利用するものです。
github.com
個人的におもしれーと思ったのが、Docker を利用してビルド環境を提供してくれているところでした。
Lambda で実行する以上、場合によってはクロスコンパイラとかいるわけで、結構大事な気遣いだなーと感心しておりました。
はまった罠
GitHub - ROki1988/kinesis-crowbar at 9ef21c359194d2e7642b9528be4d9a5d2986c920
コミットとしてはこのあたりでしょうか。
Kinesis から呼び出される想定で、S3 にファイルを保存するコードをかいたときです。*1
コンパイルが通ってよしよし、と思ったら動かない…
なぜだ、とエラーを見てみると、以下のようになっていました。
Unable to import module 'liblambda': /lib64/libcrypto.so.10: version `OPENSSL_1.0.2' not found (required by /var/task/liblambda.so)
OpenSSL …またお前か…
長い迷走
こっから長い迷走が始まります。
ビルド環境の README.md に従って見る
README.mdに openssl-devel を更新するような指定方法があったので、初手としてならってみましたが、結果は同じでした。
Issue の存在を確認
おー Issue あんじゃん、と中を確認して Pull Request もある!と期待がでてきました。
コードを修正してみて、ビルドして、デプロイ。
結果、動いた。動いたんだけど、コメントにあるとおりなんか変…
rust-openssl の対応バージョンを確認
build.rs で対応バージョンを見てみると、1.0.1 以上に対応している模様。
Issue 通りなら動くはず???
openssl 1.0.2 を静的リンクする
Lambda 上にないなら静的リンクでくっつければいいんだろ、と初 Dockerfile を書いてみました。
結果ビルドに成功したんですが、別のエラーで怒られました…
HttpDispatch(HttpDispatchError { message: "The OpenSSL library reported an error" }): RuntimeError Traceback (most recent call last): File "/var/runtime/awslambda/bootstrap.py", line 249, in handle_event_request result = request_handler(json_input, context) RuntimeError: HttpDispatch(HttpDispatchError { message: "The OpenSSL library reported an error" })
この時はサラッと次に行ってしまいましたが、今考えると TLS の検証とかで落ちてたのかもです。
CA の情報が見つからず、鍵の検証ではじかれて上記エラーかな。
そもそもの OpenSSL のバージョンを確認する
ん? そもそも Lambda 上の OpenSSL のバージョンはいくつだ? とやっとこさ気づき確認。
で、これです。
Lambda の OpenSSL のバージョン、ランタイムごとに違ってて
— 萬屋 rohki (@r_ohki) 2017年12月10日
python2.7: 1.0.1
python3.6: 1.0.0
nodejs4.3: 1.0.2
nodejs6.10: 1.0.2
てなもんでちょっと混乱してる
Python3.6が1.0.0 ってダメじゃん! なんで Pull Request のやつで動いたの?
Python2.7 + OpenSSL 1.0.1 でのビルド
幸いなことに rust-crowbar が Python 2.7 でも呼び出せたので、そちらに切り替えます。
ビルド環境として、Issue に上がっていた lambci が使えそうだったので、こちらをベースに Dockerfile を書きました。
FROM lambci/lambda:build-python2.7 RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable ADD build.sh /usr/local/bin/ VOLUME ["/code"] WORKDIR /code ENTRYPOINT ["/usr/local/bin/build.sh"]
で、コードも Python2.7 から呼び出せるように変えて、動いたー!!!
あーしんど。面白かったけどw
おわりに
迷走しすぎですね、こう書くと。静的リンクとか、もう。
環境の確認はいのいちやっていこう。
しかしこれ、Lambda OpenSSL のバージョンアップとかどうしてるんでしょう。
*1:Firehose でできるけどお試しなので許して