在我的Dockerfile里面:

ENV PROJECTNAME mytestwebsite
CMD ["django-admin", "startproject", "$PROJECTNAME"]

错误:

CommandError: '$PROJECTNAME' is not a valid project name

这里最快的解决办法是什么?Docker是否计划在Docker的后续版本中“修复”或引入该功能?

注意:如果我从Docker文件中删除CMD行,然后运行Docker容器,我可以在容器中手动运行Django-admin startproject $PROJECTNAME,它将创建项目…


当前回答

受上述启发,我这样做了:

#snapshot by default. 1 is release.
ENV isTagAndRelease=0

CMD     echo is_tag: ${isTagAndRelease} && \
        if [ ${isTagAndRelease} -eq 1 ]; then echo "release build"; mvn -B release:clean release:prepare release:perform; fi && \
        if [ ${isTagAndRelease} -ne 1 ]; then echo "snapshot build"; mvn clean install; fi && \ 
       .....

其他回答

受上述启发,我这样做了:

#snapshot by default. 1 is release.
ENV isTagAndRelease=0

CMD     echo is_tag: ${isTagAndRelease} && \
        if [ ${isTagAndRelease} -eq 1 ]; then echo "release build"; mvn -B release:clean release:prepare release:perform; fi && \
        if [ ${isTagAndRelease} -ne 1 ]; then echo "snapshot build"; mvn clean install; fi && \ 
       .....

如果你想在运行时使用这个值,在Dockerfile中设置ENV值。如果你想在构建时使用它,那么你应该使用ARG。

例子:

ARG value
ENV envValue=$value
CMD ["sh", "-c", "java -jar ${envValue}.jar"]

在build命令中传递这个值:

docker build -t tagName --build-arg value="jarName"

假设你想在一个容器中启动一个java进程:

Dockerfile摘录示例:

ENV JAVA_OPTS -XX +UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm 
... 
ENTRYPOINT ["/sbin/tini", "--", "entrypoint.sh"] 
CMD ["java", "${JAVA_OPTS}", "-myargument=true"]

示例entrypoint.sh摘录:

#!/bin/sh 
... 
echo "*** Startup $0 suceeded now starting service using eval to expand CMD variables ***"
exec su-exec mytechuser $(eval echo "$@")

你也可以使用exec 这是唯一已知的同时处理信号和使用env变量的方法。 这可能是有帮助的,而试图实现一些像优雅关闭根据Docker github

例子:

ENV PROJECTNAME mytestwebsite 
CMD exec django-admin startproject $PROJECTNAME

对于Java开发人员来说,遵循以下我的解决方案将起作用:

如果你试图像下面这样用Dockerfile运行你的容器

ENTRYPOINT ["/docker-entrypoint.sh"]
# does not matter your parameter $JAVA_OPTS wrapped as ${JAVA_OPTS}
CMD ["java", "$JAVA_OPTS", "-javaagent:/opt/newrelic/newrelic.jar", "-server", "-jar", "app.jar"]

下面是一个ENTRYPOINT shell脚本:

#!/bin/bash
set -e
source /work-dir/env.sh
exec "$@"

它将正确地构建图像,但在容器运行期间打印以下错误:

Error: Could not find or load main class $JAVA_OPTS
Caused by: java.lang.ClassNotFoundException: $JAVA_OPTS

相反,Java可以通过命令行或_JAVA_OPTIONS环境变量读取命令行参数。因此,这意味着我们可以通过_JAVA_OPTIONS传递所需的命令行参数,而不改变Dockerfile上的任何内容,同时允许它能够作为容器的父进程启动,通过exec“$@”进行有效的docker信号发送。

下面是Dockerfile和docker-entrypoint.sh文件的最终版本:

...
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["java", "-server", "-jar", "app.jar"]
#!/bin/bash
set -e
source /work-dir/env.sh
export _JAVA_OPTIONS="-XX:+PrintFlagsFinal"
exec "$@"

在你构建docker镜像并尝试运行它之后,你会看到下面的日志,这意味着它工作得很好:

Picked up _JAVA_OPTIONS: -XX:+PrintFlagsFinal
[Global flags]
      int ActiveProcessorCount                     = -1                                        {product} {default}