定期実行するLambdaをAWS CDKでデプロイする(Docker imageを使用)

2023年4月20日掲載

キービジュアル

共通プラットフォーム開発本部の宮田銀河 (入社3年目) です。

本記事では、定期実行するLambdaをAWS Cloud Development Kit (CDK) でデプロイする(Docker imageを使用)方法を紹介します。CDKでは、クラウドリソースの構成をPythonやTypescriptなどのプログラミング言語で記述できます。

また、Docker imageを使用することで、Lambda上で本来使えないnmapなどのツールを使うことができます。AWS CDKを使ってみたい方、CDKを使ってLambdaをデプロイしたい方に向けた記事です。

使用した技術はAWS CDK, Lambda, EventBridge, IAM, Dockerです。

目次

  • 本記事はnmapなどのセッションベースのアプリケーションをLambdaで利用したい方の解決策になります
  • 方法としては、動かしたアプリケーションをあらかじめインストールしたDocker imageを使用してLambdaをデプロイします。
    毎回手動でデプロイするのはめんどうなので、AWS CDKを使ってデプロイをIaC化します。

想定読者

  • CDKを触ってみたい方
  • セッションベースなアプリケーションをLambdaで実行したい方
  • Docker imageを使用してLambdaをデプロイしたい方
  • ソフトバンクの若手エンジニアの働きを知りたい方

システム構成図

本記事で作成するシステム構成図を下図に示します。

構成図

開発者はローカルのPCでcdk deployとコマンドを実行するだけで、AWS環境にリソースをデプロイすることができます。

AWS CDKとは

Cloud Development Kitの略です。 CDKを簡単に説明すると、クラウドリソースの構成をPythonやTypescriptなどのプログラミング言語で記述できるというものです。Python大好きの私からすると、yamlやjsonでリソースを定義しなくて良いという嬉しさがあります。cdk depoyとコマンドを実行するだけで、Pythonファイルで定義したリソースを作成できます。CloudFormationのyamlファイルは書かなくて良いのです。実際はCDKの裏でCloudFormationが利用されています。詳細は公式ドキュメントをご覧ください。

CDKを初めて使用する場合は、セットアップのために以下のコマンドを実行する必要があります

npm install -g aws-cdk
cdk bootstrap

1行目のコマンドにより、aws-cdkをインストールします。2行目のコマンドにより、CloudFormation (CDKが裏で利用している) を使うためのS3 バケットやIAM Role等を作成します。この2行のコマンドを実行するだけで、CDKを使ったリソースのデプロイが可能になります。

リソース作成コード

  1. Lambdaに付与するIAM Role作成コード
  2. Lambda作成コード
  3. Lambdaを定期実行するためのEventBridge作成コード

をfoo_stack.pyとしてfooディレクトリ配下に配置します。LambdaはDocker imageを使用します。

from aws_cdk import (
    aws_events as events,
    aws_lambda as lambda_,
    aws_iam as aws_iam,
    aws_events_targets as targets,
    Duration,
    Stack,
)
from constructs import Construct
import os
from dotenv import load_dotenv

load_dotenv()

class FooStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        # 1. IAM poloicy (for Lambda Function)
        lambdaRole = aws_iam.Role(
            self,
            "lambdaRole",
            role_name="foo-lambda-role",
assumed_by=aws_iam.ServicePrincipal("lambda.amazonaws.com"),
        )
     lambdaRole.add_managed_policy(aws_iam.ManagedPolicy.from_aws_managed_policy_name("AWSLambdaExecute"))
        lambdaRole.add_managed_policy(
            aws_iam.ManagedPolicy.from_aws_managed_policy_name("追加したいManagedのRoleがあれば")
        )
        # 2. lambda configuration
        lambdaFn = lambda_.DockerImageFunction(
            self,
            "FooFunction",  # リソース名
            timeout=Duration.seconds(300),
            code=lambda_.DockerImageCode.from_image_asset("lambda/"),
            role=lambdaRole,
            retry_attempts=0,
            environment={
                "Foo": os.environ["Foo"],
                "Bar": os.environ["Bar"],
            },
        )
        # 3. cron configuration
        rule = events.Rule(
            self,
            "Rule",
            schedule=events.Schedule.cron(minute="0", hour="*/8", month="*", week_day="MON-FRI", year="*"),
        )
        rule.add_target(targets.LambdaFunction(lambdaFn))

