copy指令不支持直接展开环境变量,需通过arg构建参数或宿主机路径预处理间接实现;运行时env无法影响构建阶段的copy行为。

COPY 指令本身不支持直接展开环境变量,它只做静态路径复制,不能像 RUN 那样解析 $VAR 或 ${VAR}。但你可以通过几种方式间接实现“带环境变量的复制”效果,关键看你要解决什么问题:
COPY 无法直接用环境变量(常见误区)
下面写法是无效的,构建会失败或复制空目录:
COPY $APP_DIR/src ./src # ❌ 错误:COPY 不解析变量
Dockerfile 解析 `COPY` 时,变量尚未被替换,底层只是字符串字面量匹配宿主机路径。
正确做法一:用 ARG + 构建时传参
如果想让复制路径可配置(比如不同环境复制不同子目录),用 ARG 定义构建参数,再在 COPY 中引用:
- 在 Dockerfile 开头声明:
ARG SRC_PATH=app/src - 然后使用:
COPY ${SRC_PATH} /app/src - 构建时指定:
docker build --build-arg SRC_PATH=staging/src -t myapp .
注意:ARG 必须在 FROM 之后、且早于使用它的指令;它只在构建阶段生效,不影响运行时。
正确做法二:把变量逻辑移到宿主机路径上
更常用也更可靠的方式是——让宿主机路径本身体现变量含义:
- 比如你有多个版本源码放在
./src-v1、./src-v2,就用COPY src-v1/ /app/src/ - 或者用 CI/CD 脚本动态软链接:
ln -sf src-$VERSION src-current,再COPY src-current/ /app/src/
这样完全绕过 Dockerfile 变量限制,清晰可控,适合生产环境。
运行时环境变量 ≠ 构建时路径控制
如果你真正想要的是“根据容器运行时的 ENV 动态决定复制哪份文件”,那是不可能的——COPY 发生在构建阶段,而 ENV 是镜像层的一部分,不会反向影响构建行为。这种需求应改为:
- 构建时把所有可能用到的资源都 COPY 进去
- 用
ENTRYPOINT或启动脚本,根据$ENV_VAR选择启用哪个配置/代码分支
例如:COPY configs/ /app/configs/,然后在启动脚本里 cp /app/configs/$ENVIRONMENT.yaml /app/config.yaml。
不复杂但容易忽略











