Docker Compose
提供了一个depends_on
参数。
https://docs.docker.com/compose/compose-file/#depends_on
depends_on
参数用于描述服务之间的依赖关系,服务依赖将导致如下行为:
docker-compose up
按照依赖关系的顺序启动服务。docker-compose up SERVICE
自动包含SERVICE
的依赖关系。看起来功能强大,不过接下来又说了使用depends_on
的注意事项:
depends_on
在启动服务时并不会等待相关所依赖的服务完成。也就是说,depends_on
的主要功能是自动包含SERVICE
的依赖关系,
而所谓的按照依赖关系的顺序启动服务在实践中几乎毫无意义,
因为很多被依赖的服务往往启动缓慢,例如数据库。
分析Docker
的工作原理会发现,
管理依赖关系的挑战在于Docker
本身并不管理服务的启动的过程,
一个Docker
服务在启动entrypoint
或者command
进程的时候就开始了,
一直到这个进程退出后才能被Docker
识别服务结束。
Docker
服务的生命周期不同于使用服务角度的声明周期,
从使用服务的角度看,有这么几个关键点
然后结合Docker
服务的生命周期的关键点一起看
entrypoint
或者command
进程启动entrypoint
或者command
进程结束Docker
可以识别entrypoint
或者command
进程的启动和结束,
但是里面的细节就很难识别了。
daemon
在启动服务的过程中还有一个容易混淆的地方————守护进程daemon
,
Linux
中的服务往往以守护进程daemon
的形式出现。
所有守护进程的启动脚本,都放在/etc/init.d
目录下面。
init
进程的主要任务,就是逐一运行这些脚本。
在Linux
中一个守护进程的父进程是init
进程,
因为守护进程真正的父进程在fork
出子进程后就先于子进程exit
退出了,
所以守护进程是一个由init
继承的孤儿进程。
这种工作方式有两个基本的用途。
fork
子进程的同时可以设置子进程运行于不同的环境,例如不同的用户。init
中是串行的,而且可以依循一定的顺序,fork
具体提供服务的子进程后,父进程退出,init
运行下一个守护进程的启动的父进程,免责声明:本段并非专门的Linux
技术分析,仅用于介绍相关知识。
Docker Compose
既然Docker Compose
中按照顺序启动服务的情况和守护进程类似,
那么能不能使用相同的机制呢?
从技术上没问题,如果所有的服务都采用和守护进程类似的机制,例如fork
出子进程,
或者使用&
运行后台进程。总之,只要保证主进程退出,
就可以被Docker Compose
识别了。
这种方式看上去很美,不过就严格限制了服务的灵活性。
猜测,仅仅是猜测,Docker
没有找到尽善尽美的解决方案,所以没有提供这个功能。
Docker
的解决方案Docker
没有提供直接的解决方案,不过也并且给出了一篇参考文章:
https://docs.docker.com/compose/startup-order/
这篇文章很神奇,神奇之处不是提出了什么奇思妙想,
神奇之处在于点踩的人数远远多于点赞的人数,
今天(2018年4月3日)的数据是172踩53赞。竟然达到了3倍之多!
这种情况在官方文档中是非常罕见的。
不过我也要赞一下,不是赞这篇文章,
而是为Docker
公司把这么一个数字暴露出来的勇气点赞。
文章内容就不讨论了,思路类似。
既然官方给出的思路是服务之间检测,那么检测端口是一个方法,而且是非侵入式的。
不过当另一个服务并没有提供端口,例如仅仅是若干操作环节中的一个步骤,
就不能检查端口了,此时就需要借助其他的方式。
前置的服务设置一个标志,后续的服务检查这个标志。
从这个角度思考,借助文件系统检查时间戳可能是最简单的方法之一。
volume
在不同的服务之间共享卷touch
一个文件作为标记具体涉及到两个技术细节。
uptime
,这个是主机的启动时间,https://github.com/huzhenghui/Docker-Compose-Startup-Order
version: "3"
services:
service_1:
image: ubuntu
volumes:
- Docker-Compose-Startup-Order:/Startup-Order
command: |
bash -c '
echo Service 1 Start;
sleep 10;
echo Service 1 Up;
touch /Startup-Order/service_1;'
service_2:
image: ubuntu
volumes:
- Docker-Compose-Startup-Order:/Startup-Order
command: |
bash -c '
while [[ ! -f /Startup-Order/service_1 || /Startup-Order/service_1 -ot /proc/1/cmdline ]]; do sleep 1; done;
echo Service 2 Start;
sleep 10;
echo Service 2 Up;
touch /Startup-Order/service_2;'
service_3:
image: ubuntu
volumes:
- Docker-Compose-Startup-Order:/Startup-Order
command: |
bash -c '
while [[ ! -f /Startup-Order/service_2 || /Startup-Order/service_2 -ot /proc/1/cmdline ]]; do sleep 1; done;
echo Service 3 Start;
sleep 10;
echo Service 3 Up;'
volumes:
Docker-Compose-Startup-Order:
PS C:\Users\huzh\OneDrive\Docker\Docker-Compose-Startup-Order> docker-compose up
Starting dockercomposestartuporder_service_1_1 ...
Starting dockercomposestartuporder_service_3_1 ...
Starting dockercomposestartuporder_service_3_1 ... done
Attaching to dockercomposestartuporder_service_1_1, dockercomposestartuporder_service_2_1, dockercomposestartuporder_service_3_1
service_1_1 | Service 1 Start
service_1_1 | Service 1 Up
dockercomposestartuporder_service_1_1 exited with code 0
service_2_1 | Service 2 Start
service_2_1 | Service 2 Up
dockercomposestartuporder_service_2_1 exited with code 0
service_3_1 | Service 3 Start
service_3_1 | Service 3 Up
dockercomposestartuporder_service_3_1 exited with code 0
PS C:\Users\huzh\OneDrive\Docker\Docker-Compose-Startup-Order>