Docker堆栈-等待它

时间:2020-11-04 10:00:30

标签: java docker

我想在一个堆栈中启动两个服务。

  1. Mysql
  2. 春季启动应用

主要问题是弹簧启动在数据库之前启动(或在不允许连接数据库时启动)。然后在日志中,我可以看到: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数据库?

1 个答案:

答案 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)。