Skip to content
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

No response from invoke container for Lambda inside docker-compose #2837

Open
SorsOps opened this issue Apr 28, 2021 · 73 comments
Open

No response from invoke container for Lambda inside docker-compose #2837

SorsOps opened this issue Apr 28, 2021 · 73 comments

Comments

@SorsOps
Copy link

SorsOps commented Apr 28, 2021

Description:

Related to #2492

When running a docker-compose with an image that is using sam to run a local api, the api can never get a response from the lambda container. Everything works correctly when run locally not in a container.

I have read through all the answers in 2492 and tried the various permutations suggested, nothing has worked. There appeared to be no subsequent documentation follow up for getting this setup to work with docker.

Steps to reproduce:

DockerFile

FROM python:alpine
RUN apk add --no-cache --virtual build-deps build-base=0.5-r2 gcc=10.2.1_pre1-r3 bash=5.1.0-r0 && \
    pip install aws-sam-cli==1.23.0 && \
    apk del build-deps
COPY ./sam_entrypoint.sh /bin/sam_entrypoint.sh
RUN chmod +x /bin/sam_entrypoint.sh

WORKDIR /app
COPY ./node_modules /app/node_modules
COPY ./package.json /app/package.json
COPY ./template.yml /app/template.yml
COPY ./dist /app/dist
EXPOSE 3000 
ENTRYPOINT ["sh","/bin/sam_entrypoint.sh"]

sam_entrypoint.sh

#!/bin/bash
set -o errexit
/usr/local/bin/sam local start-api --debug \
  --template ./template.yml \
  --host 0.0.0.0 \
  --container-host host.docker.internal \
  --container-host-interface  127.0.0.1 \
  --docker-network host

Template.yml

AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"
Description: "Automated lambda setup for api gateway"
Resources:
  res0:
    Type: "AWS::Serverless::Function"
    Properties:
      CodeUri: "./"
      Handler: "dist/index.handler"
      Runtime: "nodejs12.x"
      Timeout: 10
      Events:
        CatchAll:
          Type: "Api"
          Properties:
            Path: "/"
            Method: ANY
  res1:
    Type: "AWS::Serverless::Function"
    Properties:
      CodeUri: "./"
      Handler: "dist/index.handler"
      Runtime: "nodejs12.x"
      Timeout: 10
      Events:
        CatchAll:
          Type: "Api"
          Properties:
            Path: "/{proxy+}"
            Method: ANY

Docker-compose

version: '3.6'
services:
  sam_app:
    build: 
      context: .
      dockerfile: Dockerfile.test
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock  
    extra_hosts:
      - "host.docker.internal:host-gateway"

Observed result:

