sironekotoroの日記

Perl と Mac の初心者の備忘録

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

GWずっとこれやってた

平年であれば帰省して甥っ子姪っ子と遊んだり・・・いや、もう遊んでもらえない歳になってしまったか。

まぁ、今年もコロナ禍で帰省するわけにはいかない感じなので、Perl の自作モジュールを AWS Lambda で動かすってのをやってました。

最終日にしてやっと動くようになったので、自分用の備忘録で書いておきます。

こんな感じで動かしました

shogo82148.github.io

ここに書いてあるまま +α です。

+α 分を書いていきます。

  • bootstrapinstall.sh には chmod +x で実行権限をつけておく。

  • Github からスクリプトを入れる際には、パッケージのビルドスクリプトに git を入れておく。

  • cpanm は GitHub からのインストールを正式にサポートはしていないが、 git://github.com/〜 でいける。うちの場合にはこう書きました。

#!/bin/sh
yum install -y gcc git perl-App-cpanminus
cpanm -l local --notest --installdeps .
cpanm -l local --notest git://github.com/sironekotoro/Zengin-Perl.git

あと、最後に圧縮して AWS Lambda に上げるところですが

docker run --rm -v "$PWD":/var/task lambci/lambda-base ./install.sh
zip -r ../dist.zip .

zip -r ../dist.zip . で、 dist.zip の後に . スペースとドットが必要です。まぁ、その場でわかるとは思うけど(一瞬わからなくて???ってなった人)

そして、圧縮した zip ファイルですが、AWS Lambda のここからアップロードします。コード書くところの右上の「アップロード元」ってところ。

f:id:sironekotoro:20210509132706p:plain

同じファイル名で何か書いてある場合には上書きされます。

アップロードするとこんな感じになります。圧縮されたファイルが展開されて左側に色々と増えてます。

f:id:sironekotoro:20210509133741p:plain

なお、この方法で動かす場合には、Lambda Layer に追加の Perl ランタイムは不要です。

ランタイムは「カスタムランタイムを利用」にしておきます。

f:id:sironekotoro:20210509133002p:plain

ハンドラは hello.handler としていますが、この場合、Lambda 起動したときに動く Perlスクリプトhello.pl 内の handler サブルーチンです。

なんでこんなに時間がかかったのか

  1. AWS Lambda で Perl を動かすには、Perl の Lambda Layer が必須だと思っていた。が、これがどこにも書いていない、完全な思い込み。不要だった。

    自分の思い込みで、これだけで 3 日くらい費やした気がします。

    カスタムランタイムをアップロードしつつ、Perl のランタイムレイヤーを追加したりしてた。

  2. 自作モジュールをインストールするのに当初は SSH でのインストールをやろうとしていました。

    が、そうすると Docker イメージに SSH秘密鍵を設定する必要があり、それをするのに手間取りました。しかし、最終的には cpanm git://〜 の形で解決。

  3. XS利用モジュールがうまく動かなかった。

    自作のモジュールでは Function::ParametersFile::Slurp を利用していましたが、これを検索パスから辿ることができず、またこれから依存しているモジュールが見つからない、ということで難儀しました。

    どうも、XS という C 言語のバイナリを利用しているモジュールがうまく動いていないことに気づきました。

    これに関しては、自作モジュール側を改修して、これらのモジュールを外しました。

    テストを書いていたおかげで、安心して書き直すことができました。

  4. AWS Lambda 用にモジュールをローカルにインストールする為に使う lambci/lambda と、AWS Lambda に追加する Perl Runtime Leyer の役割を理解しておらず、混乱した

  5. というか、今回の方法でインストールされる Perl は 5.016003 なんだけど、どういう方法で入っているのかわからない。標準モジュールのはずの Data::Dumper も明示的に cpanfile に書かないとダメ。Perl Runtime Leyer は Perl 5.032 で標準モジュールは普通に利用できる。

他にもまぁ、アホだ間抜けだ注意不足だなどなど、色々あるんですが、なんとか動きました。

多分、このエントリにも勘違いが入ってるんだろーなーと思います。

動機

AWS でLambda をどうこうっていうと、まぁ普通はサポートしている言語のものが多いです。当たり前ですが。

そこで、Perl を動かしてやろうじゃないか、ってのが一つ。

次に、コンソールから aws cli 使ってアップロードってのが常道で多数派だとは思うのですが、であればこのWebコンソールからもできるはずで、そちらで動かしてみたい、というのが一つ

