最近在写一个即时聊天程序的DEMO,技术栈差不多是vue+nodejs+redis+rabbitmq,里面有用到rabbitmq来处理消息列队,
程序写好后,我用docker-compose做了个镜像,日后好给别人做DEMO。
docker-compose.yml大致如下
version: "3" services: redis: image: redis:latest ports: - "6379:6379" container_name: im-redis-compose restart: always command: redis-server --appendonly yes rabbitmq: image: rabbitmq:management ports: - "5672:5672" - "15672:15672" container_name: im-rabbitmq-compose environment: RABBITMQ_DEFAULT_USER: guest RABBITMQ_DEFAULT_PASS: guest RABBITMQ_DEFAULT_VHOST: my_vhost backend: build: . links: - redis - rabbitmq container_name: im-server-compose restart: on-failure depends_on: - rabbitmq - redis ports: - "3000:3000"
由于nodejs服务的启动会和redis和rabbitmq建立connection,有依赖关系。于是我使用docker-compose中的depends_on
属性来决定启动顺序,再用links
属性来做docker容器内访问的网络别名,一切看起来都很顺利。但是当我敲下docker-compose up
命令的时候却报错了。
看了一下启动log,nodejs先报的错,启动的时候报了connect refused,连接rabbitmq的时候出错。
im-server-compose | Error: connect ECONNREFUSED 172.24.0.3:5672 im-server-compose | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1136:16) { im-server-compose | errno: -111, im-server-compose | code: 'ECONNREFUSED', im-server-compose | syscall: 'connect', im-server-compose | address: '172.24.0.3', im-server-compose | port: 5672 im-server-compose | } im-server-compose | npm ERR! code ELIFECYCLE im-server-compose | npm ERR! errno 1
接下来打印出了rabbitmq启动成功的消息
im-rabbitmq-compose | 2020-01-06 08:44:17.837 [info] <0.504.0> Management plugin: HTTP (non-TLS) listener started on port 15672 im-rabbitmq-compose | 2020-01-06 08:44:17.839 [info] <0.610.0> Statistics database started. im-rabbitmq-compose | 2020-01-06 08:44:17.839 [info] <0.609.0> Starting worker pool 'management_worker_pool' with 3 processes in it im-rabbitmq-compose | 2020-01-06 08:44:18.132 [info] <0.8.0> Server startup complete; 3 plugins started. im-rabbitmq-compose | * rabbitmq_management im-rabbitmq-compose | * rabbitmq_management_agent im-rabbitmq-compose | * rabbitmq_web_dispatch im-rabbitmq-compose | completed with 3 plugins.
咦!有点confused!明明设置了depends_on定了启动顺序,为何rabbitmq还没有启动完全,就去跑nodejs的服务了?
google找了半天,还是没有找到比较好的解决方案,浪费了很多时间。最后还是去看了docker-compose文档关于depends_on的章节,才顺藤摸瓜找到解决方案
depends_on
does not wait for db and redis to be “ready” before starting web - only until they have been started. If you need to wait for a service to be ready, seeControlling startup order
for more on this problem and strategies for solving it.depends_on
在启动web这个容器前,并不会等待db和redis这个两个容器进入ready状态,而只是等到它们被启动状态了。 如果你需要等待直到某个依赖的服务进入ready状态,需要看进一阅读控制启动顺序
一文
链接我贴在这里,具体内容可以自己去看https://docs.docker.com/compose/startup-order/
我大致说下他提到的解决思路
就在容器启动命令执行前,跑一个shell脚本,这个脚本会去访问依赖的服务的页面或者ping api来判断底层的服务有没有ready,随后再去启动真正的服务。里面有个现成的解决方案sh脚本叫wait-for, 只需要下载这份shell并且在dockerfile里加上
RUN apt-get -q update && apt-get -qy install netcat
docker-compose.yml里调用wait-for的command即可
version: "3" services: redis: image: redis:latest ports: - "6379:6379" container_name: im-redis-compose restart: always command: redis-server --appendonly yes rabbitmq: image: rabbitmq:management ports: - "5672:5672" - "15672:15672" container_name: im-rabbitmq-compose environment: RABBITMQ_DEFAULT_USER: guest RABBITMQ_DEFAULT_PASS: guest RABBITMQ_DEFAULT_VHOST: my_vhost backend: build: . links: - redis - rabbitmq container_name: im-server-compose restart: on-failure depends_on: - rabbitmq - redis ports: - "3000:3000" command: sh -c './wait-for.sh rabbitmq:15672 -- npm run start'
command: sh -c './wait-for.sh rabbitmq:15672 -- npm run start'这句意思,就是等rabbitmq:15672这个management管理页面可以访问了之后,在去执行真正的nodejs启动命令"npm run start"
好久没有来sf写专栏了,希望对大家有帮助!