Search code examples
dockerdocker-composeserverless-frameworkaws-serverless

Serverless Offline - ECONNREFUSED Elasticmq with Docker-Compose


I am trying to work on a webscraper using the Serverless Framework that I want to be easily ran locally by users without having to install any necessary depedencies on their local machine. I am using serverless-offline-sqs with a local Elasticmq server hosted on a Docker container.

Currently, I have a docker-compose file that I run, then run serverless offline in another terminal which works well. That docker-compose.yml file looks like this:

# docker-compose.yml

version: '3'
services:
  database:
    image: 'mongo'
    container_name: 'database'
    environment:
      - MONGO_INITDB_DATABASE=scraper_database
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=admin
    volumes:
    - ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
    - ./mongo-volume:/data/db
    ports:
      - '27017-27019:27017-27019'
    command: mongod --quiet --logpath /dev/null
  sqs:
    image: softwaremill/elasticmq:latest
    container_name: 'sqs'
    ports:
      - '9324:9324'
  sqs-create:
    image: infrastructureascode/aws-cli:latest
    container_name: 'sqs-create'
    links:
      - sqs
    entrypoint: sh
    command: ./create-queues.sh
    volumes:
      - ./scripts/create-queues.sh:/project/create-queues.sh:ro
    environment:
      - AWS_ACCESS_KEY_ID=local
      - AWS_SECRET_ACCESS_KEY=local
      - AWS_DEFAULT_REGION=eu-east-1
      - AWS_ENDPOINT_URL=http://sqs:9324

This works well with no issues, and after ensuring that all of my containers are up, I can run serverless offline and my app works. I am trying to also include the act of running Serverless in its own docker container. I have created the following Dockerfile:

# Dockerfile

FROM node:12

RUN npm --loglevel=error install -g serverless && npm --loglevel=error install -g serverless-offline

WORKDIR /usr/src/app

COPY package*.json ./

COPY ./scripts/wait-for-it.sh ./

RUN ["chmod", "+x", "/usr/src/app/wait-for-it.sh"]

RUN npm install

COPY . .

EXPOSE 3000

I am trying to follow the Docker documentation for affecting the start-up order, found here to ensure that my queue service is up before running this. This has led me to this docker-compose.yml:

version: '3'
services:
  serverless:
    container_name: 'serverless'
    build:
      context: .
      dockerfile: Dockerfile
    env_file:
      - .env.development
    ports:
      - '3000:3000'
    depends_on:
      - sqs
    command: ["./wait-for-it.sh", "sqs:9324", "--", "serverless", "offline"]
  database:
    image: 'mongo'
    container_name: 'database'
    environment:
      - MONGO_INITDB_DATABASE=scraper_database
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=admin
    volumes:
    - ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
    - ./mongo-volume:/data/db
    ports:
      - '27017-27019:27017-27019'
    command: mongod --quiet --logpath /dev/null
  sqs:
    image: softwaremill/elasticmq:latest
    container_name: 'sqs'
    ports:
      - '9324:9324'
  sqs-create:
    image: infrastructureascode/aws-cli:latest
    container_name: 'sqs-create'
    links:
      - sqs
    entrypoint: sh
    command: ./create-queues.sh
    volumes:
      - ./scripts/create-queues.sh:/project/create-queues.sh:ro
    environment:
      - AWS_ACCESS_KEY_ID=local
      - AWS_SECRET_ACCESS_KEY=local
      - AWS_DEFAULT_REGION=eu-east-1
      - AWS_ENDPOINT_URL=http://sqs:9324

I am using the wait-for-it.sh script which the Docker documentation suggests, but it says that I am getting the following error:

