我想在一个堆栈中启动两个服务。
主要问题是弹簧启动在数据库之前启动(或在不允许连接数据库时启动)。然后在日志中,我可以看到:java.net.UnknownHostException: database
。
我们可以使用启动顺序: https://docs.docker.com/compose/startup-order/
那我该怎么办?我用docker-compose将wait-for-it.sh
复制到文件,添加行
command: ["./wait-for-it.sh", "database:3306", "--", "java -Dspring.profiles.active=prod -jar app.jar"]
结果是:
java.lang.IllegalArgumentException: Invalid argument syntax: --
后端entrypoint
中我的Dockerfile
:
ENTRYPOINT ["java","-Dspring.profiles.active=prod", "-jar","app.jar"]
如何使Spring Boot应用程序在docker stack下等待MySQL数据库?
答案 0 :(得分:0)
运行容器时,the ENTRYPOINT
and CMD
are combined。在您的示例中,您已经设置ENTRYPOINT
来运行Java进程,但是随后在CMD
中覆盖了docker-compose.yml
:而不是实际运行wait-for-it.sh
脚本,它只是被传递了作为JVM的额外参数。
将两者同时使用的典型模式是使ENTRYPOINT
是某种包装程序,该包装程序会进行首次设置,然后将CMD
作为附加参数。为此,CMD
必须是完整的shell命令。将Dockerfile更改为:
COPY wait-for-it.sh entrypoint.sh .
# ENTRYPOINT _must_ be in JSON-array form
ENTRYPOINT ["./entrypoint.sh"]
# CMD may be either string or JSON-array form
# (This is exactly what you originally had as ENTRYPOINT)
CMD ["java", "-Dspring.profiles.active=prod", "-jar", "app.jar"]
入口点脚本可以非常简单:
#!/bin/sh
# Wait for the database to be up
if [ -n "$MYSQL_HOST" ]; then
./wait-for-it.sh "$MYSQL_HOST:3306"
fi
# Run the CMD
exec "$@"
这里的重要细节是我已经配置数据库主机作为环境变量进行传递。这需要运行一个外壳来扩展它,这在JSON数组ENTRYPOINT
语法中很难完成,因此我将其移到了单独的脚本中。
最后,在docker-compose.yml
中,不要覆盖command:
(或entrypoint:
),但请确保设置脚本的环境变量以能够找到数据库。
version: '3.8'
services:
database: { ... }
application:
environment:
MYSQL_HOST: database
depends_on:
- database
# no command: override
只要容器启动,这里的包装器就会运行,因此,如果您docker-compose run application bash
获取基于图像的交互式外壳,它将仍然等待数据库启动。
如果同时控制Dockerfile和docker-compose.yml
,则通常不需要在“撰写”设置中覆盖command:
。我发现entrypoint-wrapper模式足够有用,以至于我通常默认在Dockerfiles中使用CMD
(不需要使用ENTRYPOINT
)。