sam_app_1  | 
sam_app_1  |    SAM CLI now collects telemetry to better understand customer needs.
sam_app_1  |
sam_app_1  |    You can OPT OUT and disable telemetry collection by setting the
sam_app_1  |    environment variable SAM_CLI_TELEMETRY=0 in your shell.
sam_app_1  |    Thanks for your help!
sam_app_1  |
sam_app_1  |    Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
sam_app_1  |
sam_app_1  | 2021-04-28 17:40:50,630 | Telemetry endpoint configured to be https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics
sam_app_1  | 2021-04-28 17:40:50,630 | Using config file: samconfig.toml, config environment: default
sam_app_1  | 2021-04-28 17:40:50,631 | Expand command line arguments to:
sam_app_1  | 2021-04-28 17:40:50,631 | --template_file=/app/template.yml --host=0.0.0.0 --port=3000 --static_dir=public --layer_cache_basedir=/root/.aws-sam/layers-pkg --container_host=localhost --container_host_interface=127.0.0.1      
sam_app_1  | 2021-04-28 17:40:50,704 | local start-api command is called
sam_app_1  | 2021-04-28 17:40:50,709 | No Parameters detected in the template
sam_app_1  | 2021-04-28 17:40:50,732 | 3 stacks found in the template
sam_app_1  | 2021-04-28 17:40:50,732 | No Parameters detected in the template
sam_app_1  | 2021-04-28 17:40:50,753 | 3 resources found in the stack
sam_app_1  | 2021-04-28 17:40:50,753 | No Parameters detected in the template
sam_app_1  | 2021-04-28 17:40:50,773 | Found Serverless function with name='res0' and CodeUri='./'
sam_app_1  | 2021-04-28 17:40:50,773 | --base-dir is not presented, adjusting uri ./ relative to /app/template.yml
sam_app_1  | 2021-04-28 17:40:50,773 | Found Serverless function with name='res1' and CodeUri='./'
sam_app_1  | 2021-04-28 17:40:50,773 | --base-dir is not presented, adjusting uri ./ relative to /app/template.yml
sam_app_1  | 2021-04-28 17:40:50,777 | No Parameters detected in the template
sam_app_1  | 2021-04-28 17:40:50,798 | No Parameters detected in the template
sam_app_1  | 2021-04-28 17:40:50,819 | Found '1' API Events in Serverless function with name 'res0'
sam_app_1  | 2021-04-28 17:40:50,819 | Found '1' API Events in Serverless function with name 'res1'
sam_app_1  | 2021-04-28 17:40:50,819 | Detected Inline Swagger definition
sam_app_1  | 2021-04-28 17:40:50,819 | Lambda function integration not found in Swagger document at path='/' method='x-amazon-apigateway-any-method'
sam_app_1  | 2021-04-28 17:40:50,819 | Lambda function integration not found in Swagger document at path='/{proxy+}' method='x-amazon-apigateway-any-method'
sam_app_1  | 2021-04-28 17:40:50,819 | Found '0' APIs in resource 'ServerlessRestApi'
sam_app_1  | 2021-04-28 17:40:50,819 | Removed duplicates from '0' Explicit APIs and '2' Implicit APIs to produce '2' APIs
sam_app_1  | 2021-04-28 17:40:50,819 | 2 APIs found in the template
sam_app_1  | 2021-04-28 17:40:50,825 | Mounting res0 at http://0.0.0.0:3000/ [DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT]
sam_app_1  | 2021-04-28 17:40:50,825 | Mounting res1 at http://0.0.0.0:3000/{proxy+} [DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT]
sam_app_1  | 2021-04-28 17:40:50,826 | You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You 
only need to restart SAM CLI if you update your AWS SAM template
sam_app_1  | 2021-04-28 17:40:50,826 | Localhost server is starting up. Multi-threading = True
sam_app_1  | 2021-04-28 17:40:50  * Running on http://0.0.0.0:3000/ (Press CTRL+C to quit)
sam_app_1  | 2021-04-28 17:41:20,791 | Constructed String representation of Event to invoke Lambda. Event: {"body": null, "headers": {"Accept": "*/*", "Host": "127.0.0.1:3000", "User-Agent": "insomnia/2021.2.2", "X-Forwarded-Port": "3000", "X-Forwarded-Proto": "http"}, "httpMethod": "GET", "isBase64Encoded": false, "multiValueHeaders": {"Accept": ["*/*"], "Host": ["127.0.0.1:3000"], "User-Agent": ["insomnia/2021.2.2"], "X-Forwarded-Port": ["3000"], "X-Forwarded-Proto": 
["http"]}, "multiValueQueryStringParameters": null, "path": "/v1/openapi.json", "pathParameters": {"proxy": "v1/openapi.json"}, "queryStringParameters": null, "requestContext": {"accountId": "123456789012", "apiId": "1234567890", "domainName": "127.0.0.1:3000", "extendedRequestId": null, "httpMethod": "GET", "identity": {"accountId": null, "apiKey": null, "caller": null, "cognitoAuthenticationProvider": null, "cognitoAuthenticationType": null, "cognitoIdentityPoolId": null, "sourceIp": "172.24.0.1", "user": null, "userAgent": "Custom User Agent String", "userArn": null}, "path": "/{proxy+}", "protocol": "HTTP/1.1", "requestId": "d9c5fa20-2328-43f7-b4d2-5a35028dfab1", "requestTime": "28/Apr/2021:17:40:50 +0000", "requestTimeEpoch": 1619631650, "resourceId": "123456", "resourcePath": "/{proxy+}", "stage": "Prod"}, "resource": "/{proxy+}", "stageVariables": null, "version": "1.0"}
sam_app_1  | 2021-04-28 17:41:20,791 | Found one Lambda function with name 'res1'
sam_app_1  | 2021-04-28 17:41:20,791 | Invoking dist/index.handler (nodejs12.x)
sam_app_1  | 2021-04-28 17:41:20,791 | Environment variables overrides data is standard format
sam_app_1  | 2021-04-28 17:41:20,791 | Loading AWS credentials from session with profile 'None'
sam_app_1  | 2021-04-28 17:41:20,803 | Resolving code path. Cwd=/app, CodeUri=/app
sam_app_1  | 2021-04-28 17:41:20,803 | Resolved absolute path to code is /app
sam_app_1  | 2021-04-28 17:41:20,803 | Code /app is not a zip/jar file
sam_app_1  | 2021-04-28 17:41:20,817 | Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-nodejs12.x:rapid-1.23.0.
sam_app_1  |
sam_app_1  | 2021-04-28 17:41:20,817 | Mounting /app as /var/task:ro,delegated inside runtime container
sam_app_1  | 2021-04-28 17:41:21,124 | Starting a timer for 10 seconds for function 'res1'
sam_app_1  | 2021-04-28 17:41:22,075 | Cleaning all decompressed code dirs
sam_app_1  | 2021-04-28 17:41:22,075 | No response from invoke container for res1
sam_app_1  | 2021-04-28 17:41:22,075 | Invalid lambda response received: Lambda response must be valid json
sam_app_1  | 2021-04-28 17:41:22 172.24.0.1 - - [28/Apr/2021 17:41:22] "GET /v1/openapi.json HTTP/1.1" 502 -

Expected result:

That the lambda can be executed correctly and a response received.

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

  1. OS: Windows 10
  2. sam --version: 1.23.0
  3. AWS region: us-east-1
@hoffa
Copy link
Contributor

hoffa commented Apr 30, 2021

Is your Docker daemon running locally? Could you try with --container-host-interface 0.0.0.0 (which will bind the container ports to all network interfaces) to ensure it's not an issue with port binding?

@hoffa hoffa added area/docker area/local/start-api sam local start-api command labels Apr 30, 2021
@SorsOps
Copy link
Author

SorsOps commented May 3, 2021

Hi @hoffa I've tested with --container-host-interface 0.0.0.0, at this point I can't even get a request to go through to the docker-compose container at that point. Trying

http://0.0.0.0:3000/v1/openapi.json ,
http://localhost:3000/v1/openapi.json
http:/127.0.0.1:3000/v1/openapi.json

from the host system is inaccessible

image

@xazhao
Copy link
Contributor

xazhao commented May 3, 2021

Hi @Andrewx82 could you try the command without --docker-network option? The default bridge network should work for your case.

@SorsOps
Copy link
Author

SorsOps commented May 4, 2021

Hi @xazhao The call is now accessible and I see it being processed in the logs , however I see no response from the containers

