LoginSignup
6
4

More than 1 year has passed since last update.

Lambdaをコンテナイメージから作る

Posted at

はじめに

AWSのLambdaはOSがAmazon Linux 2上で実行されるとのことです。ですがPowerShellの一部のモジュールなど、Amazon Linux 2上では動かないものもあったりします。

今回、別のOSで動かす必要があったため、自作のコンテナからLambdaを作成する方法が記載されいているページありましたので、それをやってみました。
普通になぞるだけでは味気なかったので、一部CloudFormationを使うようにしてみました。

参考

環境

  • Cloud9
    • Docker
      • インストール済み
    • コンテナを扱うので、そこそこの容量は必要かも
      • 自分は50GBで行いました。

やったこと

ディレクトリ・ファイル作成

まずはプロジェクトのディレクトリを作成し、よく使う情報を環境変数にセットします。

# プロジェクトディレクトリ作成
$ 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
app.py
import json

def handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps(
            {
                "message": "hello world",
            }
        ),
    }

参考のページではまずZip圧縮ファイルを使ってLambdaを作成する手法を紹介しています。
私はZipで作るところは飛ばして、Dockerを作るところから続けています。

$ touch Dockerfile
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
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を指定するようにしています。

createLambda.yaml
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の用途がかなり広がると思います。
簡単に試すことができましたので、やったことない方は気軽に試してみてください。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4