なお、本来の目的は全銀コード検索を Slack のスラッシュコマンドからやりたい!ってやつだったのですが、先週社内勉強会でこの話したところ「herokuの方が向いてんじゃない?」とのことだったので、そりゃそうだと納得。そのうちherokuで動かしたいと思います。

前に一回やったんで、また過去の自分のブログ記事が助けになるはず。

GWの終わりに

カレンダー通りだったんですが、とはいえ随分な時間を費やしましたわ。

でも、こうやってまとめると2600文字ちょっと。1週間前の自分に教えてあげたいー、そしたらもっと前に進むことできたのにー

Perl入学式 オンライン 2021 第1回お疲れ様でした

Perl入学式 オンライン 2021 第1回

受講された方、サポーターの方、お疲れ様でした。 講師の人です。

今回は Windows の方には事前に環境構築をお願いしており、おかげで従来の第 1 回の範囲を超えて四則演算まで到達することができました。

環境構築が間に合わなかった方、5月中旬に予定されている第 2 回まで時間があります。環境構築にチャレンジしてみませんか?

以下のテキスト、動画、そして質問等があれば Discord で Perl入学式のサポーターが回答します。

github.com

www.youtube.com

discord.com

また、講義途中でわからなくなってしまった方、 Discord で質問いただければ、サポーター陣が回答します。

ぜひ質問してください。

過去の第1回エントリ

sironekotoro.hateblo.jp

sironekotoro.hateblo.jp

sironekotoro.hateblo.jp

sironekotoro.hateblo.jp

GUICUI

従来利用しているマウスとファイル・フォルダを操作する GUI と異なり、キーボードとコマンドで操作する CUI は戸惑うことも多いと思います。

とはいえ、プログラムを学ぶときに CUI は(今のところ)避けて通ることができません。

今回の第 1 回で、普段の GUI で行っているようなファイル作成、移動・名前変更、コピー、削除、フォルダ作成、フォルダ削除ができるようになりました。

これらのコマンドとプログラム(もちろん Perl も)を組み合わせることで、GUI では手間のかかることも簡単にできるようになります。

もちろん、初心者の方が「簡単に」できるようになるまでは時間が必要ですが、時間をかけて学べばできるようになります。

例えば、フォルダの中にあるファイル名の先頭に定型の文字、例えば「処理済_」をつけるとか・・・GUI でこれをやるとしたら結構大変だと思うんですよね。

・・・ってことで適当に課題を思いついてしまったので、適当に実装してみましたがこんな感じです。

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

# add_done.pl
# このプログラムと同じフォルダにあるファイルを対象にする
# sample ってついているファイル名のファイルの先頭に 処理済み_ という
# 提携文をつける
opendir my $DH , '.' or die;
for my $file (readdir $DH){
    next if $file !~ /sample/;

    my $newfile = "処理済み_$file";
    system "mv $file $newfile";
}
closedir $DH;

・・・無理矢理 Perl で処理した感アリアリなのですが、まぁそこはともかく。

変更前

f:id:sironekotoro:20210426005557p:plain

変更後

f:id:sironekotoro:20210426005553p:plain

20 個くらいであればまぁ、手でやるのとプログラム書くので同じ時間くらいだとは思うんですが、10000 個とかになると手でやってられないですよね。

もちろんファイル変更専用のツールもあるのですが、プログラム学ぶとそれ(ファイル名変更)以外のこともできるので、応用の範囲は広いです。

放課後ミニコーナーや Discord で質問・やりたいことをお待ちしてます

今回は「Twitter のフォロワー数調査を行いたい」という要望がありました。

これを実現するには、もちろん人間が頑張るってのもあるんですが、プログラムで頑張ってもらうというのが現実的だと思います。

Twitter API 使って、フォロワーのIDをカウントするのが普通のやり方でしょうか。

API というのはプログラムからアプリケーション(ここではtwitter)の情報を取得する際の窓口、くらいに思ってください。

developer.twitter.com

このAPI を使うには、Twitter に利用申請が必要です。

dev.classmethod.jp

www.itti.jp

Twitter API を利用できるようになったら、Perl のモジュールを利用して情報を取得する、っていう感じです。

metacpan.org

これらは Perl 入学式の範囲ではないですが、こういう手順がありますよーという感じで、わかる範囲で回答できます。

世の中には、たくさんのツールがあります。

自分が欲しいツールを誰かが先に作っていればいいのですが、なければ作るしかありません。その手助けができれば幸いです。

オンライン第 2 回

5 月中旬くらいを予定しています。