sam_app_1  | 2021-05-04 11:43:05,155 | Found one Lambda function with name 'res1'
sam_app_1  | 2021-05-04 11:43:05,155 | Invoking dist/index.handler (nodejs12.x)
sam_app_1  | 2021-05-04 11:43:05,155 | Environment variables overrides data is standard format
sam_app_1  | 2021-05-04 11:43:05,155 | Loading AWS credentials from session with profile 'None'
sam_app_1  | 2021-05-04 11:43:05,168 | Resolving code path. Cwd=/app, CodeUri=/app
sam_app_1  | 2021-05-04 11:43:05,168 | Resolved absolute path to code is /app
sam_app_1  | 2021-05-04 11:43:05,169 | Code /app is not a zip/jar file
sam_app_1  | 2021-05-04 11:43:05,173 | Image was not found.
sam_app_1  | Building image...........................................................................................................................................................................................................................................................................................................................................................
sam_app_1  | 2021-05-04 11:44:41,985 | Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-nodejs12.x:rapid-1.23.0.
sam_app_1  |
sam_app_1  | 2021-05-04 11:44:41,985 | Mounting /app as /var/task:ro,delegated inside runtime container
sam_app_1  | 2021-05-04 11:44:42,334 | Starting a timer for 10 seconds for function 'res1'
sam_app_1  | 2021-05-04 11:44:43,246 | Cleaning all decompressed code dirs
sam_app_1  | 2021-05-04 11:44:43,246 | No response from invoke container for res1
sam_app_1  | 2021-05-04 11:44:43,247 | Invalid lambda response received: Lambda response must be valid json
sam_app_1  | 2021-05-04 11:44:43 172.20.0.1 - - [04/May/2021 11:44:43] "GET /v1/openapi.json HTTP/1.1" 502 -

@xazhao
Copy link
Contributor

xazhao commented May 4, 2021

@Andrewx82 extra-host in your docker compose file is for Linux. Since your OS is Windows, I guess that is actually causing the issue. Can you try it without extra-host?
Btw in your case, it seems there is no need to use --container-host-interface option since the default value should work.

@SorsOps
Copy link
Author

SorsOps commented May 5, 2021

Hi @xazhao

I have changed the sam_entrypoint.sh to the following

set -o errexit
BASEDIR=$(pwd)
/usr/local/bin/sam local start-api --debug \
  --template ./template.yml \
  --host 0.0.0.0 \
  # --docker-volume-basedir "${BASEDIR}" \
  --container-host host.docker.internal \
  # --container-host-interface  0.0.0.0 \
  # --docker-network host

along with the docker-compose to

version: '3.6'
services:
  sam_app:
    build: 
      context: .
      dockerfile: Dockerfile.test
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock  

Still appears to be no response

sam_app_1  | 2021-05-05 07:47:59,514 | Found one Lambda function with name 'res1'
sam_app_1  | 2021-05-05 07:47:59,515 | Invoking dist/index.handler (nodejs12.x)
sam_app_1  | 2021-05-05 07:47:59,515 | Environment variables overrides data is standard format
sam_app_1  | 2021-05-05 07:47:59,515 | Loading AWS credentials from session with profile 'None'
sam_app_1  | 2021-05-05 07:47:59,531 | Resolving code path. Cwd=/app, CodeUri=/app
sam_app_1  | 2021-05-05 07:47:59,531 | Resolved absolute path to code is /app
sam_app_1  | 2021-05-05 07:47:59,531 | Code /app is not a zip/jar file
sam_app_1  | 2021-05-05 07:47:59,547 | Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-nodejs12.x:rapid-1.23.0.
sam_app_1  |
sam_app_1  | 2021-05-05 07:47:59,547 | Mounting /app as /var/task:ro,delegated inside runtime container
sam_app_1  | 2021-05-05 07:47:59,823 | Starting a timer for 10 seconds for function 'res1'
sam_app_1  | 2021-05-05 07:48:00,764 | Cleaning all decompressed code dirs
sam_app_1  | 2021-05-05 07:48:00,765 | No response from invoke container for res1
sam_app_1  | 2021-05-05 07:48:00,765 | Invalid lambda response received: Lambda response must be valid json
sam_app_1  | 2021-05-05 07:48:00 172.20.0.1 - - [05/May/2021 07:48:00] "GET /v1/openapi.json HTTP/1.1" 502 -

@SorsOps
Copy link
Author

SorsOps commented May 11, 2021

@xazhao @hoffa

Would it be possible to just get a simple example of the SAM CLI working in docker using a volume from the host? There is an implicit understanding in the docs that its possible, but I don't see a working example anywhere for reference

@xazhao
Copy link
Contributor

xazhao commented May 13, 2021

@Andrewx82 I was testing using configurations from this comment: #2436 (comment). After adding --container-host host.docker.internal it works. It looks pretty similar setup with your setup though.

@SorsOps
Copy link
Author

SorsOps commented May 14, 2021

@xazhao I can confirm that that does not work . See my bash entry script

#!/bin/bash
set -o errexit
BASEDIR=$(pwd)
/usr/local/bin/sam local start-api --debug \
  --template ./template.yml \
  -v $BASEDIR \
  --host 0.0.0.0 \
  --container-host host.docker.internal 

I also tried with and without the -v option

Can we just get an official example instead of saying that it is supposed to work ?

@xazhao
Copy link
Contributor

xazhao commented May 19, 2021

@Andrewx82 This is what I'm currently using.
Dockerfile

FROM amazon/aws-cli

RUN yum -y update && \
    yum install -y python3 && \
    python3 -m pip install aws-sam-cli

ENTRYPOINT [ "" ]

docker-compose.yml

