注:该文作者是 Chmouel,原文是 Avoiding race conditions between containers with docker and fig
该文我主要是意译,详细的看原文吧。
使用 Docker 和 Fig 的时候,当我们启动多个容器的时候,比如一个 web 服务和一个 DB 服务,就有可能遇到竞争问题。正常来说,应该是 DB 先与 Web 服务启动,但是因为 DB 没有时间配置它自己,然后 web 服务已经启动了,这样就会造成 web 连接数据库失败。
理想中,app 应该等待 DB 已经设置好并且启动后才开始连接 DB。但是这不是一件容易的事情。
docker 和 fig 的开发者已经注意到这个问题,并且在开发版已经有一些建议了:
https://github.com/docker/docker/issues/7445
这个主意就是 docker 必须等待暴露的端口已经打开了并且 listening 是可用的才告诉容器已经启动。这不是容易做到的,因为 Docker 将很难弄清楚该端口是开放的。
这有个内建的 Python 解决方案。代码如下:
function check_up() {
service=$1
host=$2
port=$3
max=13 # 1 minute
counter=1
while true;do
python -c "import socket;s = socket.socket(socket.AF_INET, socket.SOCK_STREAM);s.connect(('$host', $port))" >/dev/null 2>/dev/null && break || echo "Waiting that $service on ${host}:${port} is started (sleeping for 5)"
if [[ ${counter} == ${max} ]];then
echo "Could not connect to ${service} after some time"
echo "Investigate locally the logs with fig logs"
exit 1
fi
sleep 5
(( counter++ ))
done
}
在我 app 服务的 start.sh
脚本中,在启动我的 web 服务之前,我像这样使用它:
check_up "DB Server" ${DB_PORT_3306_TCP_ADDR} 3306
该方法的优势是它能非常快速的知道端口是否打开。