无服务器离线 - ECONNREFUSED Elasticmq 与 Docker-Compose

问题描述

我正在尝试使用无服务器框架在网络爬虫上工作,我希望用户可以轻松地在本地运行该框架,而无需在他们的本地计算机上安装任何必要的依赖项。我将 serverless-offline-sqs 与托管在 Docker 容器上的本地 Elasticmq 服务器一起使用。

目前,我运行了一个 docker-compose 文件,然后在另一个运行良好的终端中运行 serverless offline。该 docker-compose.yml 文件如下所示:

# 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

这运行良好,没有任何问题,在确保我的所有容器都已启动后,我可以运行 serverless offline 并且我的应用程序可以正常工作。我还尝试将在其自己的 docker 容器中运行 Serverless 的行为包括在内。我创建了以下 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

我正在尝试按照 Docker 文档来影响启动顺序,发现 here 以确保我的队列服务在运行之前已启动。这让我想到了这个 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

我正在使用 Docker 文档建议的 wait-for-it.sh 脚本,但它说我收到以下错误

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,2021-01-07T07:54:53.494Z,None,false,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    |  

我仍然遇到一些竞争条件吗?任何建议在这里将不胜感激!

解决方法

问题很可能出在ECONNREFUSED 0.0.0.0:9324。根据端口号判断是尝试访问 sqs 服务,但 IP 地址错误。它应该连接到 sqs:9324 或该容器的 IP 地址。 0.0.0.0 表示“任何 IP 地址”,通常用于绑定端口。检查您的 serverless 配置。

此外,您可以轻松检查您是否处于“竞争条件”。为此,只需使用多个终端一项一项地启动您的服务:

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

如果您可以一项一项地启动服务,那么您很可能就是。在这种情况下,您可以向服务添加 restart: on-failure 属性。这样,如果容器以 0 以外的代码退出 - docker 会重新启动容器。

,

事实证明,我的问题实际上出在我的 serverless.yml 配置中。在这里,我的 serverless.yml 具有 custom 配置,如下所示:

custom:
  serverless-offline-sqs:
    autoCreate: true                 # create queue if not exists
    apiVersion: '2012-11-05'
    endpoint: http://0.0.0.0:9324
    region: us-east-1
    accessKeyId: root
    secretAccessKey: root
    skipCacheInvalidation: false

正确的端点实际上是`http://sqs:9324'。其他一切都正确!