如何在ENTRYPOINT数组中使用Docker环境变量?

如果我设置了一个环境变量,比如ENV ADDRESSEE=world,并且我想在入口点脚本中使用它,连接成一个固定的字符串,比如:

ENTRYPOINT ["./greeting", "--message", "Hello, world!"]

world是环境变量的值,我怎么做?我尝试使用"Hello, $ADDRESSEE",但这似乎不起作用,因为它从字面上接受$ADDRESSEE

170583 次浏览

你正在使用ENTRYPOINT的exec形式。与壳形式不同,exec形式不调用命令shell。这意味着正常的外壳处理不会发生。例如,ENTRYPOINT [ "echo", "$HOME" ]将不会对$HOME进行变量替换。如果你想要shell处理,那么使用壳形式或直接执行shell,例如:ENTRYPOINT [ "sh", "-c", "echo $HOME" ].
当使用exec表单并直接执行shell时,就像shell表单一样,是shell在进行环境变量扩展,而不是docker。(从Dockerfile参考) < / p >

在你的情况下,我会使用壳形式

ENTRYPOINT ./greeting --message "Hello, $ADDRESSEE\!"

我试图用建议的答案来解决问题,但仍然遇到了一些问题……

这是我问题的解决方案:

ARG APP_EXE="AppName.exe"
ENV _EXE=${APP_EXE}


# Build a shell script because the ENTRYPOINT command doesn't like using ENV
RUN echo "#!/bin/bash \n mono ${_EXE}" > ./entrypoint.sh
RUN chmod +x ./entrypoint.sh


# Run the generated shell script.
ENTRYPOINT ["./entrypoint.sh"]

特别针对你的问题:

RUN echo "#!/bin/bash \n ./greeting --message ${ADDRESSEE}" > ./entrypoint.sh
RUN chmod +x ./entrypoint.sh
ENTRYPOINT ["./entrypoint.sh"]

在经历了很多痛苦和上面@vitr等人的伟大的帮助之后,我决定尝试一下

  • 标准bash替换
  • 入口点壳形式(上面的好提示)

这很有效。

ENV LISTEN_PORT=""


ENTRYPOINT java -cp "app:app/lib/*" hello.Application --server.port=${LISTEN_PORT:-80}

如。

docker run --rm -p 8080:8080 -d --env LISTEN_PORT=8080 my-image

而且

docker run --rm -p 8080:80 -d my-image

两者都在容器中正确地设置了端口

参考文献

看到https://www.cyberciti.biz/tips/bash-shell-parameter-substitution-2.html

在我的案例中,工作方式是这样的:(用于docker中的Spring引导应用程序)

ENTRYPOINT java -DidMachine=${IDMACHINE} -jar my-app-name

并在docker运行时传递参数

docker run --env IDMACHINE=Idmachine -p 8383:8383 my-app-name

对于我来说,我希望将脚本的名称存储在一个变量中,并且仍然使用exec表单。

注意:确保你要使用的变量已经通过命令行或ENV指令声明为环境变量。

最初我是这样做的:

ENTRYPOINT [ "${BASE_FOLDER}/scripts/entrypoint.sh" ]

但显然这行不通,因为我们使用的是壳牌形式,而列出的第一个程序必须是PATH上的可执行程序。所以为了解决这个问题,这就是我最后做的:

ENTRYPOINT [ "/bin/bash", "-c", "exec ${BASE_FOLDER}/scripts/entrypoint.sh \"${@}\"", "--" ]

必须使用双引号

这样做的目的是允许我们获取传递给/bin/bash的任何额外参数,并在名称被bash解析后将这些相同的参数提供给脚本。


man 7 bash

——
A——表示选项结束并进一步禁用 选择处理。之后的任何争论都会被处理 作为文件名和参数。是的论点 等价于——.

以下是对我有效的方法:

ENTRYPOINT [ "/bin/bash", "-c", "source ~/.bashrc && ./entrypoint.sh ${@}", "--" ]

现在你可以向docker run命令提供任何参数,并且仍然可以读取所有环境变量。

我很简单地解决了这个问题!

< >强重要:< / >强你希望在ENTRYPOINT < >强必须< / >强中使用的变量是ENV类型(而不是ARG类型)。

例# 1:

ARG APP_NAME=app.jar                    # $APP_NAME can be ARG or ENV type.
ENV APP_PATH=app-directory/$APP_NAME    # $APP_PATH must be ENV type.
ENTRYPOINT java -jar $APP_PATH
这将导致执行: java -jar app-directory/app.jar < / p >

例2(你的问题):

ARG ADDRESSEE="world"                       # $ADDRESSEE can be ARG or ENV type.
ENV MESSAGE="Hello, $ADDRESSEE!"            # $MESSAGE must be ENV type.
ENTRYPOINT ./greeting --message $MESSAGE
这将导致执行: ./greeting --message Hello, world! < / p >
  • 请确认在分配字符串变量时是否需要引号 ""

< >强我提示:< / >强尽可能使用ENV而不是ARG,以避免您的部分或SHELL方面的混淆。

我用“创建自定义脚本”的变体解决了这个问题。上面的方法。是这样的:

FROM hairyhenderson/figlet
ENV GREETING="Hello"
RUN printf '#!/bin/sh\nfiglet -W \${GREETING} \$@\n' > /runme && chmod +x /runme
ENTRYPOINT ["/runme"]
CMD ["World"]

docker container run -it --rm -e GREETING="G'Day" dockerfornovices/figlet-greeter Alec

如果有人想将ARGENV变量传递给ENTRYPOINT的exec形式,则可能会使用在映像构建过程中创建的临时文件。

在我的情况下,我必须以不同的方式启动应用程序,这取决于. net应用程序是否已发布为自包含的。 我所做的是创建临时文件,并在bash脚本的if语句中使用它的名称

dockerfile的一部分:

ARG SELF_CONTAINED=true #ENV SELF_CONTAINED=true also works
# File has to be used as a variable as it's impossible to pass variable do ENTRYPOINT using Exec form. File name allows to check whether app is self-contained
RUN touch ${SELF_CONTAINED}.txt
COPY run-dotnet-app.sh .
ENTRYPOINT ["./run-dotnet-app.sh", "MyApp" ]

run-dotnet-app.sh:

#!/bin/sh


FILENAME=$1


if [ -f "true.txt" ]; then
./"${FILENAME}"
else
dotnet "${FILENAME}".dll
fi