Successfully built 38df0769a202
Successfully tagged assessorscraper_serverless:latest
Starting sqs      ... done
Starting database     ... done
Recreating serverless ... done
Starting sqs-create   ... done
Attaching to sqs, database, sqs-create, serverless
serverless    | wait-for-it.sh: waiting 15 seconds for sqs:9324
sqs           | 07:54:45.046 [main] INFO  org.elasticmq.server.Main$ - Starting ElasticMQ server (1.0.0) ...
sqs           | 07:54:48.133 [elasticmq-akka.actor.default-dispatcher-6] INFO  akka.event.slf4j.Slf4jLogger - Slf4jLogger started
sqs           | 07:54:51.385 [elasticmq-akka.actor.default-dispatcher-7] INFO  o.e.rest.sqs.TheSQSRestServerBuilder - Started SQS rest server, bind address 0.0.0.0:9324, visible server address http://localhost:9324
sqs           | 07:54:51.643 [elasticmq-akka.actor.default-dispatcher-7] INFO  o.e.r.s.TheStatisticsRestServerBuilder - Started statistics rest server, bind address 0.0.0.0:9325
sqs           | 07:54:51.649 [main] INFO  org.elasticmq.server.Main$ - === ElasticMQ server (1.0.0) started in 8819 ms ===
serverless    | wait-for-it.sh: sqs:9324 is available after 9 seconds
sqs-create    | Creating queue TownQueue
sqs           | 07:54:53.808 [elasticmq-akka.actor.default-dispatcher-6] INFO  o.elasticmq.actor.QueueManagerActor - Creating queue QueueData(TownQueue,MillisVisibilityTimeout(30000),PT0S,PT0S,2021-01-07T07:54:53.494Z,2021-01-07T07:54:53.494Z,None,false,false,None,None,Map())
sqs-create exited with code 0
serverless    | Serverless: Running "serverless" installed locally (in service node_modules)
serverless    | Serverless: DOTENV: Loading environment variables from .env.development:
serverless    | Serverless:      - DATABASE_URL
serverless    | Serverless:      - ACCOUNT_ID
serverless    | Serverless:      - QUEUE_URL
serverless    | Serverless: Deprecation warning: Starting with next major version, default value of provider.lambdaHashingVersion will be equal to "20201221"
serverless    |             More Info: https://www.serverless.com/framework/docs/deprecations/#LAMBDA_HASHING_VERSION_V2
serverless    | Serverless: Deprecation warning: Starting with next major version, API Gateway naming will be changed from "{stage}-{service}" to "{service}-{stage}".
serverless    |             Set "provider.apiGateway.shouldStartNameWithService" to "true" to adapt to the new behavior now.
serverless    |             More Info: https://www.serverless.com/framework/docs/deprecations/#AWS_API_GATEWAY_NAME_STARTING_WITH_SERVICE
serverless    | offline: Error: connect ECONNREFUSED 0.0.0.0:9324
serverless    |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16)
serverless    |  
serverless    |   Networking Error ---------------------------------------
serverless    |  
serverless    |   Error: connect ECONNREFUSED 0.0.0.0:9324
serverless    |       at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16)
serverless    |  
serverless    |      For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
serverless    |  
serverless    |   Get Support --------------------------------------------
serverless    |      Docs:          docs.serverless.com
serverless    |      Bugs:          github.com/serverless/serverless/issues
serverless    |      Issues:        forum.serverless.com
serverless    |  
serverless    |   Your Environment Information ---------------------------
serverless    |      Operating System:          linux
serverless    |      Node Version:              12.20.1
serverless    |      Framework Version:         2.17.0 (local)
serverless    |      Plugin Version:            4.4.1
serverless    |      SDK Version:               2.3.2
serverless    |      Components Version:        3.4.4
serverless    |  

Am I still getting some race condition? Any suggestions here would be much appreciated!


Solution

  • The problem is likely to be in ECONNREFUSED 0.0.0.0:9324. Judging by the port number it is an attempt to reach the sqs service, but the IP-address is bad. It should connect to sqs:9324 or an IP-address of that container. 0.0.0.0 means 'any IP-address' and it is usually used to bind a port. Check your serverless configuration.

    Also, you can easily check if you are in a 'race condition' or not. For that simply start your services one by one using several terminals:

    docker-compose up database
    docker-compose up sqs
    docker-compose up sqs-create
    docker-compose up serverless
    

    If you can start services one by one then it is likely you are. In this case you can add restart: on-failure property to a service. This way if a container exits with a code other than 0 - docker restarts the container.