wait-for-it.sh - 使用 Docker Compose depends_on 的必備 bash script
Posted on Nov 1, 2019 in Docker by Amo Chen ‐ 2 min read
撰寫 docker-compose.yaml
經常會遇到要使用 depends_on
的情況,確保某些特定的服務可以先啟動,例如 Web Application 經常要 depends_on
資料庫(database)服務。
但是 depends_on
指確保該 container 狀態會進到 running
,而非確保 container 內的服務會完整啟動結束。
However, for startup Compose does not wait until a container is “ready” (whatever that means for your particular application) - only until it’s running.
以 Web Application 與資料庫服務為例,在這種情況下,就會遇到資料庫服務的 container 已經進到 running
,但其實資料庫的程序(process)還沒完全啟動,進而導致 Web Application 服務連不到資料庫而失敗。
遇到這問題,建議可以使用 wait-for-it.sh 來解決!
wait-for-it.sh
wait-for-it.sh
是用 bash 所寫成的 script, 專門用以確定指定的 Host 與 Port 能夠連線,因此可以避免 depends_on
可能會遇到的問題。
當然,如果你所使用的 docker image 有內建的 sleep
指令可以使用的話,其實也可以簡單使用 sleep
等待個幾秒就好,但不見得所有的 docker image 內都有 sleep
,譬如 golang 的 image 就沒有 sleep 指令能夠使用,所以使用 wait-for-it.sh
會讓事情簡單許多。
wait-for-it.sh 可以在 vishnubob/wait-for-it 下載,並不需要額外安裝什麼軟體,唯一的要求只有 bash 。
最簡單的使用方法如下:
$ chmod +x ./wait-for-it.sh
$ ./wait-for-it.sh 127.0.0.1:9999 -t 5 -- echo "server is up"
上述的指令會負責確認本機(127.0.0.1)的 9999 通訊埠可以連線,如果超過 5 秒都無法連線就直接結束執行,如果能夠正常連線則直接列印 “server is up” 字串。
docker-compose.yaml 與 wait-for-it.sh 應用範例
接下來以實際範例解說如何將 wait-for-it.sh
應用至 docker-compose.yaml
中。
以下 docker-compose.yaml
中的 web 需要 db 先啟動完成:
version: "3"
services:
web:
container_name: "web"
build:
context: .
dockerfile: Dockerfile
depends_on:
- db
ports:
- "5000:5000"
db:
image: "postgres:10"
restart: always
container_name: "db"
ports:
- "5432:5432"
那麼就必須在 web 的 Dockerfile 中加上 wait-for-it.sh
,讓 web 等待 db 能夠連線後再執行真正的服務,例如以下的 golang Dockerfile 最後 CMD
的部分:
FROM golang:1.12.12-buster
WORKDIR /go/app
COPY . .
RUN go build -o webapp main.go
EXPOSE 5000
CMD ["./wait-for-it.sh", "db:5432", "--", "./webapp"]
最後,除了 bash 寫成的 wait-for-it.sh
之外,如果是習慣使用 sh
的人,則可以使用 wait-for 。
以上, Happy Coding!
References
https://docs.docker.com/compose/startup-order/