AWS LambdaのコードをTerraformでデプロイする

AWS LambdaのコードをTerraformでデプロイする
目次

今更感もありますが、今日はTerraformでのAWS Lambdaのコード化について書きます。 AWS Lambdaは Cloud9 がコンソール上に組み込まれたこともあり、開発がさらに容易になりました。 ブラウザエディタは そのままwebにつながる というのが最大の強みですが、まだまだ手元のリポジトリでコードを管理している手前、AWSのサービスだけで完結できていないのが現状です。 今回はAWS LambdaのコードをTerraformを使ってデプロイする方法を説明しようと思います。

↓ちなみに下が組み込まれたCloud9

cloud9_lambda

TerraformでAWS Lambdaをデプロイしたい

Infrastructure as Code はクラウド界隈でバズってだいぶ時間も立っていますので、あまりここでは触れません。 必要に応じて界隈の方のブログや以下の書籍を読んでください。



AWS Lambdaがサービスとして登場した頃は、簡易なバッチ的な仕組みとしての用途が多く、作り捨てなコードが多かったです。 その後、連携可能な他のAWSサービスも増えて、VPC内に立ち上げることも可能になり(起動時間はかなり遅いですけど)、用途の幅に広がりが出てきました。 そんな 「まぁ、Lambdaでいっか」 ケースが増えると同時に、一度デプロイしたLambdaのコードを修正して再デプロイするというケースも増えてきました。

業務上 Terraform を使ってAWSリソースをコード化しているので、Lambdaもその管理の対象にしようと思ったのが契機です。

やってみる

実際にLambdaをTerraformでデプロイするコード化してみました。 コードサンプルは こちら にあります。

簡単にリポジトリの説明をしておきます。

デプロイ用のマシンに必要なライブラリ等は以下になります。

  • Terraform
  • Python 3.6

またディレクトリ構成はこんな感じです。

 1.
 2├── Makefile
 3├── README.md
 4├── build.sh
 5├── lambda-src
 6│   ├── __init__.py
 7│   └── main.py
 8├── requirements.txt
 9└── terraform
10    ├── backend.tf
11    ├── dev.tfvars
12    ├── lambda.tf
13    ├── provider.tf
14    └── variables.tf

lambda-src ディレクトリにはLambdaで実行するPythonコード、 terraform ディレクトリにはLmabdaのデプロイに使用するterraformの設定が格納されています。 めんどい前処理の類はシェル(build.sh)でラップしてあって、開発者は make のサブコマンドだけ意識しておけば良い、という作りにしています。 この方法自体は我流なので、よりスマートな方法はあると思います。

以降は実装する上でのポイントだけ記載していきます。

コードのエントリータイプはzipにしよう

Lambdaにソースコードを適用する方法は3種類存在します。

code_entry_type

  • Edit Code Inline
    • ブラウザ上のエディタに直接書く方法。デプロイ後のコードを突貫で修正したりする時によく使う。
  • Upload a .ZIP file
    • zipファイルでアップロードする方法。今回はこれを採用する。
  • Uplaod a file from Amazon S3
    • S3からファイルを読み込む方法。

個人的には2番目の zipファイルでアップロードする方法 をオススメします。

理由としては以下

  1. 依存モジュールを含めてアップロードできる
  2. わざわざS3を積極的に経由するケースが思いつかない。(Lambdaに対して直接操作できない時とか?)

シェルでzip圧縮したいソース一式を作成する

シェルを使えば何でもできてしまうので、Terraformで完結させたい方には興ざめかもしれませんが、低コストだったのでこれにしました。 build.sh の処理を見ていただければわかるのですが、 zip圧縮させたいファイル郡を管理する必要があるので、 専用の workspace ディレクリを作成し、そこに依存モジュールとソースコードをまるごと放り込みます。

  • build.sh
 1#!/usr/bin/env bash
 2
 3SCRIPT_DIR=$(cd $(dirname $0); pwd)
 4WORKSPACE=${SCRIPT_DIR}/workspace
 5SRC_DIR=${SCRIPT_DIR}/lambda-src
 6
 7if [ -d ${WORKSPACE} ]; then
 8    rm -rf ${WORKSPACE}
 9fi
10mkdir ${WORKSPACE}
11
12pip3 install -r ${SCRIPT_DIR}/requirements.txt -t ${WORKSPACE}
13cp -rf ${SRC_DIR}/* ${WORKSPACE}

Terraformでzip圧縮&デプロイ

workspace ディレクトリのzip圧縮とデプロイを定義します。 terraformで archive_file というデータリソースを使用することで、指定されたディレクトリをzip圧縮して出力することができます。 加えて、Lambda関数の作成の際に aws_lambda_function リソースの source_code_hash プロパティに、zipアーカイブしたデータリソースのbase64エンコードを指定することができるので、これでzipのデプロイコードの完成です。

 1#####################################
 2#Lambda
 3#####################################
 4resource "aws_lambda_function" "auth_log_monitoring" {
 5    filename = "../lambda.zip"
 6    function_name = "do_something"
 7    role = "arn:aws:iam::${var.account_id}:role/XXXXXXRole"
 8    handler = "main.lambda_handler"
 9    source_code_hash = "${data.archive_file.lambda_zip.output_base64sha256}"
10    runtime = "python3.6"
11    timeout = 150
12}
13
14data "archive_file" "lambda_zip" {
15    type = "zip"
16    source_dir  = "../workspace"
17    output_path = "../lambda.zip"
18}

ビルド&デプロイをつなげる

あとは build.sh でのビルド処理とterraformでのデプロイをつなげてあげればOKです。 今回は Makefile に以下のような定義をして、コマンド一発で処理ができるようにラップしています。

  • Makefile
1deploy:
2	@${CD} && \
3		sh ../build.sh && \
4		terraform workspace select ${ENV} && \
5		terraform apply \
6        -var-file=${VARS}

あとは make deploy を打てば実行できます。(リポジトリ的にはterraformのリモートバケットの初期化を先に行う必要はあります。)

まとめ

Terraformを使用して、AWS Lambdaのソースコードのデプロイができるようになりました。 実際にはシェルを間にかませてビルドを行なっていますが、シェル内での処理自体はシンプルなので、横展開もしやすくなっています。 1点欠点としては、ランタイムがpythonの場合にはterraform実行時に毎回ハッシュにdiffが出てしまう という点。つまり、毎度デプロイしてしまうという所です。 しかし、今あるコードを正としてデプロイし続けることに問題がなければ、目をつむっても良い欠点なので、今の所気にしていません。 ちなみにランタイムがNodeだとこれはおきませんでした。

参考にさせていただいたサイト