I'm trying to build a multi-layer Python SAM (AWS Serverless Application Model) app.
Nothing too fancy, but it has some dependencies, which are managed using pipenv
.
SAM has a sam build
command which behind the scenes uses make.
I have a Makefile
that looks like this:
# Empty build target for "sam build". Why?
# 1. "sam build Layers" works
# 2. "sam build" for the main function doesn't (it tries to use pip and crashes)
# With this empty target the main build is skipped and only the layers are built, which is enough.
build-Function: ;
build-Layers:
bash pip-install.sh "$(ARTIFACTS_DIR)"
pip-install.sh
looks like this:
#!/bin/bash
ARTIFACTS_DIR="${1}"
set -eu
# Detect Cygwin: https://stackoverflow.com/a/20691293/1320143
uname="$(uname -s)"
if [[ "${uname}" =~ "Cygwin" ]]
then
# AWS SAM for Windows passes a Windows path Cygwin tools (make, etc.) don't understand.
ARTIFACTS_DIR="$(cygpath -u "${ARTIFACTS_DIR}")"
fi
PROJECT_PATH="$(echo "${ARTIFACTS_DIR}" | sed 's@/.aws-sam.*@@')"
PIPFILE_PATH="$(echo "${ARTIFACTS_DIR}" | sed 's@/.aws-sam.*@/../Pipfile.lock@' | xargs readlink -f)"
mkdir -p "${ARTIFACTS_DIR}/python"
# We're using pipenv, which does not use requirements.txt.
# requirements.txt is used by SAM to automatically package and deploy layers (dependencies).
# To avoid dependency/version duplication, we extract the info from the pipenv info.
jq -r '.default | to_entries[] | .key + .value.version' "${PIPFILE_PATH}" > requirements.txt
# For debugging purposes.
ls -lha
python -m pip install -r "${PROJECT_PATH}/requirements.txt" -t "${ARTIFACTS_DIR}/python"
The important part is that this project uses pipenv
to manage dependencies, not pip
, and SAM uses make
as the build tool but after that, it only has a pip
extension. This script basically creates a dependency list that pip
understands and then pip
downloads all the dependencies in a folder, which will then be packaged as a big layer.
The main issue is debugging.
I've seen that for some (IMHO dumb) reason make
hides the output of shell scripts it launches. Supposedly make
can be tricked to show it, with this: See output of shell script in Makefile
I've tried it and it doesn't work. I run sam build Layers
and I only see the sam
output. I've tried --debug
, same thing.
Is there a way to show that output? I want to be able to debug the script in the make
/sam build
context as I don't understand some errors I'm getting 😔
At re:Invent 2020, AWS announced that Lambda can now use Docker images.
Instead of using the mix of Make and proprietary setup SAM provides for building Lambda layers, just use standard Dockerfiles and save a lot of time 🙂