Perl の自作モジュールを AWS Lambda 上で Perl 5.34 で動かす
とりあえず満足
前回の続きです。
自分の中では以下の要求が叶えられておらず不完全燃焼のままでありました。
Perl 5.32 の Lambda Layer を利用して自作モジュール含め外部モジュールを動かしたい。
https に通信したい。
できるよねーって思って軽い気持ちで AWS Lambda 上から
use HTTP::Tiny
して Yahoo! Japan(https://www.yahoo.co.jp/) のページを get したらエラーが出た。IO::Socket::SSL
とNet::SSLeay
が無いっていわれる。が、ランタイムにインストールしてもエラーが出た。
阿部寛のホームページ(http://abehiroshi.la.coocan.jp/)は get できた。http だから。
相変わらず Web コンソールから操作するが、左側のファイル一覧ペインにモジュールのフォルダが入ってるのがなんとなく嫌だったので、Lambda レイヤーにまとめたかった。
好みの問題です。
好み以外にも、コードソース右上の「アップロード」からアップする zip ファイルが 3MB 超えたあたりでコードソースの画面での編集ができなくなります。実行は可能。
aws cli
使うのが普通?なのかなぁ。だからあんまり気にされてないと思う。
こんな方法で動かしました
基本は前回と同じ、なのですが書いてきます。
誰のためって 2021 年の GW 前の自分、数日後、数ヶ月後の自分のためです。
AWS Lambda のページ右上の「関数の作成」から関数作る。
以下を選択・入力。
Lambda 関数のページが出てきたら、ページの一番下にあるレイヤー部の「レイヤーの追加」をクリックする。
以下を選択・入力
Layer source: ARN を指定
ARN:
arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-34-runtime-al2:1
設定が終わるとこうなる。
- リージョンが東京(ap-northeast-1)以外の場合は shogo82148 さんのこちらを参照。最近(2021/5/20)発表になった Perl 5.34 が早くもある!ので使わせてもらう。
コードソース部の左側にあるファイル一覧から初期で存在する3つのファイルを右クリック -> Delete で削除する。
- bootstrap.sample
- hello.sh.sample
- README.md
- 削除せずとも良いけど使わないので・・・
hello.pl を作成する
なんで
hello.pl
かというと、最初に選択したカスタムランタイムでのハンドラ(プログラムを動かすプログラム、Lambda 実行時に動くファイルとサブルーチン)名がhello.handler
になっているから。気に入らない場合はランタイム設定の編集ボタンから変更可能。
- ここでは変えないでいく。
ファイル名.サブルーチン名
という命名ルール。
左側の先ほどファイルを削除したところを右クリックして
New File
を選択する。ファイル名は
hello.pl
。ハンドラで変えた場合にはそれに相当するファイル名にする。コードはこんな感じで。特別なことはせず、とりあえず動くか確認。最後の
1;
を忘れないこと。
コードを書いたら、CTRL + s でファイルを保存。
そして、上にある Deploy ボタンを押す!これを押さないと反映されないので注意。ボタンの右側には Change not deployed と出て警告してくれる。
- Deploy が成功すると ボタンが押せなくなり、右側に緑色で Changes deployed と表示される。
テスト
Test ボタンを押すと、まず初期のテストの名前をつけるよう画面が表示される
イベント名: firstTest または任意の名前。文字の利用制限がある
イベント名を入れたら右下の 作成 ボタンを押してテストを作成する
コードソースの画面に戻るので、Test のボタンを押す。Response が Return の内容になり、以下の画面になればok
http のサイトへのアクセスを試す
まず、http のサイトにアクセスできるかやってみます。
https のサイトへのアクセスを試す
で、この時点ではこのエラーが出ます。エラーコード 599。タイトルの取得に失敗しています。
実際どういう応答かなー?と、レスポンスの中身を見てみることにします。
return で返しているハッシュリファレンスに1行加えます
content => $res->{content},
はい、ここで HTTPS のサイトにアクセスするためのモジュールである
IO::Socket::SSL
とNet::SSLeay
が無いよー、というエラーであることが判明するわけです。
外部モジュールを入れた圧縮ファイルを作る
ここに辿り着くまでが数日かかったんですが、数日彷徨ったり勘違いした記憶はうちだけのものとして、あっさり解決策書いていきます。
全てはここ Run in Local using Docker に書いてあるんですが、せっかくなのでこのままやっていきます。
ここで先に追加した Lambda Layer と同じバージョンの Docker Image を利用して、モジュールを手元の環境にインストールし、それを zip で圧縮して Lambda のレイヤーとして登録し利用します。
うわ、俺が数日わからなかったところがなんと1行で。
手元に作業用の適当なフォルダを作ります。
今回は
lambda-layer-perl-https
という名前のフォルダにしました。フォルダの中に以下のファイルを作成します
cpanfile
install.sh
- install.sh には実行権限を付けておきます
$ chmod +x install.sh
- install.sh には実行権限を付けておきます
フォルダの中に入ったら、以下のコマンドをターミナルに貼り付けて実行します
$ docker run --rm -v $(PWD):/var/task shogo82148/p5-aws-lambda:build-5.34.al2 ./install.sh
終わると、作業用フォルダの中に
local
というフォルダが作成されています。これを zip で圧縮します。今回は作業用フォルダの中で以下のコマンドで圧縮ファイルを作成します。
$ zip -r ../lambda-layer-perl-https.zip local/
作業用フォルダの上の階層に
lambda-layer-perl-https.zip
という zip ファイルが作成されます。
圧縮ファイルを Lambda Layer として登録する
右上の レイヤーの作成 ボタンを押す
以下を選択・入力
レイヤーが作成されるので、作成したバージョンの ARN をコピーする
AWS Lambda にレイヤーを追加する
ここは Perl のレイヤーを追加した時と同じです。エラーが出た Lambda のページに戻りレイヤーを追加します。
パスを追加する
追加した Lambda Layer のモジュールは、Lambda 上のパスからは /opt/local/lib/perl5/
にあるように見えます。
このため、use lib qw(/opt/local/lib/perl5);
という 1 行を追加してモジュール検索パスに加えます。
再度実行する
デプロイを忘れずに。再度 Test ボタンを押して Yahoo のページタイトルが取れていれば成功です。お疲れ様でした。
おまけ
GitHub にあるモジュールは cpanfile に required 'git://github.com/〜'
と書くことでもいけそうなんですが、ログ上はなんか失敗しているんですよね・・・
ただ、cpanfile じゃなくて install.sh の方に cpanm --notest --local-lib local --no-man-pages --installdeps 'git://github.com/〜
って書くとインストールが終わったりします。
まぁ、もともと cpanm は git からのインストールはサポート外なので、そのつもりで。
何が時間かかったか
Lambda の環境を入れた Docker コンテナである lambci/lambda を使って作ったモジュールを、Perl 5.32 のレイヤーで動かそうとしていた。
なお、XSの依存のないモジュールであればこれでも動く(ので問題の切り分けが遅れに遅れた)