Dockerfile CMD指令无法插值解析ENV环境变量问题排查
问题现象
我已尝试所有能想到的配置组合,仍未解决问题。
相关配置文件
docker-compose.yml
version: "3.1" services: node-server: build: context: . dockerfile: Dockerfile args: - MYVAR=${MYVAR} environment: - ENV_MYVAR=${MYVAR} ports: - 8000:8000 env_file: - .env # command: ["npm", "run", "_${MYVAR}_"] This works, but for the sake of testing CMD in Dockerfile, I can't get that to work
Dockerfile
FROM node:14 ARG MYVAR ENV ENV_MYVAR="${MYVAR}" WORKDIR /usr/src/app COPY package*.json ./ RUN npm i COPY . . EXPOSE ${port} RUN echo "1" RUN echo $MYVAR # Works CMD [ "npm", "run", "_${ENV_MYVAR}_"] # OUTPUTS as _${ENV_MYVAR}_". Does not interpolate!!
.env
MYVAR=boot
package.json
{ "name": "node-server-ts", "version": "1.0.0", "license": "MIT", "scripts": { "test": "echo 'test'", "boot": "echo 'boot'", "_boot_": "echo '_boot_'" } }
执行与结果
- 终端执行命令:
docker-compose up - 预期执行结果:
npm run _boot_
实际报错:node-server_1 | ${ENV_MYVAR}
问题描述
构建阶段RUN echo $MYVAR可正常输出变量值,docker-compose中配置同格式command指令可正常生效,但Dockerfile中exec格式的CMD指令未对${ENV_MYVAR}进行变量插值,直接将变量名字符串作为参数传入导致运行报错。
问题原因
Dockerfile中CMD、ENTRYPOINT的exec格式(即方括号包裹的数组写法)不会触发shell变量替换逻辑,Docker会直接将数组内的字符串原样作为进程参数传递,完全不会解析${}这类变量引用语法。RUN echo $MYVAR能正常输出变量值,是因为RUN指令默认通过/bin/sh -c执行,shell会在命令运行前完成变量插值;docker-compose中配置的同格式command能生效,是因为docker-compose会在宿主机侧提前完成自身的变量替换逻辑,再把替换后的固定值传给容器,和Dockerfile内CMD的执行逻辑完全不同。
解决方案
二选一即可:
- 改用shell格式写CMD
把exec格式的CMD换成shell写法,Docker会自动调用shell执行,由shell完成环境变量插值:
这种写法等价于自动执行# 替换原有CMD数组写法 CMD npm run "_${ENV_MYVAR}_"/bin/sh -c "npm run _${ENV_MYVAR}_",变量会被正常解析。 - 必须使用exec格式(比如要接收Unix信号、透传启动参数)时,显式调用shell
手动在exec数组里指定shell作为执行入口,把命令作为shell的参数传入:
这种写法下变量插值由容器内的shell完成,可以正确读取容器内的CMD ["/bin/sh", "-c", "npm run _${ENV_MYVAR}_"]ENV_MYVAR环境变量。
内容的提问来源于stack exchange,提问作者Inspiraller
相关产品推荐
相关产品推荐