次回は以下を予定してますが、変わるかも知れません。配列くらいまでいけるかな?

  • 文字列連結
  • 標準入力
  • 条件分岐「if 文, else 文」
  • 論理演算子「&&(かつ), ||(または)」

開催日は公式アカウントや Discord で告知します。

Perl入学式 2021 始まります! & Perl で 画像を自動トリミングする

Perl 入学式 2021 始まります!

前回更新が 4 月 2 日だったので、3 週間ぶりくらいですか。おひさしぶりです。

ブログも書かずに何をしていたかというと、2021 年度 Perl 入学式の準備をしておりました。

4 月 24 日です!

perl-entrance.connpass.com

2021 年度は、2019 年度までのように手元の PC に Perl をインストールして学習する方法をとります。

macOS ユーザであれば、そのままシステムにインストールされている Perl を利用して学習を進めます。

Windows ユーザの方は以下の動画リストとマニュアルを参考にインストールを行ってください。

github.com

www.youtube.com

うまくいかない場合などには、Perl 入学式の Discord で質問を受けます。活用ください。

Discord の招待リンクです

皆様の参加をお待ちしております!

Perl で画像を自動トリミングしたい

以下のような画像を大量にトリミングする必要が出てきました。これは 1920 x 932 のサイズの画像です。

f:id:sironekotoro:20210420192254p:plain

この、真っ白い部分だけを別のファイルにして抜き出したい!という要望です。要望を出したのは自分ですが・・・

1. 素直に画像ソフトを使って抜き出す

フリーで利用できる GIMP という画像編集ソフトがあります。

www.gimp.org

何冊か本も出ており、うちも下の本を手元に置いています。

GIMP を利用して 1 枚 1 枚心を込めて画像を抜き出していくのも一つの方法です。

が、ちょっと自分には辛い・・・今回だけで 200 枚以上処理する必要あるし。

BIMP というソフトを利用することで 一連の処理をバッチ処理のようにつなげることもできます。

