はじめに
AWSのLambdaはOSがAmazon Linux 2上で実行されるとのことです。ですがPowerShellの一部のモジュールなど、Amazon Linux 2上では動かないものもあったりします。
今回、別のOSで動かす必要があったため、自作のコンテナからLambdaを作成する方法が記載されいているページありましたので、それをやってみました。
普通になぞるだけでは味気なかったので、一部CloudFormationを使うようにしてみました。
参考
環境
- Cloud9
- Docker
- インストール済み
- コンテナを扱うので、そこそこの容量は必要かも
- 自分は50GBで行いました。
- Docker
やったこと
ディレクトリ・ファイル作成
まずはプロジェクトのディレクトリを作成し、よく使う情報を環境変数にセットします。
# プロジェクトディレクトリ作成
$ mkdir sample-ecr-lambda
$ cd sample-ecr-lambda
# リージョンとアカウントIDを環境変数にセット
$ REGION="ap-northeast-1"
$ ACCOUNTID=$(aws sts get-caller-identity --output text --query Account)
次にLambdaで実行させるPythonスクリプトを作成します。
# pythonファイル作成
$ touch app.py
import json
def handler(event, context):
return {
"statusCode": 200,
"body": json.dumps(
{
"message": "hello world",
}
),
}
参考のページではまずZip圧縮ファイルを使ってLambdaを作成する手法を紹介しています。
私はZipで作るところは飛ばして、Dockerを作るところから続けています。
$ touch Dockerfile
FROM public.ecr.aws/lambda/python:3.8
COPY app.py ./
CMD ["app.handler"]
Dockerイメージを作成します。
$ docker build -t func1 .
# func1 というイメージがあるか確認
$ docker images
一旦テスト
この時点でPythonが動くか確認します。
ベースとなるイメージがLambda用のものであれば、RIEというものが組み込まれており、それを使ってテストできます。
$ docker run --rm -p 9000:8080 func1:latest
# 別のターミナルから
$ curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
# docker runしたターミナルで
Ctrl+C
ECRリポジトリ作成・イメージPUSH
ECRをCFnで作成します。
# ECRリポジトリ作成CFn
$ touch createECRRepository.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create ECR Stack Test
Resources:
########################################################
### ECR Repository
########################################################
TestEcrPoc:
Type: AWS::ECR::Repository
Properties:
RepositoryName: func1
$ aws cloudformation create-stack --stack-name tempecrrepo --template-body file://createECRRepository.yaml --region ${REGION}
先程作成したイメージに、ECRのURIを参照先としてタグ付与します。
# タグ付与
$ docker tag func1:latest \
${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/func1:latest
次にレジストリに対して Docker CLI を認証します。
# 認証
$ aws ecr get-login-password --region ${REGION} | docker login --username AWS --password-stdin ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com
Login Succeeded
作ったイメージをPUSHします。
# PUSH サイズは180MB程度
$ docker push ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/func1:latest
Lambada作成
Lambadaを作成するCFnファイルを記述します。
# Lambda作るCFn
$ touch createLambda.yaml
たくさん書いてありますが、Lambda用のロググループとIAMロールを一緒に作っているだけです。
パラメータにはLambdaの名前とECRのイメージURIを指定するようにしています。
AWSTemplateFormatVersion: "2010-09-09"
Description: Create ECR Stack Test
Parameters:
LambdaFunctionName:
Type: String
ImageUri:
Type: String
Resources:
########################################################
### Log Group
########################################################
FunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${LambdaFunctionName}"
RetentionInDays: 3653
########################################################
### IAM Role
########################################################
FunctionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "for-lambdafunction-${LambdaFunctionName}"
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: '/service-role/'
Policies:
# CloudWatch
- PolicyName: write-cloudwatchlogs
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${LambdaFunctionName}:*"
########################################################
### Lambda Function
########################################################
TargetFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Ref LambdaFunctionName
Role: !GetAtt FunctionRole.Arn
PackageType: Image
Code:
ImageUri: !Ref ImageUri
パラメータに渡す文字列が長いため一度変数に格納し、Lambda作成時の引数に使います。
# CFnのパラメータに使う文字列を生成
$ DIGEST=$(aws ecr list-images --repository-name func1 --region ${REGION} --out text --query 'imageIds[?imageTag==`latest`].imageDigest')
$ IMAGEURI=${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/func1@${DIGEST}
# Lambda作成。IAM作るのでcapabilities指定
$ aws cloudformation create-stack --stack-name tempecrlambda \
--template-body file://createLambda.yaml \
--region ${REGION} \
--parameters \
ParameterKey=LambdaFunctionName,ParameterValue=func1-container \
ParameterKey=ImageUri,ParameterValue=${IMAGEURI} \
--capabilities CAPABILITY_NAMED_IAM
# 実行
$ aws lambda invoke --function-name func1-container --region ${REGION} output ; cat output
片づけ
作ったものを削除していきます。CFnで作っているので簡単に削除できます。
# Lambda削除
$ aws cloudformation delete-stack --stack-name tempecrlambda --region ${REGION}
# ECR上イメージ削除
aws ecr batch-delete-image --repository-name func1 --region ${REGION} --image-ids imageDigest=${DIGEST}
# ECRリポジトリ削除
$ aws cloudformation delete-stack --stack-name tempecrrepo --region ${REGION}
# Dockerイメージを確認して、削除
$ docker images | grep func1
$ docker rmi <<IMAGENAME>>
おわりに
今回はDockerイメージからLambdaを作成してみました。
Lambdaは普段SAMから作成していましたが、Dockerイメージから作成することで、Lambdaの用途がかなり広がると思います。
簡単に試すことができましたので、やったことない方は気軽に試してみてください。