docker-compose RabbitMQ与Nodejs接收端同时运行时的错误
首先讲一下背景:
我现在在开发的一个项目,需要运行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接收端同时运行时的错误相关推荐
- RabbitMQ:Docker Compose部署RabbitMQ
创建目录,用于存放Docker Compose部署RabbitMQ的yaml文件: mkdir -p /root/composefile/rabbitmq 写入该yaml文件: vim /root/c ...
- docker-compose下载慢_编写Docker Compose时要注意的五大常见错误
在构建容器化的应用时,开发人员往往需要某种方法来引导启动目标容器,以对其进行代码级别的测试.尽管业界有许多方法可以实现该目的,但Docker Compose是目前最受欢迎的一种方法.它能够让如下两个方 ...
- RHEL 8 - 用podman compose替代docker compose运行Ansible Tower
<OpenShift 4.x HOL教程汇总> 已在 RHEL 8.4 上验证 本文的前置条件:RHEL8 - 配置基于安装 ISO 文件的 YUM Repo 文章目录 安装podman ...
- Docker Compose安装以及入门
Docker 安装 脚本安装 自定义脚本 wget https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages ...
- 自动化代码审查平台: 基于Docker Compose整合Jenkins + SonarQube
目录 代码审查平台 本文目标 环境要求 系统环境 组件服务版本 前言 代码评审 SonarQube简介 概述 部署流程 检查系统参数 设置系统参数 拉取代码 进入文件目录 创建数据卷目录 部署文件信息 ...
- 一步步学会用docker部署应用(nodejs版)
docker是一种虚拟化技术,可以在内核层隔离资源.因此对于上层应用而言,采用docker技术可以达到类似于虚拟机的沙盒环境.这大大简化了应用部署,让运维人员无需陷入无止境繁琐的依赖环境及系统配置中: ...
- 【Spring Cloud 基础设施搭建系列】Spring Cloud Demo项目 使用Docker Compose编排Spring Cloud微服务
文章目录 Docker Compose快速人门 入门示例 使用Docker Comose编排Spring Cloud微服务 使用Maven插件读取Dockerfile进行构建 使用Maven插件构建D ...
- SpringCloud系列知识快速复习 -- part 1(SpringCloud基础知识,Docker,RabbitMQ)
SpringCloud知识快速复习 SpringCloud基础知识 微服务特点 SpringCloud常用组件 服务拆分和提供者与消费者概念 Eureka注册中心 原理 Ribbon负载均衡 原理 负 ...
- Docker compose 容器编排
1. 概述 问题:如果要使用 Docker 运行 LNMP 架构,那么 Nginx.MySQL.PHP. Linux三个服务运行在一个容器里,还是运行在多个容器里呢? 答案是都可以. 你可以分别放在三 ...
最新文章
- linux学习第三天 (Linux就该这么学)
- 1046 Shortest Distance (20 分)【难度: 简单 / 知识点: 前缀和 / 破环成链】
- 日常生活中的法语积累2
- [转]Spinner的常用技巧
- html小游戏代码_研发实践:Mozilla分享如何开发一款WebVR小游戏
- 腾达ap设置说明_优科 Ruckus R610 AC1900规格 无线AP 开箱拆解评测
- Node.js连接数据库
- 教你用illustrator画十二色环
- Python Numpy random.poisson() 泊松分布
- 允许应用更改计算机,解决电脑总弹出“是否允许程序对计算机进行更改”
- 我的测试工程师之路--测试人员不看后悔
- DotEPUB:一键将网页转换成 EPUB 格式电纸书
- EDIUS中的图片该如何进行剪裁
- 互联网日报 | 6月10日 星期四 | 腾讯云推出“云签约”解决方案;华为商城上线“鸿蒙智联”页面;“生鲜电商第一股”争夺战打响...
- word打开文件出错怎么办?
- Archlinux 安装、美化、软件入门(四)
- 综合架构-高可用服务
- JAVA乐居租房网的设计与实现计算机毕业设计Mybatis+系统+数据库+调试部署
- oracle数据库中spool的作用,Oracle中Spool命令如何使用 Oracle中Spool命令使用方法
- vue基础 - 11 (组件间的通信:event bus -- 事件车,$emit,$on,$off,封装一个事件车)