AWS Lambda: "ELF load command address/offset not properly aligned" when deployed via Serverless Framework

Viewed 2652

I have a Lambda function in python3.6 that uses the following packages:

opencv-python
imutils
numpy
joblib
mahotas
scikit-image
scikit-learn==0.22.1
sklearn
pymongo==3.10.1

I am using the Serverless Framework to minimize the deployment sizes and to deploy to lambda. I've used the serverless-python-requirements plugin to manage packages. This is what my template.yml file looks like:

functions:
  hello:
    handler: handler.hello

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: non-linux
    zip: true
    slim: true
    noDeploy:
      - boto3
      - botocore
      - docutils
      - jmespath
      - pip
      - python-dateutil
      - s3transfer
      - setuptools
      - six
      - tensorboard
package:
  exclude:
    - node_modules/**
    - model/**
    - .vscode/**

I need to use slim & zip option because otherwise the deployment package will be too large (~350mb).

For some reason, if I don't include pymongo in requirements.txt, the function runs fine. The output of sls deploy when pymongo is not included is:

Serverless: Adding Python requirements helper...
Serverless: Generated requirements from /home/amman/Desktop/serverless-hello-world/requirements.txt in /home/amman/Desktop/serverless-hello-world/.serverless/requirements.txt...
Serverless: Using static cache of requirements found at /home/amman/.cache/serverless-python-requirements/3967fa669ece2345132bfe2a31be4287e2d61deedfb8b6006997a2192cea5753_slspyc ...
Serverless: Zipping required Python packages...
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Removing Python requirements helper...
Serverless: Injecting required Python packages to package...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service hello-world.zip file to S3 (128.52 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...

So the total .zip size is ~128 MB, and the function runs fine. But, if I include pymongo,the output of sls deploy is:

Serverless: Adding Python requirements helper...
Serverless: Generated requirements from /home/amman/Desktop/serverless-hello-world/requirements.txt in /home/amman/Desktop/serverless-hello-world/.serverless/requirements.txt...
Serverless: Installing requirements from /home/amman/.cache/serverless-python-requirements/279b0240a975ac6ad3c96e3b0ed81eec7981a8e66e0216037484878bfcaf4479_slspyc/requirements.txt ...
Serverless: Using download cache directory /home/amman/.cache/serverless-python-requirements/downloadCacheslspyc
Serverless: Running ...
Serverless: Zipping required Python packages...
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Removing Python requirements helper...
Serverless: Injecting required Python packages to package...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service hello-world.zip file to S3 (109.37 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...

Now the size is decreased to ~109 MB. Shouldn't the size increase because I've added a new dependency? When I run the lambda function, I get an error:

Unable to import module 'handler': /tmp/sls-py-req/cv2/cv2.cpython-36m-x86_64-linux-gnu.so: ELF load command address/offset not properly aligned

I think this might be a serverless framework issue. What could I do to fix this? I have tried installing different versions of pymongo but no luck.

I am using the following Serverless Framework version:

> serverless --version
Framework Core: 1.73.1
Plugin: 3.6.13
SDK: 2.3.1
Components: 2.31.2

Edit: Are there any alternative to pymongo? I've seen some but they use pymongo as the underlying dependency.

2 Answers

I couldn't fix this with serverless. So I decided to sls deploy without pymongo and once serverless generated the .requirements.zip file, I copied that file elsewhere and once again ran sls deploy but this time with only pymongo (and pymongo[srv]) in requirements.txt. That generated .requirements.zip containing pymongo and its dependencies. I merged files from this .requirments.zip and the one requirements.zip generated from the first sls deploy. This way I got all other dependencies (opencv2, numpy, joblib etc) and pymongo in one .requirements.zip file.

After that I zipped the source code plus the merged .requirements.zip file and manually uploaded the zip to s3. It came down to 128MB zipped. Pointed my lambda function to use this deployment package from S3 and it worked. I got pymongo along with opencv2 and other dependencies.

But, a drawback is that you have to upload to S3 and update the function yourself. Until this is problem is fixed, I am going to have to use this "hack".

Use layers. Pack functions individually.

  lambda:
handler: lambda/handler.lambda_handler
runtime: python3.8
layers:
  - {Ref: PythonRequirementsLambdaLayer}
package:
  individually: true

...

  pythonRequirements:
dockerizePip: non-linux
dockerImage: lambci/lambda:build-python3.8
layer: true
slim: true
slimPatterns:
  # the commented ones are included in slim: true
  # - '**/*.py[c|o]'
  # - '**/__pycache__*'
  # - '**/*.dist-info*'
  - '**/*.egg-info*'
  - '**/test/*'
  - '**/tests/*'
invalidateCaches: true
Related