結構引っかかったのでメモ。
Lambda用のPerl Container
コンテナ自体はshogoさんが動くものを置いていただいているのでそれをベースイメージとすればよい。感謝感謝。
自分で作る手順も書いてあるのでこんどやる。
手順としては、まず 上記のコンテナをFROMとして Dockerfile
をつくりECRにビルドしてpush、そしてビルドしたECRのイメージをLambdaで使うという設定をすればよい。
実際にやってみる
だいたいコピペ。
ECRとかLambdaのIAMとかは適宜作ってください。
以下の Dockerfile
を用意。
FROM public.ecr.aws/w2s0h5h2/p5-aws-lambda:base-5.32-paws.al2
COPY handler.pl /var/task/
CMD [ "handler.handle" ]
以下の handler.pl
を用意
use utf8;
use warnings;
use strict;
$| = 1;
sub handle {
my $payload = shift;
print "log test from perl";
warn "test";
return +{"hello" => "lambda"};
}
1;
以下のようなビルドスクリプトがあるといい感じかもしれない。
ローカルでビルドしたimagesとsha256が同じやつがECRにいないかをチェックして
いなければECRにpushするということをやる。
APP=xxx
REPO=$(aws ecr describe-repositories --repository-names $APP --query "repositories[0].repositoryUri" --output text | perl -pe '$_ = (split "/")[0]')
DATE=$(date '+%Y%m%d_%H%M%S')
docker build . -t $APP
docker tag "$APP:latest" "$REPO/$APP:$DATE"
LOCAL_BUILD=$(docker inspect $APP | jq '.[0].RepoDigests[0] | split("@")[1]' -r)
REMOTE_BUILDS=$(aws ecr list-images --repository-name $APP | jq '.imageIds[].imageDigest' -r)
REMOTE_COUNT=$(echo "$REMOTE_BUILDS" | sort | uniq | wc -l)
ALL_COUNT=$(echo "$LOCAL_BUILD\n$REMOTE_BUILDS" | sort | uniq | wc -l)
if [ $ALL_COUNT = $REMOTE_COUNT ]; then
echo "build is same. skipping..."
else
echo "build is different. push to ecr..."
aws ecr get-login-password | docker login --username AWS --password-stdin $REPO
docker push "$REPO/$APP:$DATE"
fi
ゆくゆくはCIもやりましょう。
はまったこと・注意すること
標準出力のflushをオンにする。
Perlにおいては $| = 1
をやればよい。
自作のコンテナでlambdaを動かす場合は、標準出力がバッファリングされないように設定しないとCloudwatch Logsに出ないっぽい。rubyのコンテナを参考にしたところ、標準出力をflushにしていたので倣ったところ出るようになった。
最初普通に print
をやっても出力されず、warn
をやったら出力されたのでピンときた。
もしかして自作コンテナだとログは自分で CloudWatch Logsの PutLogEvents
を呼ばないとだめなのか?と思ったけどそうじゃなくてよかった。
なお、Lambda上だとSTDOUTとSTDERRが一緒くたに扱われる上に、バッファリングがオフにしないといけないので
print 123;
warn 456
のようなコードが
123456 at /var/task/handler.pl line 9.
と出力されるので一瞬びっくりするかもしれない。
loggerのライブラリを使うべきで素のwarnとかprintは使うべきではないっぽいですね。
CloudWatchのログ出力名は関数名と同じ
たとえばLambdaの関数名を moge
とした場合、
作成されるCloudWatch Logsのロググループ名は /aws/lambda/moge
固定。
serverlessみたいなフレームワークにまかせっきりにしてたことなので知りませんでしたね。
名前が固定されているからといって何もせずにログが出るということはなく、下記みたいな権限設定が必要なのも忘れずに。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Action": "logs:CreateLogStream",
"Resource": "arn:aws:logs:ap-northeast-1:000000000000:log-group:/aws/lambda/moge:*"
},
{
"Sid": "2",
"Effect": "Allow",
"Action": "logs:PutLogEvents",
"Resource": "arn:aws:logs:ap-northeast-1:000000000000:log-group:/aws/lambda/moge:*:*"
}
]
}
まとめ
しかし、lambda docker
で検索するとローカルでのlambdaの開発をdockerでやるみたいな話がいっぱい出てきて、lambdaをDocker containerで動かす話のググラビリティが低くて困る。どう検索したらいいんでしょうね。
上記文を書いて思ったけど、全然前者と後者の区別がつかないねこれ。
LambdaのDocker Containerの開発自体は、さすがにserverlessみたいなフレームワークほど手軽ではないものの、いうほど大変でないのでとてもよいです。