services:
  testcase:
    build: .
    working_dir: $PWD
    command: sam local start-api --host 0.0.0.0 --container-host host.docker.internal
    ports:
      - 3000:3000
    volumes:
      - '$PWD:$PWD'
      - '/var/run/docker.sock:/var/run/docker.sock'`

Then open another terminal and use the following command:
curl localhost:3000/hello

Please note: My development environment is macOS and I think mounting volume is different in Windows (Seems you already did properly). For your No response ... error, it usually happens when lambda function is not hosted on a container correctly.
One thing you might try is see if you can resolve host.docker.internal to an IP address. For me, host.docker.internal resolves to 192.168.65.2. If I use this ip instead of host.docker.internal, it will work too.

@SorsOps
Copy link
Author

SorsOps commented May 19, 2021

@xazhao I've tried to align my files to be similar to yours
aws-sam.zip

It appears that something is happening here as I'm getting information about interacting with the lambda, however it doesn't seem like its reading the values correctly. For clarity I don't want to use volumes for this as I want to bake a docker image with the lambda

@sbhvt
Copy link

sbhvt commented May 20, 2021

I'm having a very similar issue. I think that the root cause is related to the code path it is attempting to mount.

In the output that @Andrewx82 posted earlier, you see this line: Mounting /app as /var/task:ro,delegated inside runtime container. '/app' is the WORKDIR and is the path within the container but it is not the path on the host, and the docker engine needs the path on host for mounting.

In order to properly evaluate paths for mounts, the docker engine needs the path on the host of the docker engine. In @xazhao 's examples, this is accomplished because of the working_dir: $PWD line in the docker-compose file. Using the sample code that @xaxhao shared, I am able to reproduce the same error that @Andrewx82 shared by commenting out the working_dir: $PWD line from docker-compose.

(Note that if using the exact code shared by @xazhao , the WORKDIR is "aws" instead of "app", but the issue is the same regardless.) Here's what you see logged when working_dir: $PWD is commented out:

sam_app_1  | 2021-05-20 20:26:52,932 | Resolving code path. Cwd=/aws, CodeUri=/aws/hello_world
sam_app_1  | 2021-05-20 20:26:52,932 | Resolved absolute path to code is /aws/hello_world
sam_app_1  | 2021-05-20 20:26:52,933 | Code /aws/hello_world is not a zip/jar file
...

In the use case of running from within VSCode devcontainers, which is one of the use cases mentioned in #2492, the option with working_dir: $PWD is not a feasible solution.

I also tried this (working_dir commented out but passing $PWD to the --docker-volume-basedir parameter) :

version: '3.6'
services:
  sam_app:
    #working_dir: $PWD
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    command: sam local start-api --host 0.0.0.0 --container-host host.docker.internal --debug --docker-volume-basedir $PWD
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - $PWD:$PWD

In that case, here is the the output:

sam_app_1  | 2021-05-20 20:30:33,580 | --base-dir is not presented, adjusting uri hello_world/ relative to /aws/template.yml
...
sam_app_1  | 2021-05-20 20:26:52,932 | Resolving code path. Cwd=<MY_LOCAL_PATH>, CodeUri=/aws/hello_world
sam_app_1  | 2021-05-20 20:26:52,932 | Resolved absolute path to code is /aws/hello_world
sam_app_1  | 2021-05-20 20:26:52,933 | Code /aws/hello_world is not a zip/jar file
...

I looked at the codebase related to that area of code: resolve_code_path in samcli/lib/utils/codeuri.py. The calling code already resolved the codeuri parameter to an absolute path before calling that method. Judging by the output, it looks like this happens in when it logs --base-dir is not presented. It looks like if the CodeUri were a relative path (the raw value in the template itself) instead of the absolute path when that method was called (i.e. Resolving code path. Cwd=<MY_LOCAL_PATH>, CodeUri=./hello_world), then it would properly resolve the absolute path to code and therefore work to use the --docker-volume-basedir $PWD option. This would allow for the functionality as it existed in prior versions of SAM CLI using that --docker-volume-basedir option and correspond to the documentation on the usage of that parameter which says:

If Docker is running on a remote machine, you must mount the path where the AWS SAM file exists on the Docker machine and modify this value to match the remote machine.

Requiring the configuration to use working_dir doesn't seem a viable resolution to #2492, especially in light of how it conflicts with the documentation around the --docker-volume-basedir parameter. It seems also related to: #963 and #1834.

The desired behavior being described in this issue, #2492, #963 and #1834 seem like they would be resolved if you used --base-dir with the value passed for --docker-volume-basedir or resolved the stack location from the outset using the --docker-volume-basedir parameter value.

@sbhvt
Copy link

sbhvt commented May 27, 2021

@xazhao any updates on the above?

@SorsOps
Copy link
Author

SorsOps commented May 31, 2021

👍

@SorsOps
Copy link
Author

SorsOps commented Jun 15, 2021

@xazhao @hoffa Could @sbhvt and I potentially get an ETA on this resolution?

@alexsanderp
Copy link

I solved this problem just using network_mode: host in my docker-compose.yml

@bfoura
Copy link

bfoura commented Jun 17, 2021

I solved this problem just using network_mode: host in my docker-compose.yml

@alexsanderp Can you please share your docker-compose file ?

@alexsanderp
Copy link

alexsanderp commented Jun 18, 2021

@bfoura

sam.Dockerfile

FROM python:alpine

RUN apk update && \
    apk upgrade && \
    apk add bash && \
    apk add --no-cache --virtual build-deps build-base gcc && \
    pip install aws-sam-cli && \
    apk del build-deps

WORKDIR /app

docker-compose.yml

version: '3'
services:
    sam-api:
        image: default/sam-api:dev
        container_name: sam-api
        build:
            context: .
            dockerfile: sam.Dockerfile
        entrypoint: ["/app/sam-api-entrypoint.sh"]
        command: ["$PWD"]
        volumes:
            - .:/app
            - /var/run/docker.sock:/var/run/docker.sock
        network_mode: host

networks:
    default:
        name: default

sam-api-entrypoint.sh

#!/bin/sh

BASEDIR="$1"
sam build
sam local start-api \
 --host 0.0.0.0 \
 --docker-volume-basedir "${BASEDIR}" \
 --docker-network default \
 --debug

So I can access the API from host with http://localhost:3000. But I can't access from other containers :(

@alexsanderp
Copy link

alexsanderp commented Jun 18, 2021

I was able to connect to the API from other containers using extra_hosts:

    extra_hosts:
      - host.docker.internal:host-gateway

Connect to API from inside the other container:
http://host.docker.internal:3000

That is, I can now connect from within other containers and from the host :)

If you want the lambda container to connect to other containers (example: dynamodb), configure them on the network specified in --docker-network and use the name of the containers when connecting.

@SorsOps
Copy link
Author

SorsOps commented Jun 18, 2021

@alexsanderp We don't want to use volumes like your example is doing, we want a baked image that can be distributed

@SorsOps
Copy link
Author

SorsOps commented Jul 5, 2021

@xazhao any movement around this, it has been more than a month

@CoshUS CoshUS added the type/bug label Jul 8, 2021
@NickDarvey
Copy link

I get one step further by using the official SAM CLI images. Perhaps it's worth a try @Andrewx82?

version: '3.9'
services:
  api:
    image: public.ecr.aws/sam/build-nodejs14.x:1.26.0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./dist:/var/task:ro
    ports:
      - 3000:3000
    command: sam local start-api --template stack.yaml --host 0.0.0.0 --docker-network application --container-host host.docker.internal --warm-containers EAGER

networks:
  default:
    name: application

Mind you, I'm now stuck because the spawned container's /var/task is empty even though it appears to correctly and successfully mount the volume from the CLI container. (#2955 may be related?) You might not run in to this depending on your environment. (I'm Docker version 20.10.5, build 55c4c88 on Windows 10 in WSL 2 mode.)

api_1  | 2021-07-14 06:56:35  * Running on http://0.0.0.0:3000/ (Press CTRL+C to quit)
api_1  | Invoking app.handler (nodejs14.x)
api_1  | Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-nodejs14.x:rapid-1.26.0.
api_1  |
api_1  | Mounting /var/task/ResolveSource as /var/task:ro,delegated inside runtime container
api_1  | 2021-07-14T06:56:39.760Z       undefined       ERROR   Uncaught Exception      {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'app'\nRequire stack:\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'app'","Require stack:","- /var/runtime/UserFunction.js","- /var/runtime/index.js","    at _loadUserApp (/var/runtime/UserFunction.js:100:13)","    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)","    at Object.<anonymous> (/var/runtime/index.js:43:30)","    at Module._compile (internal/modules/cjs/loader.js:1085:14)","    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)","    at Module.load (internal/modules/cjs/loader.js:950:32)","    at Function.Module._load (internal/modules/cjs/loader.js:790:14)","    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)","    at internal/main/run_main_module.js:17:47"]}

@grahamlyons
Copy link

grahamlyons commented Jul 15, 2021

I tried @NickDarvey's docker-compose.yaml - I'm testing with a vanilla sam init hello world api, so I mounted . instead of dist - and I still get:

api_1  | No response from invoke container for HelloWorldFunction
api_1  | Invalid lambda response received: Lambda response must be valid json
api_1  | 2021-07-15 09:49:46 172.18.0.1 - - [15/Jul/2021 09:49:46] "GET /hello HTTP/1.1" 502 -

Tested on Debian Linux.

I would really like to get a solution to this too. I have used sam in the past (a few years ago) in a Compose environment to execute a function and it worked. I'm not sure what's changed since then but I'd love to see this working.

@Harriebo
Copy link

Hi, I ran into the same problem of running sam in a docker container for a project I work on. I manged in the end to fix it by running sam as:
sam local start-api -p 3001 --debug
--host 0.0.0.0
--container-host 172.17.0.2
--container-host-interface 0.0.0.0

notice that container-host is 172.17.0.2 because I override that in my docker daemon config, by default that would be 172.17.0.1 (on linux, on mac this is a hostname with a random ip I belive)
I also had to add -v "/var/run/docker.sock:/var/run/docker.sock:rw" do my docker run to make sure docker in docker works.

@xazhao
Copy link
Contributor

xazhao commented Jul 30, 2021

@sbhvt @Andrewx82 Sorry for the delay.

@sbhvt Thanks for the detailed response and analysis. It did help me identify the bug a lot. When we introduced nested stack feature, we started resolving CodeUri before it is resolved using the value of --docker-volume-basedir. Therefore it won't be resolved with the directory you passed in even if you use that option. A fix in my mind is to remove the logic of first resolving. Also I'm just curious how do you reproduce the bug using the code example I provided? If I comment out work_dir line, it won't be able to find the template. (Not a docker expert myself)

@Andrewx82 Could you please try the method that @sbhvt proposed using --docker-volume-basedir and --base-dir? In short, when --base-dir is used, it won't be resolved twice so that bug won't happen. For some reasons when I was running your example, it showsRuntime.HandlerNotFound: dist/index.handler is undefined or not exported. My guess is because of Mac zip issue but I haven't looked into that.

We will fix it once we confirm that is the root cause.

@grahamlyons
Copy link

grahamlyons commented Aug 18, 2021

I've tested this using the latest Sam CLI and an API Gateway project created from sam init:

Dockerfile:

FROM node:14-buster-slim

ENV NODE_ENV test

RUN apt-get update && \
    apt-get install -y \
        unzip \
        curl && \
    (cd /tmp/ && \
    curl -OL https://github.com/aws/aws-sam-cli/releases/download/v1.28.0/aws-sam-cli-linux-x86_64.zip && \
    unzip aws-sam-cli-linux-x86_64.zip -d sam-installation && \
    ./sam-installation/install)

docker-compose.yaml:

version: '3.9'
services:
  sam_app:
    working_dir: $PWD
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    command: sam local start-api --host 0.0.0.0 --container-host 172.17.0.1 --debug --docker-volume-basedir $PWD
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - $PWD:$PWD

This is the output I see from docker-compose up:

Creating network "sam-app_default" with the default driver
Creating sam-app_sam_app_1 ... done
Attaching to sam-app_sam_app_1
sam_app_1  | 
sam_app_1  |    SAM CLI now collects telemetry to better understand customer needs.
sam_app_1  | 
sam_app_1  |    You can OPT OUT and disable telemetry collection by setting the
sam_app_1  |    environment variable SAM_CLI_TELEMETRY=0 in your shell.
sam_app_1  |    Thanks for your help!
sam_app_1  | 
sam_app_1  |    Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
sam_app_1  | 
sam_app_1  | 2021-08-18 10:22:04,409 | Telemetry endpoint configured to be https://aws-serverless-tools-telemetry.us-west-2.amazonaws.com/metrics
sam_app_1  | 2021-08-18 10:22:04,410 | Using config file: samconfig.toml, config environment: default
sam_app_1  | 2021-08-18 10:22:04,410 | Expand command line arguments to:
sam_app_1  | 2021-08-18 10:22:04,410 | --template_file=/home/graham/workspace/sam-app/template.yaml --host=0.0.0.0 --container_host=172.17.0.1 --docker_volume_basedir=/home/graham/workspace/sam-app --port=3000 --static_dir=public --layer_cache_basedir=/root/.aws-sam/layers-pkg --container_host_interface=127.0.0.1 
sam_app_1  | 2021-08-18 10:22:04,493 | local start-api command is called
sam_app_1  | 2021-08-18 10:22:04,502 | No Parameters detected in the template
sam_app_1  | 2021-08-18 10:22:04,534 | 2 stacks found in the template
sam_app_1  | 2021-08-18 10:22:04,534 | No Parameters detected in the template
sam_app_1  | 2021-08-18 10:22:04,564 | 2 resources found in the stack 
sam_app_1  | 2021-08-18 10:22:04,564 | No Parameters detected in the template
sam_app_1  | 2021-08-18 10:22:04,595 | Found Serverless function with name='HelloWorldFunction' and CodeUri='hello-world/'
sam_app_1  | 2021-08-18 10:22:04,595 | --base-dir is not presented, adjusting uri hello-world/ relative to /home/graham/workspace/sam-app/template.yaml
sam_app_1  | 2021-08-18 10:22:04,600 | No Parameters detected in the template
sam_app_1  | 2021-08-18 10:22:04,630 | No Parameters detected in the template
sam_app_1  | 2021-08-18 10:22:04,659 | Found '1' API Events in Serverless function with name 'HelloWorldFunction'
sam_app_1  | 2021-08-18 10:22:04,659 | Detected Inline Swagger definition
sam_app_1  | 2021-08-18 10:22:04,659 | Lambda function integration not found in Swagger document at path='/hello' method='get'
sam_app_1  | 2021-08-18 10:22:04,659 | Found '0' APIs in resource 'ServerlessRestApi'
sam_app_1  | 2021-08-18 10:22:04,660 | Removed duplicates from '0' Explicit APIs and '1' Implicit APIs to produce '1' APIs
sam_app_1  | 2021-08-18 10:22:04,660 | 1 APIs found in the template
sam_app_1  | 2021-08-18 10:22:04,667 | Mounting HelloWorldFunction at http://0.0.0.0:3000/hello [GET]
sam_app_1  | 2021-08-18 10:22:04,667 | You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
sam_app_1  | 2021-08-18 10:22:04,667 | Localhost server is starting up. Multi-threading = True
sam_app_1  | 2021-08-18 10:22:04  * Running on http://0.0.0.0:3000/ (Press CTRL+C to quit)

And when I hit localhost:3000/hello I see this output:

sam_app_1  | 2021-08-18 10:23:24,190 | Constructed String representation of Event to invoke Lambda. Event: {"body": null, "headers": {"Accept": "*/*", "Host": "localhost:3000", "User-Agent": "curl/7.64.0", "X-Forwarded-Port": "3000", "X-Forwarded-Proto": "http"}, "httpMethod": "GET", "isBase64Encoded": false, "multiValueHeaders": {"Accept": ["*/*"], "Host": ["localhost:3000"], "User-Agent": ["curl/7.64.0"], "X-Forwarded-Port": ["3000"], "X-Forwarded-Proto": ["http"]}, "multiValueQueryStringParameters": null, "path": "/hello", "pathParameters": null, "queryStringParameters": null, "requestContext": {"accountId": "123456789012", "apiId": "1234567890", "domainName": "localhost:3000", "extendedRequestId": null, "httpMethod": "GET", "identity": {"accountId": null, "apiKey": null, "caller": null, "cognitoAuthenticationProvider": null, "cognitoAuthenticationType": null, "cognitoIdentityPoolId": null, "sourceIp": "192.168.112.1", "user": null, "userAgent": "Custom User Agent String", "userArn": null}, "path": "/hello", "protocol": "HTTP/1.1", "requestId": "313b059f-6e74-4d2d-9033-d47f935ca834", "requestTime": "18/Aug/2021:10:22:04 +0000", "requestTimeEpoch": 1629282124, "resourceId": "123456", "resourcePath": "/hello", "stage": "Prod"}, "resource": "/hello", "stageVariables": null, "version": "1.0"}
sam_app_1  | 2021-08-18 10:23:24,191 | Found one Lambda function with name 'HelloWorldFunction'
sam_app_1  | 2021-08-18 10:23:24,191 | Invoking app.lambdaHandler (nodejs14.x)
sam_app_1  | 2021-08-18 10:23:24,191 | No environment variables found for function 'HelloWorldFunction'
sam_app_1  | 2021-08-18 10:23:24,191 | Environment variables overrides data is standard format
sam_app_1  | 2021-08-18 10:23:24,191 | Loading AWS credentials from session with profile 'None'
sam_app_1  | 2021-08-18 10:23:26,219 | Resolving code path. Cwd=/home/graham/workspace/sam-app, CodeUri=/home/graham/workspace/sam-app/hello-world
sam_app_1  | 2021-08-18 10:23:26,219 | Resolved absolute path to code is /home/graham/workspace/sam-app/hello-world
sam_app_1  | 2021-08-18 10:23:26,220 | Code /home/graham/workspace/sam-app/hello-world is not a zip/jar file
sam_app_1  | 2021-08-18 10:23:26,275 | Skip pulling image and use local one: public.ecr.aws/sam/emulation-nodejs14.x:rapid-1.28.0.
sam_app_1  | 
sam_app_1  | 2021-08-18 10:23:26,275 | Mounting /home/graham/workspace/sam-app/hello-world as /var/task:ro,delegated inside runtime container
sam_app_1  | 2021-08-18 10:23:27,132 | Starting a timer for 1 seconds for function 'HelloWorldFunction'
sam_app_1  | 2021-08-18 10:23:28,866 | Cleaning all decompressed code dirs
sam_app_1  | 2021-08-18 10:23:28,866 | No response from invoke container for HelloWorldFunction
sam_app_1  | 2021-08-18 10:23:28,866 | Invalid lambda response received: Lambda response must be valid json
sam_app_1  | 2021-08-18 10:23:28 192.168.112.1 - - [18/Aug/2021 10:23:28] "GET /hello HTTP/1.1" 502 -

From @sbhvt's version I had to add in the working_dir line otherwise I got the error Error: Template file not found at /var/opt/template.yml.

When I add the --base-dir option I get the error: Error: no such option: --base-dir.

@xazhao, is this enough information for you to investigate further? If not then please let me know - I'm really keen to get this resolved as it's blocking my adoption of Sam over Serverless.

@Saeger
Copy link

Saeger commented Feb 8, 2022

Came here because of the same issue when I try to invoke locally my lambda function with sam cli.

❯ sam local invoke
Invoking src/handlers/document-handler.triggerNewDocumentHandler (nodejs14.x)
Skip pulling image and use local one: public.ecr.aws/sam/emulation-nodejs14.x:rapid-1.37.0-x86_64.

Mounting /.../smart-lambdas/services/fii-documents-trigger/.aws-sam/build/documentHandlerFunction as /var/task:ro,delegated inside runtime container
No response from invoke container for documentHandlerFunction

@austinben
Copy link

Also interested about this.

I have success running the commands locally, but when I run them in CircleCI, I am faced with the dreaded No response from invoke container. Is there special flags to provide to the sam commands for running in the circleCI environment to allow communication between the container and the rest of the environment? I assume that is the issue.

I am using the following two orbs:

  aws-cli: circleci/[email protected]
  sam: circleci/[email protected]

@grahamlyons
Copy link

@austinben, what OS are you running on locally? In the example I posted above I got it working on macOS but then had to add something else to make it work on Linux. I don't remember exactly what but take a look and see if you've anything missing.

@austinben
Copy link

@grahamlyons

Running it on macOS locally, but have confirmed it also runs locally on linux. I am not using docker compose. Simply invoking the sam cli commands sam build and sam local invoke.

@vbalagovic
Copy link

vbalagovic commented Feb 27, 2022

Hello my friends in aws suffering :) Just my two cents on this issue. Yes most of these configs work, but for some like me they simply don't. I was trying everything for a few days and then my boss just started the first configuration on (clean) mac and it worked.

Before I tried to put aws sam cli in docker I installed everything locally (then it was 1.38 version) to test everything (mac os, dockers for lambdas, and experimenting with file sharing to make it work). After the docker-compose configuration worked for my boss and my very troubled mind I deleted everything locally, reseted docker and then it simply started to work in docker… So maybe an option to think about. Also meanwhile aws-sam-cli was upgraded to 1.40, i refuse to believe that this was cause of my suffering tho x)

So this simple config should work, try it maybe on some other machine, linux or something, and take into consideration that problem isn't up to config. I hope this will help somebody..

version: '3.6'

networks:
  sam_app_network:
    name: 'sam_app_network'
    external: true

services:
  sam_app_1:
    container_name: sam_app_1
    working_dir: $PWD/some-service-with-template
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      AWS_DEFAULT_REGION: ca-central-1
      AWS_REGION: ${AWS_REGION}
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - $PWD:$PWD
    # command: "sam local start-lambda --host 0.0.0.0 --container-host host.docker.internal --debug"
    command: "sam local start-api --host 0.0.0.0 --container-host host.docker.internal --debug --docker-network sam_app_network"
    ports:
      - "3000:3000"
    networks:
      - sam_app_network

  dynamodb:
    image:  amazon/dynamodb-local
    container_name: dynamodb
    hostname: dynamodb
    restart: always
    volumes:
      -  $PWD/dynamo-data:/home/dynamodblocal/data
    ports:
      - 8000:8000
    command: "-jar DynamoDBLocal.jar -sharedDb -dbPath /home/dynamodblocal/data/"
    networks:
      - sam_app_network

the docker file in docker-compose

FROM python:3.8-alpine
RUN apk update && \
    apk upgrade && \
    apk add bash && \
    apk add --no-cache --virtual build-deps build-base gcc && \
    pip install awscli && \
    pip install aws-sam-cli && \
    apk del build-deps

@jfuss
Copy link
Contributor

jfuss commented Mar 3, 2022

@grahamlyons Sorry for my slow response. Was on leave for a while at the end of last year/beginning of this year and then this just fell off my radar.

There was some back and forth whether Discussions was useful. For now, a lightweight way (I can think of) is just move discussion about "docker in docker" into a [Discussion] titled issue. That will at least allow that to focus. We do have a slack channel, which could be another option.

@grahamlyons
Copy link

@jfuss, no worries - thanks for coming back on this.

I would welcome any discussion on running Sam with Docker (although I'd avoid the phrase "docker in docker" as that implies running the docker daemon inside a container which is whole other thing) as it's something I've been doing for a while so would be good to air my use cases.

@leoGalani
Copy link

btw,
Once you define the docker network, you don't need to use the host.docker.internal anymore.
You can use the service name on the URL you want to connect :)

@hawflau
Copy link
Contributor

hawflau commented Sep 19, 2022

Closing as the fix has been released in SAM v1.57.0

@hawflau hawflau closed this as completed Sep 19, 2022
@awilkins
Copy link

awilkins commented Sep 20, 2022

Hey, @hawflau ; I'm not convinced this issue is the one fixed by the PR merged above.

That PR seems to resolve Issue 3520 (not going to hotlink it to avoid associating it with this ticket).

This ticket is to do with accessing APIs over a Docker user network. I'm not sure why that PR mentions this issue by ID.

@hawflau
Copy link
Contributor

hawflau commented Sep 30, 2022

Hi @awilkins, I'll check with the PR contributor. If that's the case, we will reopen the issue. Thanks for flagging it!

@lucashuy
Copy link
Contributor

lucashuy commented Oct 6, 2022

Hi, thanks for bringing up your observations! I can confirm that the linked PR fixed one of the original issues (not being able to target the correct directory on the host machine). It looks like there is another issue related to the usage of the --docker-network flag in sam local. After testing with the OP's original files and removing the --docker-network host flag, I'm able to invoke the API using curl on the host machine.

We'll investigate further and look into next steps to resolve this.

@tariromukute
Copy link

Hi, the thread was helpful, I managed to get the app working, however, I started facing issues when I was trying to use layers. My docker-compose file is as below.

version: '3'
services:
  lambdas:
    build:
      context: ./
      dockerfile: Dockerfile
    image: myapp-lambda:local
    ports:
      - 3000:3000
    environment:
      - SAM_CLI_CONTAINER_CONNECTION_TIMEOUT=12
      # This will override the AWSEndpoint paramter defined in the template
      - AWS_ENDPOINT=http://host.docker.internal:4566 # localstack container host for dynamodb
      - AWS_DEFAULT_REGION='us-west-2'
      - AWS_REGION='us-west-2'
      - AWS_ACCESS_KEY_ID='fake-access-key-id'
      - AWS_SECRET_ACCESS_KEY='fake-secret-key'
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./:/var/task
    entrypoint: sam local start-api --host 0.0.0.0 --port 3000 --docker-volume-basedir $PWD --container-host host.docker.internal

  localstack:
    image: localstack/localstack:latest
    ports:
      - '8000:8000' # using port 8000 to be consistent with dynamodb local jar
      - '4566:4566' # new dynamodb port
      - '8080:8080' # the localstack admin portal
    container_name: dynamodb_localstack
    environment: 
      - AWS_DEFAULT_REGION=us-east-1
      - EDGE_PORT=4566
      - SERVICES=dynamodb,s3
      # App uses different profiles, this allows a single database file will be shared for all clients
      - DYNAMODB_SHARE_DB=1

The error I am getting is that the path to the utilities-layer is not being found. The path is on the host machine and it exists. I am running a Mac OS M1 using a docker desktop. See the error I am facing below.

FileNotFoundError: [Errno 2] No such file or directory: '/Users/tariromukute/Documents/dev/app/utilities-layer'

I tried to add the flag --layer-cache-basedir=/root/.aws-sam/layers-pkg with no luck. Anyone with an idea to get the sam app working with docker-compose when using layers? See a section of the template.yaml below.

Resources:  
....

  utilitiesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: utilities-layer
      Description: Utility layer
      ContentUri: utilities-layer/
      CompatibleRuntimes:
        - nodejs12.x
      LicenseInfo: "MIT"
      RetentionPolicy: Retain

Globals:
  Function:
    Runtime: nodejs14.x
    Architectures:
      - arm64
    MemorySize: 128
    Timeout: 100
    Layers:
      - !Ref utilitiesLayer

@tariromukute
Copy link

tariromukute commented Feb 15, 2023

I was able to get sam working inside docker. It turns out when running the application using docker-compose the utilities base path has to be the working directory inside docker. My working directory was /var/task/. I appended that to the ContentUri: utilities-layer/ to ContentUri: /var/task/utilities-layer/ and I got the application working.

I tried to find a way to make this dynamic. My attempt was to have the base path for the utilities as a parameter like ContentUri: !Join ["", [!Ref UtilitiesBasePath, 'utilities-layer/']]. However it turns out --parameter-overrides 'ParameterKey=UtilitiesBasePath, ParameterValue=/var/task/' doesn't work when running locally. But it works with sam deploy, see the discussion #1490.

My work around was to have the default of the parameter set to /var/task/ since I expect to test my application locally using docker compose then during sam deploy I have to make sure to replace the base path with ./. I haven't tested the last bit yet though. Note: I had no issue when running sam local start-api on my local machine outside docker-compose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests