Reputation: 4843
I have a very simple Python3.6 Lambda function, the only complexity being that I want to include pyyaml
within it. index.py
looks like this -
import yaml
def handler(event, context):
return event
Everything works fine if I bundle pyyaml
within my Lambda deployable, like this -
(aws_layer_demo) justin@justin-XPS-13-9360:~/work/aws_demos/aws_layer_demo$ jar -tvf tmp/layer-demo-dev/2019-05-31-06-27-41.zip
59 Fri May 31 06:27:13 BST 2019 index.py
0 Fri May 31 06:19:32 BST 2019 __init__.py
4881 Fri May 31 06:15:37 BST 2019 yaml/composer.py
25554 Fri May 31 06:15:37 BST 2019 yaml/constructor.py
3294 Fri May 31 06:15:37 BST 2019 yaml/cyaml.py
{... etc ...}
I can ping the Lambda function and get a response, no problem.
Now I want to test including pyyaml
within a layer. So I now have two deployables, one for the app -
(aws_layer_demo) justin@justin-XPS-13-9360:~/work/aws_demos/aws_layer_demo$ jar -tvf tmp/layer-demo-dev/2019-05-31-06-43-42.zip
59 Fri May 31 06:27:13 BST 2019 index.py
0 Fri May 31 06:19:32 BST 2019 __init__.py
and one for the layer -
(aws_layer_demo) justin@justin-XPS-13-9360:~/work/aws_demos/aws_layer_demo$ jar -tvf tmp/layer-demo-layer-dev/2019-05-31-06-43-42.zip
0 Fri May 31 06:43:42 BST 2019 __init__.py
4881 Fri May 31 06:15:37 BST 2019 yaml/composer.py
25554 Fri May 31 06:15:37 BST 2019 yaml/constructor.py
3294 Fri May 31 06:15:37 BST 2019 yaml/cyaml.py
{... etc ...}
I have deployed both using a Cloudformation stack (via S3) and it looks like both the function and layer have been deployed correctly -
(aws_layer_demo) justin@justin-XPS-13-9360:~/work/aws_demos/aws_layer_demo$ ./scripts/show_function_config.sh dev
------------------------------------------------------------------------------------------------
| GetFunctionConfiguration |
+--------------+-------------------------------------------------------------------------------+
| CodeSha256 | MImn7X/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX= |
| CodeSize | 372 |
| Description | |
| FunctionArn | arn:aws:lambda:eu-west-1:XXXXXXXXXXXX:function:layer-demo-dev |
| FunctionName| layer-demo-dev |
| Handler | index.handler |
| LastModified| 2019-05-31T05:44:14.089+0000 |
| MemorySize | 512 |
| RevisionId | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
| Role | arn:aws:iam::XXXXXXXXXXXX:role/layer-demo-dev-AppFunctionRole-XXXXXXXXXXXX |
| Runtime | python3.6 |
| Timeout | 5 |
| Version | $LATEST |
+--------------+-------------------------------------------------------------------------------+
|| Layers ||
|+-------------+------------------------------------------------------------------------------+|
|| Arn | arn:aws:lambda:eu-west-1:XXXXXXXXXXXX:layer:layer-demo-dev:2 ||
|| CodeSize | 41184 ||
|+-------------+------------------------------------------------------------------------------+|
|| TracingConfig ||
|+-------------------------------+------------------------------------------------------------+|
|| Mode | PassThrough ||
|+-------------------------------+------------------------------------------------------------+|
|| VpcConfig ||
|+---------------------------------------------------------------+----------------------------+|
|| VpcId | ||
|+---------------------------------------------------------------+----------------------------+|
In particular note "Layers" in the above, and the fact that the CodeSize > 0 (ie I haven't accidentally deployed a size zero zipfile)
But when I ping my newly layerized Lambda function, I now get -
Unable to import module 'index'
And if I delve a bit deeper into the Cloudwatch logs I get -
Unable to import module 'index': No module named 'yaml'
So. It feels like I have probably somehow mis-structured my layer package (in terms of directory structue) so that Lambda doesn't see yaml
on internal AWS PYTHONPATH
. Or something. Can anyone advise me where I might be going wrong ?
Many thanks.
Upvotes: 5
Views: 7221
Reputation: 4843
Turns out this was due to a couple of factors.
First is that you have to be very careful about how you structure the layer package structure. It's not enough just to zip the dependencies - in the case of Python Lambda functions they have to be installed in a python
directory within the zip file. That directory changes depending on the runtime you are using. Not particularly clear from the Lambda docs, but more details here -
https://medium.com/@adhorn/getting-started-with-aws-lambda-layers-for-python-6e10b1f9a5d
Second is that when deploying the layer you need to specify the compatible runtime(s) - so if you're using the AWS CLI it's something like -
aws lambda publish-layer-version --layer-name $appname --content S3Bucket=$s3bucketname,S3Key=$appname/layer.zip --compatible-runtimes python3.7
Follow these two steps and your layer should work fine.
Upvotes: 3