docker-compose 提供了 depends_on 选项,以便控制服务的启动和关闭顺序。这个选项确保服务在启动时遵循依赖关系,其中依赖关系通过停止容器的 depends_on、links、volumes_from 和 network_mode: “service:…” 来定义。
然而,在启动过程中,Compose 不会等待容器完全“就绪”(就您的特定应用程序而言)后再运行。这背后有其合理原因。
例如,等待数据库准备就绪的问题实际上是分布式系统面临的更大挑战之一。在生产环境中,您的数据库可能随时不可用或迁移到其他主机。您的应用程序必须能够应对这些故障。
为了解决这个问题,您可以设计应用程序,使其在失败后重新尝试与数据库的连接。如果应用程序能够重试连接,它最终会成功连接到数据库。
最佳的解决方案是在应用程序代码中实现启动时和断开连接时的检查。然而,如果您不需要如此高的弹性,可以考虑使用包装脚本来解决此问题:
可以使用工具如 wait-for-it、dockerize、sh-compatible wait-for 或 RelayAndContainers 模板。这些是小型包装脚本,可以嵌入到应用程序的镜像中,定期轮询特定的主机和端口,直到接受 TCP 连接为止。
例如,使用 wait-for-it.sh 或 wait-for 脚本来包装服务的命令:
version: “2”
services:
web:
build: .
ports:
– “80:8000”
depends_on:
– “db”
command: [“./wait-for-it.sh”, “db:5432”, “–“, “python”, “app.py”]
db:
image: postgres
第一个解决方案存在局限性,例如,它无法验证特定服务何时真正就绪。如果您向命令添加更多参数,可以结合使用 bash shift 命令和循环,如下所示。
或者,您可以编写自定义包装脚本,以执行更符合应用程序需求的健康检查。例如,您可能希望等待 PostgreSQL 准备好接收命令:
#!/bin/sh
# wait-for-postgres.sh
set -e
host=”$1″
shift
cmd=”$@”
until PGPASSWORD=$POSTGRES_PASSWORD psql -h “$host” -U “postgres” -c ””q””; do
>&2 echo “PostgreSQL is unavailable – sleeping”
sleep 1
done
>&2 echo “PostgreSQL is up – executing command”
exec $cmd
您可以将其用作前面示例中的包装脚本:
command: [“./wait-for-postgres.sh”, “db”, “python”, “app.py”]
