在我的 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 ,它将创建项目......
$PROJECTNAME
?
CMD ["sh", "-c", "your command with ${any ENV} here"]
当您使用执行列表时,如...
CMD ["django-admin", "startproject", "$PROJECTNAME"]
...然后 Docker 将直接执行给定的命令,而不涉及 shell。由于不涉及外壳,这意味着:
无变量扩展
没有通配符扩展
没有使用 >、<、| 等的 i/o 重定向
没有通过 command1 的多个命令;命令2
等等。
如果您希望您的 CMD
扩展变量,您需要安排一个外壳。你可以这样做:
CMD ["sh", "-c", "django-admin startproject $PROJECTNAME"]
或者你可以使用一个简单的字符串而不是一个执行列表,它得到的结果与前面的例子大致相同:
CMD django-admin startproject $PROJECTNAME
如果要在运行时使用该值,请在 Dockerfile
中设置 ENV
值。如果您想在构建时使用它,那么您应该使用 ARG
。
例子 :
ARG value
ENV envValue=$value
CMD ["sh", "-c", "java -jar ${envValue}.jar"]
在构建命令中传递值:
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 "$@")
对于 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 上的任何内容,并允许它能够作为容器的父进程启动,以通过 {1 发出有效的 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}
受上述启发,我这样做了:
#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 && \
.....
exec
来替换 bash 的新进程。它可能与接收信号和 CTRL+C 有关。CMD ["sh", "-c", "exec django-admin startproject $PROJECTNAME"]
之类的东西。