docker-compose中解決depends_on無效問題

背景

最近在寫一個即時聊天程序的DEMO,技術棧差很少是vue+nodejs+redis+rabbitmq,裏面有用到rabbitmq來處理消息列隊,
程序寫好後,我用docker-compose作了個鏡像,往後好給別人作DEMO。
docker-compose.yml大體以下vue

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 命令的時候卻報錯了。node

分析

看了一下啓動log,nodejs先報的錯,啓動的時候報了connect refused,鏈接rabbitmq的時候出錯。git

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啓動成功的消息github

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的服務了?web

解決方案

google找了半天,仍是沒有找到比較好的解決方案,浪費了不少時間。最後仍是去看了docker-compose文檔關於depends_on的章節,才順藤摸瓜找到解決方案
image.pngredis

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, see Controlling 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里加上docker

RUN apt-get -q update && apt-get -qy install netcat

docker-compose.yml裏調用wait-for的command便可shell

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寫專欄了,但願對你們有幫助!npm

相關文章
相關標籤/搜索