バッチ処理といえば、macOS に入っている Autometer と プレビューの組み合わせでもいけるのかな・・・(思いつき

が、ここはせっかくなので Perl でやってみます。

2. Perl + ImageMagick

Perl で画像を扱う、というかプログラムから画像を扱うときには ImageMagick というソフトを使うのが定番とされていました。

imagemagick.org

が、この ImageMagick は多機能であるが故にインストールが大変なソフトとしても知られています。

うちも何回か挫折しています。

最近だったら Docker や、macOS であれば homebrew 使って入れるのがいいかも知れません。

また、手元で動かすにはいいのですが、世界に公開するサービスに組み込む際には脆弱性に気をつける必要があります。以下は報告されている脆弱性のリストです。

jvndb.jvn.jp

とにかく、 ImageMagick さえ安定して入っていれば、 Perl から ImageMagick を扱うモジュールを通して操作することができます。

しかし今回はこれを使わずにやります。

3. Perl + Imager

インストール&動作確認テスト的なやつ

Perl の画像処理モジュールに Imager というのがあります。これを使います。

metacpan.org

いつものように cpanm Imager でインストール。

SYNOPSYS みて、ふむふむって感じで自分で試してみます。お手軽そうな画像のサイズ縮小をやってみます。

さっきの画像と同じ場所にスクリプト置いて実行します・・・

あっさり成功しました。縦横のサイズが半分になってます。

input.png : 1920x932
output.png : 960x466

ピクセルを指定して切り抜き

では本題。

GIMP で画像を拡大して拡大してルーラーで計ったところ、横(x軸)の白い部分は 631 ピクセルから 1289 ピクセル目までということがわかりました。

縦(y軸)は 932 ピクセルでフルに利用しています。

この情報をもとに抜き出してみます。

こちらもあっさり成功です。きれいに白い所が抜きだせたようです。速度も 1 枚 0.2 秒ほどで申し分なし。

input.png : 1920x932
output_imager_manually_crop.png : 658x932

自動で切り抜き( Imager::Trim

さて、ここでやっぱり楽をしたいなーってなります。

いちいち、画像の部分だけピクセルを測るのが面倒だ、と。このような「よくある要望」は実装されていることが多いです。

実際、Imager::Trim というのがあるんですが、当初うちの環境ではうまく動きませんでした・・・

しかし、このブログを書くにあたって色々検証した結果、fuzz の値を調整し、背景色の情報 color の引数をちゃんと渡すことで警告なしで動くことが判明しました。

# 動く
my $color_cropped_img = $cropped_img->trim( fuzz => 7, color => $color );

# エラーは出るが動く
my $color_cropped_img = $cropped_img->trim( fuzz => 7 );

# エラーは出ないが、切り抜きは失敗する
my $color_cropped_img = $cropped_img->trim( fuzz => 6, color => $color );

ただし遅い。1 枚 10 秒くらいかかります。

input.png : 1920x932
    trim_top:0
    trim_bottom:932
    trim_left:631
    trim_right:1289
output_imger_trim.png : 658x932

自動で切り抜き( Imager::Filter::Autocrop

他のモジュールを探したところ Imager::Filter::Autocrop を見つけました。

こちらは 1 枚 3 秒ほど。この方法を取ることにしました。

input.png : 1920x932
output_imager_filter_autocrop.png : 658x932

md5 で雑に確認してみましたが、どのファイルも同じバイナリのようです。

$ md5 output*
md5: output: Is a directory
MD5 (output_imager_filter_autocrop.png) = ab744b9263aada986381630da980b1f9
MD5 (output_imager_manually_crop.png) = ab744b9263aada986381630da980b1f9
MD5 (output_imager_trim.png) = ab744b9263aada986381630da980b1f9

ということで、画像の抜き出しをやってみた記事でした。

困ったら情報を整理して聞いてみよう!

誰かに聞くつもりで内容をまとめると、そこで気づきが出て解決につながっちゃうというね。

ちなみに、解決しなかったら Perl 入学式の Discord で聞くつもりでおりました。

Perl を使った AWS Lambda を API Gateway に登録してブラウザから Hello, World する

前回までのあらすじ

sironekotoro.hateblo.jp

AWS Lambda で Perl を動かすことに成功した sironekotoro.

しかし、それは AWS Lambda 上で「動かしただけ」であり、なんのアクションもインプットもないものだった・・・

ってわけで

・・・いや、アクションもインプットもあったら Hello, World じゃないやろ。

今回は AWS Lambda と Amazon API Gateway を組み合わせてみます。

ブラウザでアクセスすると Hello, World! って出てくる、そういうのを目指します。

AWS Lambda の準備

なお、2021年04月02日時点での画面での記述です。

前回と同じ部分ありますが、まぁ、そういうものだと思ってお付き合いください。

ただし、2ヶ月後も同じ設定項目が、同じ名前で、同じ画面にあるかどうか・・・

  1. AWS Lambda のページ右上にある「関数の作成」をクリックする

  2. 関数の作成

    • 「1から作成」を選択
    • 関数名:my_perl_function
    • ランタイム:Amazon Linux 2 でユーザー独自のブートストラップを提供する
    • 実行ロール:デフォルトの「基本的な Lambda アクセス権限で新しいロールを作成」のまま

    右下の「関数の作成」をクリックする

  3. 「関数の概要」の画面にある Layers(0) をクリックする f:id:sironekotoro:20210402173323p:plain

    • レイヤーの追加をクリックする f:id:sironekotoro:20210402174221p:plain

    • 「ARN を指定」を選択する

    • Amazon リソースネーム(ARN)に以下を入力する arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-32-runtime-al2:1 f:id:sironekotoro:20210402174249p:plain

    保存をクリックする。「関数の概要」のところで Layers(1) となっていればok

    f:id:sironekotoro:20210402173902p:plain

  4. コードソース

    • 今回はデフォルトで用意されている bootstrap.sample, hello.sh.sample, README.md を削除しておきます。

      • 該当のファイル名の上で右クリック -> Delete を選択 f:id:sironekotoro:20210402174917p:plain
    • File から New File を選択し、エディタ部に以下のようにコードを書きます。

    • 書いたら File から Save As を選択してファイルを保存します。または Ctrl + s 。 f:id:sironekotoro:20210402191718p:plain f:id:sironekotoro:20210402191840p:plain

  5. テスト

    • エディタ部の上にある「Test」をクリックします

      • ラジオボタンは「新しいテストイベントの作成」でそのまま
      • イベント名はなんでも良いですが、ここでは「first1」としておきます
      • 下のエディタ部分は触らずに右下の「作成」ボタンをクリックします
    • ここで、Test の右隣にある Deploy ボタンをクリックします f:id:sironekotoro:20210402180608p:plain

    • デプロイが成功すると、Deploy の右にある表示が緑色で「Changes Deployed」に変わります。 f:id:sironekotoro:20210402181653p:plain

    • 再度、Test ボタンを押すと、エディタ部にタブが一つ増えテスト結果が表示されます。 f:id:sironekotoro:20210402192124p:plain

ここまでが AWS Lambda 側の準備です。

このテストはは、用意されたJSONをそのまま受け取り、body に入れて返しているというものです。

テスト結果を見ると、Web アプリ作っている人にはお馴染みの Content-TypestatusCode がありますね。

この段階でよく(自分が)引っかかるポイントは、Deploy ボタン押すのを忘れてテストやって反映されてない!ってやるやつです。

Amazon API Gateway の準備

  1. AWS のページ上部にある検索窓に API Gateway と入れて、そこから API Gateway の設定ページに進みます。 f:id:sironekotoro:20210402182713p:plain

  2. API のタイプ選択ですが、今回は 「HTTP API」で作成してみます。右下にある構築をクリックします。 f:id:sironekotoro:20210402193341p:plain

  3. 「統合を追加」のボタンをクリックし、以下のように設定します

    • 統合:Lambda
    • AWSリージョン:Lambda を作ったリージョン(今回は ap-northeast-1 (東京リージョン)) を選択
    • Lambda 関数:作成した Lambda の名前 `` を選択
    • api 名:任意に設定できるが、今回は Lambda 関数名に合わせて my_perl_api とする

    f:id:sironekotoro:20210402193739p:plain

    「次へ」をクリック

  4. ルートを設定

    ここで、HTTP のメソッドに応じた Lambda 関数を設定することができるが、今回は 1 つだけなので ANY のままでよい。

    リソースパスが API のエンドポイントになる(今回は Lambda 関数名である my_perl_function

    f:id:sironekotoro:20210402194400p:plain

    「次へ」をクリック

  5. API はバージョンによって v1 とか v2 などのようにバージョン分けすることができる。

    が、今回はそこまで改修しないのでデフォルトで設定されている通り、自動バージョニングを設定する。

    f:id:sironekotoro:20210402201205p:plain

    「次へ」をクリック

  6. 確認画面が出るので、「作成」をクリック f:id:sironekotoro:20210402201454p:plain

これで出来上がり。

f:id:sironekotoro:20210402201628p:plain

「URLを呼び出す」のところにある URL をクリックすると・・・このように not found になります。

f:id:sironekotoro:20210402201810p:plain

このURLの後ろにエンドポイントである /my_perl_function を追加してみます。

f:id:sironekotoro:20210402201938p:plain

出ました! Hello! World

これで、 AWS Lambda で作成した関数を AMAZON API Gateway に紐づけることができました。

詰まったところ

  • return で返すハッシュリファレンスを encode_jsonエンコードして返したらうまくいかなかった => 返り値は自動でエンコードしてくれる親切仕様だった

  • ログどうやって出すんだろ・・・? って試行錯誤しているうちにできたっぽい。

    API Gateway の左側メニューにある「ログ記録」を有効にして、Cloudwatch Logs の設定が必要とか言われたんで適当に作り、その ARN を貼り付けたらできた。

    ここもちゃんと解説できるようになりたいなぁ。

    f:id:sironekotoro:20210402204925p:plain

「PHPでもサーバーレス!AWS Lambda Custom Runtime 入門」でさっそく詰まる

AWS Lambda で詰まった

  • 前回AWS Lambda を使って Perl を動かして Hello, World! まではできた
  • Lambda 上で自作のモジュールを動かしたいけど、やり方がわからない
    • コンテナの所定のフォルダに入れる?
    • どのコンテナ使うの?Alpineとかでいいの?

AWS Lambda 標準でサポートされていない Perl を使うっていう獣道をいくんだから、分からないの仕方ないよねー

で、この本を読んでみることにしました。 id:taiko19xx さんの本です。

PHP以外の言語でカスタムランタイムを実行する際にも役に立つ一冊です。

この一言にすがる気持ちで・・・

そう、PHPAWS Lambda 標準でサポートされていない言語なので、何かわかるのではないか!?と。

時の流れは無常

この本は 2019 年に発行された本です。そして、2 年もあれば AWS の設定画面が変わるには十分すぎる時間なわけです。

と言うわけで、最初の phpinfo() を出すところまでの画面ショットと解説です。

もちろん、自分用です。

自分は AWS Lambda 触って日が浅いです。Amazon 公式のハンズオンを見て動かしただけというレベル感です。

pages.awscloud.com

ハンズオンごとに登録を求められるのが本当に鬱陶しいのですが、まぁ、相手は企業やしな・・・と言う寛大な気持ちで登録してハンズオン見させてもらっています。

2.1 Lambdaの設定をする

  • 図2.4:名前とランタイム

    • 「関数の作成」 -> ランタイムの選択「ユーザー独自のブートストラップを提供する」とあるが、ない。
    • Amazon Linux 2 でユーザー独自のブートストラップを提供する」を選択
  • 図2.7:関数にレイヤーを追加

    • 画面上部の「ARN を指定」のラジオボタンを選択
    • 画面下部の「ARN を指定」の入力欄に arn:aws:lambda:ap-northeast-1:834655946912:layer:php-demo-layer:4 を入力
      • PC 版 kindle からコピペするとハイフンが消えてしまうようなので注意
    • 画面右下の「追加」ボタンをクリック
  • 図2.13:ハンドラを変更

    • ハンドラはコードエディタの下、ランタイム設定の右上にある「編集」ボタンをクリックしてデフォルトの hello.handler から変更する
  • そして、ここが大事なのですが、コードを書いた後にデプロイする必要があります。

    • f:id:sironekotoro:20210329183705p:plain
    • この画像のオレンジ色の「Deploy」ボタンをクリックすること!
    • このボタンを押していないと、API Gateway と関連づけてもエラーになります。
      • ブラウザで API Gateway の呼び出し先をクリックした時のエラー
      • Warning: Unknown: failed to open stream: No such file or directory in Unknown on line 0 Fatal error: Unknown: Failed opening required 'index.php' (include_path='.:/usr/share/pear7:/usr/share/php7') in Unknown on line 0
      • f:id:sironekotoro:20210329184103p:plain

2.2 API Gateway の設定をする

  • 図2.15:APIGatewayのコンソール

    • API タイプを選択」の画面になるので「REST API」の「構築」ボタンをクリック
    • f:id:sironekotoro:20210328230854p:plain
      • この確認画面が出たらokボタンをクリックして閉じる
  • 図2.16:APIの新規作成

    • 「新しい API」のラジオボタンを選択
    • 名前と説明
      • API名:CustomRuntimeFirstFunction
      • 説明:空欄でok
  • 図2.20:権限の許可

    • f:id:sironekotoro:20210328231512p:plain
    • ここまでは掲載通りいける感じ。くれぐれも「Lambda プロキシ統合の使用」のチェックを忘れないこと!
      • もちろん自分が忘れたのでここで注釈として書いておきます・・・
      • f:id:sironekotoro:20210329185113p:plain
  • ステージ

    • f:id:sironekotoro:20210328232129p:plain
  • 画面確認

    • f:id:sironekotoro:20210328232346p:plain

ということで

回り道してる感もあるんですが、それもまた楽しからずや、です。

Perl を AWS Lambda で使って Hello World! する

前回までのあらすじ

AWS 何もわからん・・・でもやらないと・・・そんな気持ちだけが先走った状態をやっと抜け、 AWS のハンズオンに取り組み始めた sironekotoro 。

しかし、ここで自分が動画ハンズオンが苦手なことに気づいてしまう。追い討ちをかけるように低速度回線(WiMAX 夜間108kbps)が進捗と精神を蝕む。

そして、どうしても AWS Lambda で Perl を動かしたい!という気持ちが抑えられないのだった。

前提

AWS の勉強はこれをやってます。

qiita.com

書いてある順にこなし、AWS Lambda のところまで来ました。

pages.awscloud.com

AWS公式で掲載されているハンズオンも 2019 年に収録されているものなので、AWS のコントロールパネルの配置や情報のたどり方が違っています。

進化の早い業界なので仕方ないですね・・・でも、大体なんとかわかります。

あ、一点だけ、途中に出てくる JSON が invalid なのでそこだけは注意かなぁ。

invalid な(よろしくない)やつ

{
    "statusCode": 200,
    "body": {
        {
            "report_id": 5,
            "report_title" : "Hello, world"
        },
        {
            "report_id": 7,
            "report_title" : "Good morning!"
        }
    }
}

多分こうじゃないかなという

{
    "statusCode": 200,
    "body": [
        {
            "report_id": 5,
            "report_title" : "Hello, world"
        },
        {
            "report_id": 7,
            "report_title" : "Good morning!"
        }
    ]
}

ハンズオン自体はまず Lambda で関数を作り、API GatewayAPI 作って GET を叩き、最後に DynamoDB で入出力の記録を収録するというものです。

途中で書くコードは AWS Lambda が標準でサポートしている Python でした。

Perl 書いて Lambda で Hello,World!

準備

AWS Lambda で Perl を動かす方法はいろいろあるみたいなのですが、今回はレイヤーを使いました。

docs.aws.amazon.com

レイヤーは、ライブラリ、カスタムランタイム、またはその他の依存関係を含む .zip ファイルアーカイブです。レイヤーを使用することで、関数のライブラリを使用することができます。

「Lambda Perl」で検索すると、このカスタムランタイムなるものを使えば Perl が動く、ってことが書いてある・・・あるけど、具体的にどうやるのか分からず。

が、分からないまま進めていきます。蛮勇。

github.com

Perl のレイヤー一覧見ていくと、AWS のリージョンごとに提供されている模様。

今回、自分は東京リージョンで Lambda を作成したので arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-32-runtime-al2:3 を用います。

具体的な進め方

結局、試行錯誤したんで、かつての自分が知りたかったことを書いていきます。いつか、「Perl 入学式 in AWS」 でやるかもしれない・・・(そんな企画はない

  1. AWS の Lambda のページを開く

  2. 「関数の作成」のページ

    • 画面上部にあるオプションは「一から作成」を選択
    • 関数名は任意ですが、今回は「perl_test」とします
    • ランタイムはプルダウンメニュー最下部にある「カスタムランタイム」の中の「Amazon Linux 2 でユーザー独自のブートストラップを提供する」を選択
      • shogo82148 / p5-aws-lambdaUse Prebuild Public Lambda Layers3. For the "Runtime" selection, select Provide your own bootstrap on Amazon Linux 2. より
    • 画面右下のオレンジ色の「関数の作成」をクリック f:id:sironekotoro:20210312223315p:plain
  3. 「関数の概要」部の「Perl_test」の下にある「Layers」をクリック f:id:sironekotoro:20210312223805p:plain

  4. 遷移した先の「レイヤーの追加」ボタンをクリック f:id:sironekotoro:20210312224009p:plain

  5. レイヤーの情報を入力する

    • 「ARN を指定」のラジオボタンを選択
    • 「ARN を指定」のテキストボックスに arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-32-runtime-al2:3 をコピペ f:id:sironekotoro:20210312224422p:plain
    • 画面右下のオレンジ色の「追加」をクリック
  6. 「関数の概要」部の「Perl_test」の下にある「Layers」の右に (1) となっていればレイヤーの追加に成功している

    f:id:sironekotoro:20210312231120p:plain

  7. 「関数の概要」の下にあるコードソースのところで新しいファイルを作る

    • File から New File を選択

      f:id:sironekotoro:20210312231215p:plain

    • 右側のテキストフィールドに以下のコードを記述またはコピペ

      • このサブルーチン名 hundler は固定

    gist.github.com

    • コードを書いたら File から Save を選択し hello.pl という名前で保存する
      • このファイル名 hello.pl は今のところ固定

    f:id:sironekotoro:20210312233303p:plain

    f:id:sironekotoro:20210312233526p:plain

    • 左側のファイル一覧に保存した hello.pl が増えてることを確認する

    f:id:sironekotoro:20210312233751p:plain

  8. デプロイする

    • コードの編集・保存をする都度、上にあるオレンジ色の「Deploy」ボタンを押す

    f:id:sironekotoro:20210312235132p:plain

    • コードの保存をしても、この「Deploy」ボタンを押さないと Lambda 上では変更が反映されないので注意

    • 「Deploy」ボタンを押すと、ボタン右の表示が緑色になり「Deploy」ボタンが押せなくなる

    f:id:sironekotoro:20210312235434p:plain

  9. コード入力欄の上にある「Test」をクリックする

    f:id:sironekotoro:20210312234648p:plain

    • ラジオボタンは「新しいテストイベントの作成」をクリックする
    • イベントテンプレートは hello-world のまま
    • イベント名は適当に PerlTest とかで
    • 入力が終わったら、画面右下のオレンジ色の「作成」ボタンを押す

    f:id:sironekotoro:20210312234319p:plain

  10. 再度「Test」ボタンを押す

    • コードを書いたテキストフィールドの上に「Execution results」タブが増えており、そこにテスト結果が入っている

    f:id:sironekotoro:20210313001802p:plain

もう一歩

ここまでだと、単にテストケース増やしただけなので、もう少しコードを増やしてみます。

増やしたら保存&「Deploy」を忘れずに。

gist.github.com

f:id:sironekotoro:20210313001815p:plain

ということで

Lambda でも Perl 使えるよ!ってな記事でした。

公式の AWS Lambda ハンズオンのように、他のサービスに繋げるのもできるのではないかなぁと思います(やってない)。

ただ、現状では標準モジュール以外のモジュール(cpanm とかでインストールするもの)が使えません。

どうも、モジュールを zip で固めてレイヤーで追加する・・・らしいんですが、その辺りが不明です。

あと、AWSが提供している他のサービスとの連携・・・を Perl でやるには?とか。

aws-sdk-perl

AWS::Lambda とか?

その辺りは勉強進めていきたいですね。

何か良い資料ある方、あるいは教えてやろうという方お待ちしてます。

感想

「何も Perl でやらなくても良いのでは?」

「メモリで課金されるし、Perl 使うと高くつくのでは」

「標準で提供されている言語でやるのが楽なのでは」

などなど、やりながらいろいろ思ったんですが、何やかんやで「好奇心」と 1 週間前の自分に教えてあげたいよねー、というのが推進力でした。

Perl でうるう年判定

最近こんなツイートを見かけました。

ってわけで、このブログでうるう年の判定とか書いてたよなぁ・・・と思って検索したら書いてなかったという。あれー?

Perl でうるう年判定

条件分岐を教えるネタというと FizzBuzz なんですが、うるう年判定もいいかもしれないですね。

以下、wikipedia から拾ってきたうるう年判定の条件です。

  1. 400で割り切れる場合は閏年
  2. 400で割り切れず、100で割り切れる場合は平年
  3. 条件 1. と 2. を両方とも満たさない(400で割り切れず、かつ100でも割り切れない)場合、4で割り切れれば閏年、そうでなければ平年

ja.wikipedia.org

素直に書いてみました。

#!/usr/bin/env perl
use strict;
use warnings;

my $year = 1900;

# 1. 400で割り切れる場合は閏年
# 2. 400で割り切れず、100で割り切れる場合は平年
# 3. 条件 1. と 2. を両方とも満たさない(400で割り切れず、かつ100でも割り切れない)場合、4で割り切れれば閏年、そうでなければ平年

if ( $year % 400 == 0 ) {
    print "うるう年!\n";
}
elsif ( $year % 100 == 0 ) {
    print "平年\n";
}
elsif ( $year % 4 == 0 ) {
    print "うるう年!\n";
}
else {
    print "平年\n";
}

1 行でうるう年判定

検索してたら、東工大にいらっしゃる出口弘先生が神戸女学院大学にいた頃のページが出てきました。

wwws.kobe-c.ac.jp

C言語で解くうるう年の問題(閏年の判定)がのってます。

そこにこんな一文が

isleap関数をif文を1個で実現してみよ

となると、論理演算子です。Wikipedia にも載ってるこれを使います

また、閏年の規則は次の一つだけの論理式に読み替えることもできる。

(400で割り切れる)または(100で割り切れずかつ4で割り切ることができる)ならば閏年、そうでなければ平年

if ( ( $year % 400 == 0 && $year % 100 != 0 ) || $year % 4 == 0 ) {
    print "うるう年!\n";
}
else {
    print "平年\n";
}

1 個で書けというのがあるなら 1 行でかけってのもあるかなぁ、と書いてみました。三項演算子の重ねがけです。

print $year % 400 == 0 ? "うるう年" : $year % 100 == 0 ? "平年" : $year % 4 == 0 ? "うるう年" : "平年";

見やすく改行してみるとこうです。1 行じゃなくなってしまいますが・・・

print $year % 400 == 0 ? "うるう年"
    : $year % 100 == 0 ? "平年"
    : $year % 4 == 0   ? "うるう年"
    :                    "平年";

うるう年についての忘れられない話

2018年に開催された 設計Night2018 powered by Classi での @magnoria さんのこのトーク。2月29日生まれの人は平年のいつ歳を取るのか?とか知らなくてへぇ〜!ってなったトークでした。

logmi.jp

ところで

「最近こんなツイートを見かけました」から始まるのって定型文ぽくて、昔そういう短編みたなぁ・・・ってちょっと記憶さぐったら、夏目漱石の「夢十夜」でした。

漱石先生は「こんな夢を見た。」から書き始めてますね。しっかし激エモだなぁ・・・

「死んだら、埋めて下さい。大きな真珠貝で穴を掘って。そうして天から落ちて来る星の破片を墓標に置いて下さい。そうして墓の傍に待っていて下さい。また逢いに来ますから」

www.aozora.gr.jp