只是想在通过 docker-compose 运行 postgres 和应用程序时添加我的解决方案,我需要应用程序在开始之前等待 init sql 脚本完成。
dockerize 似乎在等待 db 端口可用(端口 5432),这是 depends_on 的等价物,可在 docker 3 中使用:
version: '3'
services:
app:
container_name: back-end
depends_on:
- postgres
postgres:
image: postgres:10-alpine
container_name: postgres
ports:
- "5432:5432"
volumes:
- ./docker-init:/docker-entrypoint-initdb.d/
问题:
如果您有一个大型初始化脚本,则应用程序将在该脚本完成之前启动,因为 depends_on 只等待数据库端口。
虽然我同意解决方案应该在应用程序逻辑中实现,但我们遇到的问题仅适用于我们想要运行测试并使用测试数据预填充数据库时,因此在代码之外实现解决方案更有意义因为我倾向于不喜欢引入代码“让测试工作”
解决方案:
在 postgres 容器上实施健康检查。
对我来说,这意味着检查 pid 1 的命令是 postgres,因为它会在 init db 脚本运行时在 pid 1 上运行不同的命令
在应用程序端编写一个脚本,等待postgres 变为healthy。脚本如下所示:
#!/bin/bash
function check {
STATUS=\`curl -s --unix-socket /var/run/docker.sock http:/v1.24/containers/postgres/json | python -c 'import sys, json; print json.load('sys.stdin')["State"]["Health"]["Status"]'\`
if [ "$STATUS" = "healthy" ]; then
return 0
fi
return 1
}
until check; do
echo "Waiting for postgres to be ready"
sleep 5
done
echo "Postgres ready"
然后 docker-compose 应该挂载脚本的目录,这样我们就不会为应用程序编辑 Dockerfile,如果我们使用自定义 postgres 映像,这样我们就可以继续为您的应用程序使用 docker 文件已发布图片。
我们还覆盖了应用程序的 docker 文件中定义的入口点,以便我们可以在应用程序启动之前运行等待脚本
version: '3'
services:
app:
container_name: back-end
entrypoint: ["/bin/sh","-c","/opt/app/wait/wait-for-postgres.sh && <YOUR_APP_START_SCRIPT>"]
depends_on:
- postgres
volumes:
- //var/run/docker.sock:/var/run/docker.sock
- ./docker-scripts/wait-for-postgres:/opt/app/wait
postgres:
image: postgres:10-alpine
container_name: postgres
ports:
- "5432:5432"
volumes:
- ./docker-init:/docker-entrypoint-initdb.d/
- ./docker-scripts/postgres-healthcheck:/var/lib
healthcheck:
test: /var/lib/healthcheck.sh
interval: 5s
timeout: 5s
retries: 10