- 
                Notifications
    You must be signed in to change notification settings 
- Fork 65
add terraform lambda layers sample + migrate serverless sample to new dir #238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| .terraform | ||
| .venv | ||
| build | ||
| .terraform.lock.hcl | ||
| output.json | ||
| terraform.* | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| export AWS_ACCESS_KEY_ID ?= test | ||
| export AWS_SECRET_ACCESS_KEY ?= test | ||
| export AWS_DEFAULT_REGION = us-east-1 | ||
| SHELL := /bin/bash | ||
| PYTHON_BIN ?= $(shell which python3 || which python) | ||
|  | ||
| usage: ## Show this help | ||
| @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//' | ||
|  | ||
| start: | ||
| localstack start -d | ||
|  | ||
| install: ## Install dependencies | ||
| @which localstack || pip install localstack | ||
| @which awslocal || pip install awscli-local | ||
| @which terraform || (\ | ||
| echo 'Terraform was not found, installing locally' && \ | ||
| wget https://releases.hashicorp.com/terraform/1.0.8/terraform_1.0.8_linux_amd64.zip && \ | ||
| unzip terraform_*.zip && \ | ||
| rm terraform_*.zip) | ||
| @test -e .venv || ($(PYTHON_BIN) -m venv .venv; source .venv/bin/activate; pip3 install terraform-local;) | ||
|  | ||
| package: | ||
| source .venv/bin/activate; pip install \ | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A comment pointing to the AWS packaging docs for Python would be helpful here: https://docs.aws.amazon.com/lambda/latest/dg/python-package.html | ||
| --platform manylinux2014_x86_64 \ | ||
| --target=package \ | ||
| --implementation cp \ | ||
| --only-binary=:all: \ | ||
| --upgrade \ | ||
| --requirement requirements.txt \ | ||
| --target build/my-lambda-layer/python | ||
|  | ||
| init: | ||
| tflocal init | ||
|  | ||
| deploy: | ||
| tflocal apply --auto-approve | ||
|  | ||
| invoke: | ||
| awslocal lambda invoke \ | ||
| --function-name my-lambda-function \ | ||
| output.json | ||
| cat output.json | ||
|  | ||
| run: start install package init deploy invoke | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding some (minimal) validation step. We should at least check that the Lambda invoked successfully and did not fail for the CI to catch regressions. | ||
|  | ||
| clean: | ||
| rm -rf build | ||
| rm -rf .terraform | ||
| rf -f output.json | ||
|  | ||
| .PHONY: start install init deploy invoke clean | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: incomplete missing (e.g., missing  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # Lambda Layers with Terraform | ||
|  | ||
| Simple demo application illustrating Lambda layers using LocalStack, deployed via Terraform. | ||
|  | ||
| ## Prerequisites | ||
|  | ||
| * LocalStack | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should clarify that Layers require the Pro image here | ||
| * Docker | ||
| * Terraform & `tflocal` | ||
| * Python & `pip` | ||
| * `make` | ||
|  | ||
| ## Installing | ||
|  | ||
| To install the dependencies: | ||
| ``` | ||
| make install | ||
| ``` | ||
|  | ||
| ## Running | ||
|  | ||
| Make sure that LocalStack is started: | ||
|  | ||
| ``` | ||
| LOCALSTACK_AUTH_TOKEN=... DEBUG=1 localstack start | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. General Idea for docs: Would it make sense to use a variable such as  | ||
| ``` | ||
|  | ||
| Deploy the app locally and run a Lambda test invocation: | ||
|  | ||
| ``` | ||
| make run | ||
| ``` | ||
|  | ||
| You should see a success output in the terminal: | ||
| ``` | ||
| {"status": "success"} | ||
| ``` | ||
|  | ||
| ... and your LocalStack container should contain output similar to this: | ||
|  | ||
| ``` | ||
| 2024-05-17T15:46:22.870 DEBUG --- [et.reactor-1] l.s.l.i.version_manager : [my-lambda-function-52785b61-d14d-4871-8074-d5ab5fc49bb1] REPORT RequestId: 52785b61-d14d-4871-8074-d5ab5fc49bb1 Duration: 20.65 ms Billed Duration: 21 ms Memory Size: 128 MBMax Memory Used: 128 MB | ||
| 2024-05-17T15:46:22.872 DEBUG --- [et.reactor-1] l.s.lambda_.provider : Lambda invocation duration: 2230.03ms | ||
| 2024-05-17T15:46:22.874 INFO --- [et.reactor-1] localstack.request.aws : AWS lambda.Invoke => 200 | ||
| ``` | ||
|  | ||
| ## License | ||
|  | ||
| This code is available under the Apache 2.0 license. | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| terraform { | ||
| required_providers { | ||
| aws = { | ||
| source = "hashicorp/aws" | ||
| version = "~> 5.0" | ||
| } | ||
| } | ||
| } | ||
|  | ||
| provider "aws" { | ||
| region = "us-east-1" # Replace with your preferred region | ||
| } | ||
|  | ||
| # Lambda Layer | ||
| data "archive_file" "lambda_layer_zip" { | ||
| type = "zip" | ||
| source_dir = "${path.module}/build/my-lambda-layer" # Path to your Python dependencies directory | ||
| output_path = "${path.module}/build/lambda_layer.zip" | ||
| } | ||
|  | ||
| # Layer bucket | ||
| resource "aws_s3_bucket" "lambda_layer_bucket" { | ||
| bucket = "my-lambda-layer-bucket" | ||
| } | ||
|  | ||
| # Layer ZIP upload | ||
| resource "aws_s3_object" "lambda_layer" { | ||
| bucket = aws_s3_bucket.lambda_layer_bucket.id | ||
| key = "lambda_layer.zip" | ||
| source = data.archive_file.lambda_layer_zip.output_path | ||
| depends_on = [data.archive_file.lambda_layer_zip] # Triggered only if the zip file is created | ||
| } | ||
|  | ||
| # Lambda Layer from S3 | ||
| resource "aws_lambda_layer_version" "dependencies" { | ||
| s3_bucket = aws_s3_bucket.lambda_layer_bucket.id | ||
| s3_key = aws_s3_object.lambda_layer.key | ||
| layer_name = "my-lambda-layer" | ||
| compatible_runtimes = ["python3.12"] | ||
| depends_on = [aws_s3_object.lambda_layer] # Triggered only if the zip file is uploaded to the bucket | ||
| } | ||
|  | ||
| # Lambda Function | ||
| data "archive_file" "lambda_function" { | ||
| type = "zip" | ||
| source_file = "${path.module}/src/lambda_function.py" | ||
| output_path = "${path.module}/build/lambda_function.zip" | ||
| } | ||
|  | ||
| resource "aws_lambda_function" "my_lambda" { | ||
| filename = data.archive_file.lambda_function.output_path | ||
| function_name = "my-lambda-function" | ||
| role = aws_iam_role.lambda_role.arn # See IAM Role below | ||
| handler = "lambda_function.handler" | ||
| runtime = "python3.12" | ||
|  | ||
| layers = [aws_lambda_layer_version.dependencies.arn] | ||
| } | ||
|  | ||
| # IAM Role for Lambda | ||
| resource "aws_iam_role" "lambda_role" { | ||
| name = "lambda_basic_execution" | ||
|  | ||
| assume_role_policy = <<EOF | ||
| { | ||
| "Version": "2012-10-17", | ||
| "Statement": [ | ||
| { | ||
| "Action": "sts:AssumeRole", | ||
| "Principal": { | ||
| "Service": "lambda.amazonaws.com" | ||
| }, | ||
| "Effect": "Allow" | ||
| } | ||
| ] | ||
| } | ||
| EOF | ||
| } | ||
|  | ||
| resource "aws_iam_role_policy" "lambda_logs_policy" { | ||
| name = "lambda_logs_policy" | ||
| role = aws_iam_role.lambda_role.id | ||
|  | ||
| policy = <<EOF | ||
| { | ||
| "Version": "2012-10-17", | ||
| "Statement": [ | ||
| { | ||
| "Action": [ | ||
| "logs:CreateLogGroup", | ||
| "logs:CreateLogStream", | ||
| "logs:PutLogEvents" | ||
| ], | ||
| "Resource": "arn:aws:logs:*:*:*", | ||
| "Effect": "Allow" | ||
| } | ||
| ] | ||
| } | ||
| EOF | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1 @@ | ||
| PyYAML==6.0.1 | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import yaml | ||
|  | ||
| def handler(event, context): | ||
| status_yaml = """ | ||
| status: success | ||
| """ | ||
| status = yaml.safe_load(status_yaml) | ||
| return status | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated Terraform version and hardcoding amd64 fails on ARM machines.
https://developer.hashicorp.com/terraform/install