TerraformでAWS LambdaLayer with Python を利用する

ほぼclassmethodさんの記事通りですが

ソースコード

github.com

$ tree
.
├── README.md
├── build-layer.sh
├── iam.tf
├── lambda
│   ├── function.zip
│   └── lib.zip
├── lambda.tf
├── provider.tf
├── requirements.txt
├── src
│   └── index.py
├── terraform.tfstate
├── terraform.tfstate.backup
└── variables.tf

DeployするLambda functionのソースコード

import os
import sys
import requests
from bs4 import BeautifulSoup


def lambda_handler(event: dict, context):
    response = requests.get("http://example.com/")
    bs = BeautifulSoup(response.text)
    return bs.title.name

lambda functionでrequestsとBeautifulSoupを使いたい。そのためにlambda layerを利用する。

Lambda Layer

見るのはlambda.tfとbuild-layer.sh

data "archive_file" "function" {
  type        = "zip"
  source_file = "./src/index.py"
  output_path = "lambda/function.zip"
}

data "archive_file" "layer" {
  type        = "zip"
  source_dir  = "./lib"
  output_path = "lambda/lib.zip"
}

resource "aws_lambda_layer_version" "layer" {
  filename         = "${data.archive_file.layer.output_path}"
  layer_name       = "lib"
  source_code_hash = "${data.archive_file.layer.output_base64sha256}"

  compatible_runtimes = ["python3.6"]
}

resource "aws_lambda_function" "example_lambda" {
  function_name = "example_lambda"

  runtime          = "python3.6"
  handler          = "index.lambda_handler"
  filename         = "${data.archive_file.function.output_path}"
  role             = "${aws_iam_role.iam_role.arn}"
  source_code_hash = "${data.archive_file.function.output_base64sha256}"
  layers           = ["${aws_lambda_layer_version.layer.arn}"]
}

肝になるのはlambda functionとlayerのsourceの参照先の違い。

lambda functionのソースコードproject/src/index.pyを利用するが、 lambda layerは lib/ を利用する。pipライブラリのinstallについてはnull_resourceを利用してterraformで完結しようとしたが、うまく出来なかったので、shellファイルで実行する。何か良い方法あれば教えてほしい

#!/usr/bin/env bash

if [ -d lib/ ]; then
  rm -rf lib/
fi

echo "bundle pypi packages"
pip install -r requirements.txt -t lib/python

find lib -type f | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm

pip installで lib/python を指定しているのはlambda functionからlambda layerを参照するpathを通すため。lib/packagesなどではpathが通らないので注意。 __pycache__と.pyc、pyoを削除しているが、これはpip installをしても__pycache__配下のファイルの影響で差分が発生してしまうから。

$ sh build-layer.sh
$ terraform plan
$ terraform apply

参考