Skip to content

MariaDB 與 Docker Compose 的 depends_on

發佈日期:

我先講結論:Docker Compose 的 depends_on 只能控制容器的執行順序,開完一個容器就會開下一個,不會等到容器正常執行才開下一個容器。導致單純使用 depends_on 時,就好像蒙面走鋼索。假設 B 容器相依於 A 容器提供的服務,要是 B 容器在 A 容器還沒執行正常時就開始,B 容器就無法正確初始化。

前幾天,我要用 Docker Compose 裝 Bookstack,使用 LinuxServer.io 的 image。如果使用範例的 docker-compose.yml,搭配他們家的 MariaDB image 可以正常運作,但是換成官方的 MariaDB image 卻無法正常運作。

看 log 有 connection refused 還以為是網路問題。花了一些時間才發現原因在於 MariaDB container 因為 bug 造成初始化時間很長。Bookstack container 在進行 php artisan migrate 時,資料庫尚未初始化完成,所以產生錯誤。

發現同樣是 MariaDB image,有些初始化時間長到造成錯誤,有些卻不會。所以做了一個實驗看看各個 MariaDB image 初始化需要的時間(以第一則到最後一則 log 的時間計算):

雖然在這邊只要用初始化時間短的 image 就沒問題,不過在其他狀況下,如何確保容器正常執行後,再開與它相依的容器呢?

  1. 放在不同的 docker-compose.yml,分別啓動
  2. healthcheck 搭配 depends_on
    • 可以參考這篇文章這篇文章
    • version 2.1 加入的選項,version 3 之後移除
    • 大概長這樣,bookstack 相依於 bookstack_db,不過 healthcheck 的檢定條件試不出來,下面這個是不能用的,只是示範:
version: "2.1"

services:
  bookstack:
    image: linuxserver/bookstack
    container_name: bookstack
    environment:
      - PUID=1000
      - PGID=1000
      - DB_HOST=bookstack_db
      - DB_USER=bookstack
      - DB_PASS=yourdbpass
      - DB_DATABASE=bookstackapp
    restart: unless-stopped
    depends_on:
      bookstack_db:
        condition: service_healthy
  bookstack_db:
    image: mariadb
    container_name: bookstack_db
    environment:
      - MYSQL_ROOT_PASSWORD=yourdbpass
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=yourdbpass
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 30s
      timeout: 10s
      retries: 10
    restart: unless-stopped
  1. wait-for-it 之類的工具

覺得第一種方法比較省事,有需要再考慮第二種跟第三種。

好,講結論。使用 Docker Compose 時,如果有 docker container 要在另一個 docker container 完成初始化、正常執行後才啓動的話,不能只依賴 depends_on 選項,必須要用其他方式才能確保這些服務都正常運作。