我们在docker运维的过程中经常会遇到一个问题,我们启动一个
docker-compose.yml
文件时,虽然我们使用depends_on
属性用依赖关系定义了两个容器的启动顺序,但这个顺序仅仅是docker创建启动的顺序,而并不是在上一个容器完全启动成功的情况下启动下一个容器。
比如一个docker-compose.yml
脚本中有mysql
和依赖此mysql
的一个java
程序a
容器,虽然a
容器在mysql
启动之后启动,但还是存在a
容器启动的时候mysql
容器还在启动中,还无法提供可用的数据库连接,这就导致一个问题,a
容器此时启动异常或者失败,虽然部分有做异常情况快速失败停止程序触发docker重启机制,但也会导致a
容器多次重启。
甚至在部分服务器资源有限的情况下,多个容器同时启动,但因为数据库等容器还未启动导致其他服务多次重启互相抢占系统资源,导致数据库容器也无法正常启动,陷入死循环,甚至严重的导致docker
服务直接无响应。
为了实现上诉a
容器在mysql
容器完全启动可以提供数据库连接的情况下再启动,就需要在a
容器中加入一个逻辑来检查等待mysql
的3306端口已经打开,然后执行a
容器的启动程序语句。
在这里用到了github上的一个开源项目wait-for-it
,可以看到其中有一个shell文件wait-for-it.sh
,这个自行去github项目中下载,这里以下面的docker-compose.yml
为例:
version: '2.2'
services:
mysql:
restart: always
image: mysql:5.6
ports:
- "3306:3306"
env_file:
- env/mysql.env
app:
image: app:latest
restart: always
env_file:
- env/mysql.env
ports:
- 8054:8054
depends_on:
- mysql
volumes:
- ./wait-for-it.sh:/wait-for-it.sh
command: ["/wait-for-it.sh", "-t", "0", "mysql:3306", "--", "java", "-jar", "/app.jar"]
这里将wait-for-it.sh
挂载到app
容器内,然后设置执行语句command: ["/wait-for-it.sh", "-t", "0", "mysql:3306", "--", "java", "-jar", "/app.jar"]
,其中mysql:3306
代表检查mysql
容器的3306端口是否可用,-t 0
代表设置超时为0代表禁用超时功能,即wait-for-it
脚本一直等mysql服务可用之后再执行后续命令,java -jar app.jar
就是app
容器原本的java程序启动命令。