在 Dockerfile 中使用 shell 脚本运行 java 以接收操作系统信号

问题描述 投票:0回答:1

我想运行一个 shell 脚本,该脚本将在容器运行时导入 Amazon RDS 证书,然后启动我的 Java 应用程序。

我有以下入口点:

ENTRYPOINT ./import-amazon-rds-certs.sh && java -jar /app.jar

问题是

ENTRYPOINT
命令未接收操作系统信号 - 正如所解释的https://docs.docker.com/reference/build-checks/json-args-recommended/

我想知道如何运行此脚本以使我的 Java 应用程序接收操作系统信号。

java bash docker dockerfile
1个回答
0
投票

您可以编写一个脚本来进行首次设置,然后使用特殊的 shell

exec
命令将 shell 脚本替换为主容器进程。 那么你的Java应用程序在容器内的pid将是1,它将直接接收
docker stop
和类似的信号。

我通常建议将其分为两部分,“进行设置”和“主容器命令”。 如果“设置”部分作为图像的

ENTRYPOINT
运行,那么它会接收
CMD
作为参数(可能在容器启动时被覆盖)。 因此,执行设置的典型脚本可能是

#!/bin/sh

# run the setup script
if ! ./import-amazon-rds-certs.sh; then
  echo 'failed to import certificates' >&2
  exit 1
fi

# switch to the main container command
exec "$@"

在 Dockerfile 中,您需要将安装脚本和主命令分成两个单独的部分,例如

COPY entrypoint.sh ./  # should be checked into source control as executable
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["java", "-jar", "/app/app.jar"]

这里还有一个微妙之处。

ENTRYPOINT
CMD
(还有
RUN
)有两种语法。 如果您只是写出一个命令字符串,Docker 会自动将其包装在
/bin/sh -c
中。 这有一些不良的副作用。 对于您的情况,外壳包装器接收信号而不是您的主命令。 特别是对于
ENTRYPOINT
sh -c
也会“吞噬”命令行参数,因此您实际上无法运行
CMD
。 我已将
ENTRYPOINT
CMD
制作为“exec 形式”JSON 数组,这避免了引入 shell 包装器。


偶尔会有一种模式尝试使

CMD
列表只是应用程序的参数。 我倾向于避免这种模式(例如,如果您使用上面的入口点包装器
docker run --rm -it ... sh
您的图像,则可以验证 RDS 凭据是否已出现)。 如果您尝试使用此模式,shell 构造
"$@"
会扩展到所有当前位置参数,并且 Docker 会以这种方式传递
CMD

在这种情况下,入口点包装脚本可能以

结尾
exec java -jar /app/app.jar "$@"

你可以

docker run ... your-image --options-to-java-app
© www.soinside.com 2019 - 2024. All rights reserved.