sironekotoroの日記

Perl で楽をしたい

Perl の自作モジュールを AWS Lambda 上で Perl 5.34 で動かす

とりあえず満足

前回の続きです。

sironekotoro.hateblo.jp

自分の中では以下の要求が叶えられておらず不完全燃焼のままでありました。

  • Perl 5.32 の Lambda Layer を利用して自作モジュール含め外部モジュールを動かしたい。

    • 前回はカスタムランタイムから起動させた Perl 5.16.3 だった。

    • 特に Perl 5.32 じゃなければいけないとか、 Perl 5.16.3 だと困るという事情は無い。

      • 新しい Perl で動かしてみたい!という強い気持ちです。
  • https に通信したい。

    • できるよねーって思って軽い気持ちで AWS Lambda 上から use HTTP::Tiny して Yahoo! Japanhttps://www.yahoo.co.jp/) のページを get したらエラーが出た。

      • IO::Socket::SSLNet::SSLeay が無いっていわれる。が、ランタイムにインストールしてもエラーが出た。
    • 阿部寛のホームページ(http://abehiroshi.la.coocan.jp/)は get できた。http だから。

  • 相変わらず Web コンソールから操作するが、左側のファイル一覧ペインにモジュールのフォルダが入ってるのがなんとなく嫌だったので、Lambda レイヤーにまとめたかった。

    • 好みの問題です。

    • 好み以外にも、コードソース右上の「アップロード」からアップする zip ファイルが 3MB 超えたあたりでコードソースの画面での編集ができなくなります。実行は可能。

      • aws cli 使うのが普通?なのかなぁ。だからあんまり気にされてないと思う。

こんな方法で動かしました

基本は前回と同じ、なのですが書いてきます。

誰のためって 2021 年の GW 前の自分、数日後、数ヶ月後の自分のためです。

  1. AWS Lambda のページ右上の「関数の作成」から関数作る。

    f:id:sironekotoro:20210522235858p:plain

  2. 以下を選択・入力。

    1. 関数の作成: 一から作成

    2. 基本的な情報

      • 関数名: 任意の名前(例では perl5_34_https

      • ランタイム: Amazon Linux 2 でユーザー独自のブートストラップを提供する

    f:id:sironekotoro:20210523000620p:plain

  3. Lambda 関数のページが出てきたら、ページの一番下にあるレイヤー部の「レイヤーの追加」をクリックする。

    f:id:sironekotoro:20210523001546p:plain

  4. 以下を選択・入力

    • Layer source: ARN を指定

    • ARN: arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-34-runtime-al2:1

    設定が終わるとこうなる。

    f:id:sironekotoro:20210523003221p:plain

    • リージョンが東京(ap-northeast-1)以外の場合は shogo82148 さんのこちらを参照。最近(2021/5/20)発表になった Perl 5.34 が早くもある!ので使わせてもらう。

    github.com

  5. コードソース部の左側にあるファイル一覧から初期で存在する3つのファイルを右クリック -> Delete で削除する。

    • bootstrap.sample
    • hello.sh.sample
    • README.md

    f:id:sironekotoro:20210523003800p:plain

    • 削除せずとも良いけど使わないので・・・
  6. hello.pl を作成する

    • なんで hello.pl かというと、最初に選択したカスタムランタイムでのハンドラ(プログラムを動かすプログラム、Lambda 実行時に動くファイルとサブルーチン)名が hello.handler になっているから。

    • 気に入らない場合はランタイム設定の編集ボタンから変更可能。

      • ここでは変えないでいく。
    • ファイル名.サブルーチン名 という命名ルール。

    f:id:sironekotoro:20210523004322p:plain

    • 左側の先ほどファイルを削除したところを右クリックして New File を選択する。

    • ファイル名は hello.pl 。ハンドラで変えた場合にはそれに相当するファイル名にする。

    • コードはこんな感じで。特別なことはせず、とりあえず動くか確認。最後の 1; を忘れないこと。

    gist.github.com

    • コードを書いたら、CTRL + s でファイルを保存。

    • そして、上にある Deploy ボタンを押す!これを押さないと反映されないので注意。ボタンの右側には Change not deployed と出て警告してくれる。

    f:id:sironekotoro:20210523005629p:plain

    • Deploy が成功すると ボタンが押せなくなり、右側に緑色で Changes deployed と表示される。

    f:id:sironekotoro:20210523005737p:plain

  7. テスト

    • Test ボタンを押すと、まず初期のテストの名前をつけるよう画面が表示される

    • イベント名: firstTest または任意の名前。文字の利用制限がある

    • イベント名を入れたら右下の 作成 ボタンを押してテストを作成する

    • コードソースの画面に戻るので、Test のボタンを押す。Response が Return の内容になり、以下の画面になればok

    f:id:sironekotoro:20210523010242p:plain

  8. http のサイトへのアクセスを試す

    • まず、http のサイトにアクセスできるかやってみます。

      • 阿部寛さんのサイト、2021 年 5 月 23 日現在は文字コードが Shift JIS でした。それに合わせで decode 入れてるのと、タイトルタグの中身をとるときに正規表現の名前付きキャプチャを使っています。

    gist.github.com

    f:id:sironekotoro:20210523013446p:plain

  9. https のサイトへのアクセスを試す

    gist.github.com

    で、この時点ではこのエラーが出ます。エラーコード 599。タイトルの取得に失敗しています。

    f:id:sironekotoro:20210523014722p:plain

    実際どういう応答かなー?と、レスポンスの中身を見てみることにします。

    return で返しているハッシュリファレンスに1行加えます content => $res->{content},

    はい、ここで HTTPS のサイトにアクセスするためのモジュールである IO::Socket::SSLNet::SSLeay が無いよー、というエラーであることが判明するわけです。

    f:id:sironekotoro:20210523015559p:plain

外部モジュールを入れた圧縮ファイルを作る

ここに辿り着くまでが数日かかったんですが、数日彷徨ったり勘違いした記憶はうちだけのものとして、あっさり解決策書いていきます。

全てはここ Run in Local using Docker に書いてあるんですが、せっかくなのでこのままやっていきます。

ここで先に追加した Lambda Layer と同じバージョンの Docker Image を利用して、モジュールを手元の環境にインストールし、それを zip で圧縮して Lambda のレイヤーとして登録し利用します。

うわ、俺が数日わからなかったところがなんと1行で。

  1. 手元に作業用の適当なフォルダを作ります。

    今回は lambda-layer-perl-https という名前のフォルダにしました。

  2. フォルダの中に以下のファイルを作成します

    • cpanfile

    • install.sh

      • install.sh には実行権限を付けておきます $ chmod +x install.sh

    gist.github.com

    f:id:sironekotoro:20210523021314p:plain

  3. フォルダの中に入ったら、以下のコマンドをターミナルに貼り付けて実行します

    $ docker run --rm -v $(PWD):/var/task shogo82148/p5-aws-lambda:build-5.34.al2 ./install.sh

  4. 終わると、作業用フォルダの中に local というフォルダが作成されています。これを zip で圧縮します。

    今回は作業用フォルダの中で以下のコマンドで圧縮ファイルを作成します。

    $ zip -r ../lambda-layer-perl-https.zip local/

    作業用フォルダの上の階層に lambda-layer-perl-https.zip という zip ファイルが作成されます。

圧縮ファイルを Lambda Layer として登録する

  1. AWS Lambda のページからレイヤーのページに移動する

  2. 右上の レイヤーの作成 ボタンを押す

  3. 以下を選択・入力

    • 名前: lambda-layer-perl-https

    • zip をアップロード のラジオボタンを選択

    • 「アップロード」ボタンから、作成した zip ファイルを選択してアップロード

      f:id:sironekotoro:20210523032417p:plain

    • アップロードできたら、右下の「作成」ボタンを押す

  4. レイヤーが作成されるので、作成したバージョンの ARN をコピーする

    f:id:sironekotoro:20210523032417p:plain

AWS Lambda にレイヤーを追加する

ここは Perl のレイヤーを追加した時と同じです。エラーが出た Lambda のページに戻りレイヤーを追加します。

f:id:sironekotoro:20210523033333p:plain

パスを追加する

追加した Lambda Layer のモジュールは、Lambda 上のパスからは /opt/local/lib/perl5/ にあるように見えます。

このため、use lib qw(/opt/local/lib/perl5); という 1 行を追加してモジュール検索パスに加えます。

f:id:sironekotoro:20210523033852p:plain

再度実行する

デプロイを忘れずに。再度 Test ボタンを押して Yahoo のページタイトルが取れていれば成功です。お疲れ様でした。

f:id:sironekotoro:20210523034011p:plain

おまけ

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の依存のないモジュールであればこれでも動く(ので問題の切り分けが遅れに遅れた)