首先讲一下背景:

我现在在开发的一个项目,需要运行RabbitMQ和Nodejs接收端(amqplib库),但是在Nodejs接收端运行时,无法连接至RabbitMQ端,经常提示说 connect ECONNREFUSED ,无法连接至RabbitMQ服务器,我在docker-compose.yml文件中明明在Nodejs接收端将RabbitMQ服务器设置为depends_on,即RabbitMQ运行之后Nodejs接收端才会启动,那么为什么还是无法连接呢?

我查找了相关的资料,终于找到了原因

RabbitMQ容器启动后,离服务可用还有一小段时间

Nodejs接收端容器,则是启动后,就开始尝试连接至RabbitMQ服务器,那么中间就会有一个时间差,当Nodejs接收端去连接RabbitMQ服务器,服务无法响应,则会造成无法连接的错误

那么应该如何解决这个问题呢?

找到一个解决方案:wait-for-it,这个库中会增加对IP和端口的监测,只有当某个IP和端口可访问后,才会进行下一步动作,正好解决了以上的关于服务启动的时间差问题

关于写法,可以参考《https://stackoverflow.com/questions/48015477/docker-and-rabbitmq-econnrefused-between-containers》

需要在Nodejs接收端中增加wait-for-it.sh文件,还需要在Dockfile中将sh文件加入至镜像中,并且启动的命令是,当RabbitMQ服务已经启动后,再尝试启动Nodejs服务,这样就可以正常的启动了

请注意:其中等待的最长时间是我们在脚本中定义好的,我这国定义的是120秒,即两分钟,如果容器在两分钟还是无法启动成功,估计是会造成失败的