上記のコードを一部解説します。

  • lambdaRole.add_managed_policyを使用して、付与したいIAMRoleを付与できます(便利)
  • code=lambda_.DockerImageCode.from_image_asset("lambda/")により、lambdaディレクトリ配下のDockerfileを参照することができます。
  • Schedule.cron(minute="0", hour="*/8", month="*", week_day="MON-FRI", year="*")と書くことで、平日の8時間おきにLambdaを実行することができます。

Lambda用のDockerfileの作成

Lambda用のDockerfileは以下です。Dockerを使用した経緯を説明すると、元々Lambda上でnmapを使いたかったのですが、AWSが使用しているデフォルトのLambda環境にはnmapがインストールされてませんでした。そのため、AWSが用意しているLambdaのイメージにnmapのインストールを実行して、そのイメージを使う方針にしました。nmapの他に使用したいツール等あればこの段階でインストールしましょう。

FROM public.ecr.aws/lambda/python:3.8

COPY requirements.txt ${LAMBDA_TASK_ROOT}
RUN  pip3 install -r requirements.txt --target "${LAMBDA_TASK_ROOT}" && yum install -y nmap
COPY . ${LAMBDA_TASK_ROOT}

CMD [ "foo.handler" ] 

上記のDockerfileをlamba/に配置します。ディレクトリの構成は以下です。

.
├── app.py
├── lambda
│   ├── Dockerfile
│   ├── foo.py # lambdaで実行したいコード
│   ├── requirements.txt # 使用するライブラリ
├── foo
│   ├── __init__.py
│   └── foo_stack.py

後はローカルのPCでcdk deployとコマンドを実行すれば、foo_stack.pyに定義したLambdaやIAM Role等がデプロイされます (便利)。

本システムの構築・運用中に遭遇した問題

ここでは遭遇した問題を2つまとめました。

1. Pythonで特定のライブラリを使用するために、Lambda Layerを作成する必要があった

Lambda上でrequestsなどのPythonのライブラリを使用するためには、使いたいライブラリをzipしてLambda Layerを作成した後に、Lambdaにアタッチしなければいけません。そのため以下のようなコマンドを実行して、作成したzipファイルをAWSにアップロードして、Lambda layerを作成していました (少し手間だった

cd lambda
pip install -r requirements.txt -t ./python
zip -r layer.zip python/

→対処法: Docker imageにPythonライブラリを内包することにより解決しました。

2. ローカルPCでdockerを起動しないとエラーが発生した

dockerを起動しない状態でcdk deployを実行すると、以下のログが出力されます。

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

→対処法: dockerを起動した状態でcdk deployを実行する (他にも良いやり方はありそうです。暫定対応です)。

今後やりたいこと

今の状態だとローカルPCでdockerを起動していなければcdk deployできません。新しく開発メンバーが入った時には、ローカルのPCにcdk等をインストールしなければいけません。この手間を省くためにも、リソースのデプロイまでを自動化したいと考えています。具体的にはAWS CodePiplineを使用して実現する予定です。開発者がGitHubやAWS CodeCommitにコードをpushしたら、Code Deploy上でcdk deployを実行しリソースがデプロイされる構成を考えています。

まとめ

本記事では、AWSのCDKを使ってLambdaをデプロイする方法を紹介しました。開発者は必要なDockerfileとCDKのコードを用意して、cdk deployを実行するだけで、リソースのデプロイが可能になります。

AWS CDKを使ってみたい方、CDKを使ってLambdaをデプロイしたい方の参考になれば幸いです。

この記事を読んで興味を持っていただいた学生・エンジニアの方は、ぜひ当社の採用に応募して頂けると嬉しいです。

関連サービス

ソフトバンク新卒採用

常に進化し続けるソフトバンクを楽しみながら

  • いかなる仕事もチャンスと捉えやり遂げる
  • さまざまな機会へ自ら意欲的に手を挙げる

そんな一人一人の挑戦が会社の未来を創ります

おすすめの記事

条件に該当するページがございません