Dockerfile 的 RUN source 报 not found:切换构建 shell 后还要保留同一步环境
构建时RUN source报not found,检查Dockerfile默认shell。选择Bash或POSIX点命令,并在同一RUN使用加载的环境。
Dockerfile 中执行 RUN source /opt/build/env.sh,报 /bin/sh: 1: source: not found;进入容器手工用 Bash 却能加载同一文件。若使用 Linux 镜像且没有修改 SHELL,构建步骤默认由 /bin/sh -c 处理。应先解决解释器差异,再判断加载的环境要在哪一步使用。
本文适用于 Dockerfile 构建时加载环境或函数的场景。它不涉及容器运行入口的信号处理,也不能让 shell 函数自动成为镜像里的独立命令。
文件存在不代表当前 shell 支持 source
如果报错对象是 source,不是环境文件路径,检查当前阶段的 SHELL 和 shell 安装状态。source 是 Bash 的内建命令,不能把它当作要安装的普通程序。
环境文件只使用 POSIX shell 语法时,可以用点命令,以下为示例:
RUN . /opt/build/env.sh && /opt/build/build-app
点后必须有空格,文件路径替换为实际的受信任配置脚本。点命令会执行文件中的代码,不能用它加载来历不明的配置。若文件含 Bash 数组或其他专用语法,仅把 source 改成 . 仍可能失败。
需要 Bash 时,明确选择它
当前镜像已有 /bin/bash 时,可以只为这一条步骤指定解释器:
RUN ["/bin/bash", "-c", "source /opt/build/env.sh && /opt/build/build-app"]
后续多条步骤都需要 Bash 时,在当前阶段先设置:
SHELL ["/bin/bash", "-c"]
RUN source /opt/build/env.sh && /opt/build/build-app
基础镜像若没有 Bash,应按该发行版的包管理方式先安装,或者使用确实支持的 POSIX 写法。不要删除 /bin/sh 再把它链接到 Bash,单个构建需求不应改变整个镜像中其他脚本的解释器。
SHELL 控制后续 shell 形式的指令;exec 形式中显式写出的程序仍由该数组决定。增加新的 FROM 后也要检查该阶段自己的基础镜像和 shell 配置,不能只看 builder 的设置。
source 成功后,下一条 RUN 仍可能没有变量或函数
每条 RUN 都开启自己的进程。加载环境文件后留下的文件修改可以保留,但当前 shell 中的变量、函数和激活状态不会因为上一条成功就传给下一条。
因此,需要加载配置后立即编译、安装依赖或调用某个函数时,把加载和使用放在同一条 RUN 内,用 && 在加载失败时阻止后续动作。需要长期保留的普通非敏感变量,可以用 Dockerfile 的 ENV;它会进入镜像配置,不能用来保留密码、密钥等构建秘密。
如果只是调用虚拟环境中的程序,能够直接使用其绝对路径时,通常无需加载整个交互配置文件。也不要默认添加 --login 就能读取 .bashrc,登录与交互 shell 的启动文件规则不同。
修复后,真正依赖这份配置的构建步骤应在同一步中成功完成,后续镜像里的程序和文件符合预期。仅让一条独立的 RUN source ... 不报错,还没有证明下一步获得了所需环境。保存旧 Dockerfile 和镜像标签,新镜像验收通过后再切换部署。


