Search code examples
aws-lambdaaws-samaws-sam-cli

How to run multiple lambda functions when deploying as a Docker image?


How does the dockerfile look like for aws lambda with docker image via aws-sam when declaring multiple functions/apps in templates.yaml?

Here is the sample dockerfile to run "a single app"

FROM public.ecr.aws/lambda/python:3.8

COPY app.py requirements.txt ./

RUN python3.8 -m pip install -r requirements.txt -t .

# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]


Solution

  • The Dockerfile itself looks the same. No changes needed there.

    The presence of the CMD line in the Docker file looks like it needs to change, but that is misleading. The CMD value can be specified on a per-function basis in the template.yaml file.

    The template.yaml file must be updated with information about the new function. You will need to add an ImageConfig property to each function. The ImageConfig property must specify the name of the function in the same way the CMD value otherwise would have done so.

    You will also need to update each function's DockerTag value to be unique, though this may be a bug.

    Here's the NodeJs "Hello World" example template.yaml's Resources section, updated to support multiple functions with a single Docker image:

    Resources:
      HelloWorldFunction:
        Type: AWS::Serverless::Function
        Properties:
          PackageType: Image
          ImageConfig:
            Command: [ "app.lambdaHandler" ]
          Events:
            HelloWorld:
              Type: Api
              Properties:
                Path: /hello
                Method: get
        Metadata:
          DockerTag: nodejs14.x-v1-1
          DockerContext: ./hello-world
          Dockerfile: Dockerfile
      HelloWorldFunction2:
        Type: AWS::Serverless::Function
        Properties:
          PackageType: Image
          ImageConfig:
            Command: [ "app.lambdaHandler2" ]
          Events:
            HelloWorld:
              Type: Api
              Properties:
                Path: /hello2
                Method: get
        Metadata:
          DockerTag: nodejs14.x-v1-2
          DockerContext: ./hello-world
          Dockerfile: Dockerfile
    

    This assumes the app.js file has been modified to provide both exports.lambdaHandler and exports.lambdaHandler2. I assume the corresponding python file should be modified similarly.

    After updating template.yaml in this way, sam local start-api works as expected, routing /hello to lambdaHandler and /hello2 to lambdaHandler2.

    This technically creates two separate Docker images (one for each distinct DockerTag value). However, the two images will be identical save for the tag, and based on the same Dockerfile, and the second image will therefore make use of Docker's cache of the first image.