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

Serverless Offline - ECONNREFUSED Elasticmq with Docker-Compose

我正在尝试使用无服务器框架在 webscraper 上工作,我希望用户可以在本地轻松 运行,而无需在本地计算机上安装任何必要的依赖项。我正在使用 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 并且我的应用程序可以正常工作。我还试图将 运行ning Serverless 的行为包含在它自己的 docker 容器中。我创建了以下 Docker 文件:

# 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,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    |  

我还会遇到一些竞争条件吗?如有任何建议,我们将不胜感激!

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

此外,您可以轻松检查自己是否在 'race condition' 中。为此,只需使用多个终端一项一项地启动您的服务:

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.ymlcustom 配置如下:

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”。其他一切都是正确的!