Docker构建时如何根据build-arg参数条件配置CMD指令
错误根因
RUN 指令的执行逻辑是调用容器内的系统shell(默认/bin/sh)运行传入的命令字符串,而CMD是Docker构建器解析的Dockerfile原生指令,不属于shell环境下的可执行程序,把CMD写在RUN的shell判断逻辑中时,shell会将其作为普通系统命令查找,自然抛出CMD: not found错误。
正确实现方案
推荐使用无版本兼容问题的启动阶段判断方案,不需要依赖高版本Docker特性,逻辑稳定:
- 调整Dockerfile,将构建参数透传为容器内环境变量,把判断逻辑放到容器启动阶段执行:
# 声明构建参数 ARG arg # 将构建参数映射为容器运行时可读取的环境变量 ENV RUNTIME_ARG=${arg} # 此处保留你原有的构建逻辑,比如依赖安装、文件复制等步骤 # COPY . . # RUN yarn install --frozen-lockfile # 启动时根据环境变量判断执行逻辑,替换下方else分支为你非test场景下的默认启动命令 CMD if [ "$RUNTIME_ARG" = "test" ]; then yarn test; else yarn start; fi
- 构建命令不需要调整,和你原有写法一致即可:
docker build -f ./Dockerfile -t ${npm_package_version} . --build-arg arg=test
如果希望启动逻辑更易维护,可以把判断逻辑抽到独立的入口脚本中:
- 新建
entrypoint.sh文件:
#!/bin/sh if [ "$RUNTIME_ARG" = "test" ]; then yarn test else # 非test场景执行传入的启动命令 exec "$@" fi
- 调整Dockerfile对应部分:
COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] # 非test场景的默认启动命令 CMD ["yarn", "start"]
如果你使用的是18.09及以上版本Docker,也可以开启BuildKit后使用构建阶段条件判断,直接在构建时决定是否写入CMD配置,但该方案需要提前在构建环境开启BuildKit(执行export DOCKER_BUILDKIT=1),兼容性弱于上述启动阶段判断方案。
注意:所有Dockerfile内置指令(
FROM/COPY/RUN/CMD/ENTRYPOINT等)均由Docker构建器在解析Dockerfile阶段识别,无法通过RUN调用的shell环境动态生成或执行。
内容的提问来源于stack exchange,提问作者Panch
相关产品推荐
相关产品推荐