wait-for-it.sh文件内容,请最好参考官方的github地址(https://github.com/vishnubob/wait-for-it/edit/master/wait-for-it.sh),我这边的是现在能用,但不能保证未来一定可用

#!/usr/bin/env bash
#   Use this script to test if a given TCP host/port are availableWAITFORIT_cmdname=${0##*/}echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }usage()
{cat << USAGE >&2
Usage:$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]-h HOST | --host=HOST       Host or IP under test-p PORT | --port=PORT       TCP port under testAlternatively, you specify the host and port as host:port-s | --strict               Only execute subcommand if the test succeeds-q | --quiet                Don't output any status messages-t TIMEOUT | --timeout=TIMEOUTTimeout in seconds, zero for no timeout-- COMMAND ARGS             Execute command with args after the test finishes
USAGEexit 1
}wait_for()
{if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; thenechoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"elseechoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"fiWAITFORIT_start_ts=$(date +%s)while :doif [[ $WAITFORIT_ISBUSY -eq 1 ]]; thennc -z $WAITFORIT_HOST $WAITFORIT_PORTWAITFORIT_result=$?else(echo > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1WAITFORIT_result=$?fiif [[ $WAITFORIT_result -eq 0 ]]; thenWAITFORIT_end_ts=$(date +%s)echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"breakfisleep 1donereturn $WAITFORIT_result
}wait_for_wrapper()
{# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692if [[ $WAITFORIT_QUIET -eq 1 ]]; thentimeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &elsetimeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &fiWAITFORIT_PID=$!trap "kill -INT -$WAITFORIT_PID" INTwait $WAITFORIT_PIDWAITFORIT_RESULT=$?if [[ $WAITFORIT_RESULT -ne 0 ]]; thenechoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"fireturn $WAITFORIT_RESULT
}# process arguments
while [[ $# -gt 0 ]]
docase "$1" in*:* )WAITFORIT_hostport=(${1//:/ })WAITFORIT_HOST=${WAITFORIT_hostport[0]}WAITFORIT_PORT=${WAITFORIT_hostport[1]}shift 1;;--child)WAITFORIT_CHILD=1shift 1;;-q | --quiet)WAITFORIT_QUIET=1shift 1;;-s | --strict)WAITFORIT_STRICT=1shift 1;;-h)WAITFORIT_HOST="$2"if [[ $WAITFORIT_HOST == "" ]]; then break; fishift 2;;--host=*)WAITFORIT_HOST="${1#*=}"shift 1;;-p)WAITFORIT_PORT="$2"if [[ $WAITFORIT_PORT == "" ]]; then break; fishift 2;;--port=*)WAITFORIT_PORT="${1#*=}"shift 1;;-t)WAITFORIT_TIMEOUT="$2"if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fishift 2;;--timeout=*)WAITFORIT_TIMEOUT="${1#*=}"shift 1;;--)shiftWAITFORIT_CLI=("$@")break;;--help)usage;;*)echoerr "Unknown argument: $1"usage;;esac
doneif [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; thenechoerr "Error: you need to provide a host and port to test."usage
fiWAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}# check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; thenWAITFORIT_ISBUSY=1WAITFORIT_BUSYTIMEFLAG="-t"elseWAITFORIT_ISBUSY=0WAITFORIT_BUSYTIMEFLAG=""
fiif [[ $WAITFORIT_CHILD -gt 0 ]]; thenwait_forWAITFORIT_RESULT=$?exit $WAITFORIT_RESULT
elseif [[ $WAITFORIT_TIMEOUT -gt 0 ]]; thenwait_for_wrapperWAITFORIT_RESULT=$?elsewait_forWAITFORIT_RESULT=$?fi
fiif [[ $WAITFORIT_CLI != "" ]]; thenif [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; thenechoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"exit $WAITFORIT_RESULTfiexec "${WAITFORIT_CLI[@]}"
elseexit $WAITFORIT_RESULT
fi

view-for-it.sh

原本以为这个方案是十拿九稳的,在运行的过程中又出现了问题,即在Nodejs接收端,又出现了No such file or directory/usr/bin/env: bash的错误,这是个什么问题???

查找了网上的一些相关问题后,锁定了问题的原因,是因为Windows和Linux文件的编码问题,其中找到一个ELK的docker-compose也是相同的问题《https://github.com/deviantony/docker-elk/issues/36》

其中提到了两点,

1、使用Nodepad++替换指定的换行符

2、在docker-compose up -d启动前,使用docker-compose build命令编译一次

那好,第一步:将wait-for-it.sh文件使用Nodepad++处理一下

第二步:在docker-compose up -d前面执行docker-compose build一次

最后,在启动容器后,可以看到,在Nodejs接收端,wait-for-it作用后,过了九秒才启动Nodejs接收端


2019-03-29 更新:当第二次使用容器时,出现另一个错误

ERROR: for mes-run_mesrabbitmqmonitoringclient_1  Cannot start service mesrabbitmqmonitoringclient: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"./wait-for-it.sh\": permission denied": unknownERROR: for mesrabbitmqmonitoringclient  Cannot start service mesrabbitmqmonitoringclient: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"./wait-for-it.sh\": permission denied": unknown
ERROR: Encountered errors while bringing up the project.

个人猜测原因是,代码是在Windows电脑上进行代码开发的,默认情况下在Docker Windows中build image时,会为文件默认增加运行(X)权限,然后将镜像tag image后,直接push image到docker hub上,在服务器中,使用Docker-compose直接从docker hub 上pull image后运行container

但现在为何不行?因为现在修改为使用Azure DevOps平台build image,默认是没有设置运行(X)权限的,pull image后,在运行wait-for-it.sh时,会无法检测到权限

接下来应该要解决的是,如何在运行前增加sudo 用户,并且chrom +x  ./wait-for-it.sh

2019-03-29 最终解决问题了

现在也依然是使用Azure DevOps build image,增加一行代码chmod +x ./wait-for-it.sh即可

# FROM BASIC IMAGE
FROM node:7# CREATE AND SET WORK-DIRECTORY
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app# INSTALL APP DEPENDENCIES
COPY package.json /usr/src/app/
RUN npm install -g cross-env babel-cli
RUN npm install# DB ENVIRONMENT SETTING
# ENV NODE_ENV="local"# BUILD SOURCE CODE
COPY . /usr/src/app
COPY wait-for-it.sh /usr/src/app#这一行非常重要
RUN chmod +x ./wait-for-it.shRUN npm run build# No Need PORT(Just Command)
# EXPOSE 3000# DEFAULT COMMAND
# CMD [ "npm", "start" ]
CMD ["./wait-for-it.sh", "rabbitmq:5672", "-t", "120", "--", "npm", "start"]

如果问题没有得到解决,可以参考:https://github.com/nodejs/docker-node/issues/6

方案参考地址:

《Docker and Rabbitmq: ECONNREFUSED between containers》

《docker-compose start kibana failed!--No such file or directory/usr/bin/env: bash》

转载于:https://www.cnblogs.com/weschen/p/10253664.html

docker-compose RabbitMQ与Nodejs接收端同时运行时的错误相关推荐

  1. RabbitMQ:Docker Compose部署RabbitMQ

    创建目录,用于存放Docker Compose部署RabbitMQ的yaml文件: mkdir -p /root/composefile/rabbitmq 写入该yaml文件: vim /root/c ...

  2. docker-compose下载慢_编写Docker Compose时要注意的五大常见错误

    在构建容器化的应用时,开发人员往往需要某种方法来引导启动目标容器,以对其进行代码级别的测试.尽管业界有许多方法可以实现该目的,但Docker Compose是目前最受欢迎的一种方法.它能够让如下两个方 ...

  3. RHEL 8 - 用podman compose替代docker compose运行Ansible Tower

    <OpenShift 4.x HOL教程汇总> 已在 RHEL 8.4 上验证 本文的前置条件:RHEL8 - 配置基于安装 ISO 文件的 YUM Repo 文章目录 安装podman ...

  4. Docker Compose安装以及入门

    Docker 安装 脚本安装 自定义脚本 wget https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages ...

  5. 自动化代码审查平台: 基于Docker Compose整合Jenkins + SonarQube

    目录 代码审查平台 本文目标 环境要求 系统环境 组件服务版本 前言 代码评审 SonarQube简介 概述 部署流程 检查系统参数 设置系统参数 拉取代码 进入文件目录 创建数据卷目录 部署文件信息 ...

  6. 一步步学会用docker部署应用(nodejs版)

    docker是一种虚拟化技术,可以在内核层隔离资源.因此对于上层应用而言,采用docker技术可以达到类似于虚拟机的沙盒环境.这大大简化了应用部署,让运维人员无需陷入无止境繁琐的依赖环境及系统配置中: ...

  7. 【Spring Cloud 基础设施搭建系列】Spring Cloud Demo项目 使用Docker Compose编排Spring Cloud微服务

    文章目录 Docker Compose快速人门 入门示例 使用Docker Comose编排Spring Cloud微服务 使用Maven插件读取Dockerfile进行构建 使用Maven插件构建D ...

  8. SpringCloud系列知识快速复习 -- part 1(SpringCloud基础知识,Docker,RabbitMQ)

    SpringCloud知识快速复习 SpringCloud基础知识 微服务特点 SpringCloud常用组件 服务拆分和提供者与消费者概念 Eureka注册中心 原理 Ribbon负载均衡 原理 负 ...

  9. Docker compose 容器编排

    1. 概述 问题:如果要使用 Docker 运行 LNMP 架构,那么 Nginx.MySQL.PHP. Linux三个服务运行在一个容器里,还是运行在多个容器里呢? 答案是都可以. 你可以分别放在三 ...

最新文章

  1. linux学习第三天 (Linux就该这么学)
  2. 1046 Shortest Distance (20 分)【难度: 简单 / 知识点: 前缀和 / 破环成链】
  3. 日常生活中的法语积累2
  4. [转]Spinner的常用技巧
  5. html小游戏代码_研发实践:Mozilla分享如何开发一款WebVR小游戏
  6. 腾达ap设置说明_优科 Ruckus R610 AC1900规格 无线AP 开箱拆解评测
  7. Node.js连接数据库
  8. 教你用illustrator画十二色环
  9. Python Numpy random.poisson() 泊松分布
  10. 允许应用更改计算机,解决电脑总弹出“是否允许程序对计算机进行更改”
  11. 我的测试工程师之路--测试人员不看后悔
  12. DotEPUB:一键将网页转换成 EPUB 格式电纸书
  13. EDIUS中的图片该如何进行剪裁
  14. 互联网日报 | 6月10日 星期四 | 腾讯云推出“云签约”解决方案;华为商城上线“鸿蒙智联”页面;“生鲜电商第一股”争夺战打响...
  15. word打开文件出错怎么办?
  16. Archlinux 安装、美化、软件入门(四)
  17. 综合架构-高可用服务
  18. JAVA乐居租房网的设计与实现计算机毕业设计Mybatis+系统+数据库+调试部署
  19. oracle数据库中spool的作用,Oracle中Spool命令如何使用 Oracle中Spool命令使用方法
  20. vue基础 - 11 (组件间的通信:event bus -- 事件车,$emit,$on,$off,封装一个事件车)

热门文章

  1. extjs实现组织架构图_如何画好一张架构图?(内含知识图谱)
  2. 机器人车间气管_大开眼界!机器人焊装车间火力全开
  3. 对CSS选择器的理解
  4. 叶氏量能大抄底(通达信副图)
  5. 自考那些事儿(四):软件开发工具(理论篇)
  6. 中关村十大AI研究院 | 盘点
  7. Chrome十周年,作了一次死
  8. c#之线程总结(一)
  9. CentOs7.3 搭建 Solr单机服务
  10. Android学习笔记(十五)——实战:强制下线