如何让Docker在容器创建时执行挂载卷内的命令?
首先,你遇到的核心问题不是挂载顺序——Docker确实会在启动容器进程之前完成卷挂载。真正的原因是:你在主机上编译的hello-docker-mount是动态链接的,它依赖主机的GNU libc,但Busybox镜像使用的是轻量级的Musl libc,两者不兼容,所以系统找不到依赖的库,才会抛出"no such file or directory"错误(这个错误提示有点误导人,实际是找不到动态链接库,而非程序本身)。
你可以在主机上用ldd hello-docker-mount查看程序依赖,再对比Busybox容器里的libc路径,就能验证这个差异。
接下来针对你的需求,提供几种可行方案:
方案1:静态编译你的C程序
如果可以重新编译程序,加上静态编译参数,让程序把所有依赖库打包进去,这样就能在任何容器里独立运行:
gcc -static hello-docker-mount.c -o hello-docker-mount
编译完成后,再用你原来的docker run命令就能直接执行这个程序,因为它不再依赖系统的libc。
方案2:使用与主机libc兼容的镜像
如果你不想重新编译程序,可以换用和主机相同libc的镜像(比如Ubuntu、Debian这类基于GNU libc的镜像),而非Busybox。示例命令:
docker run -it --name foo --rm -v /home/flash:/home/flash -w /home/flash ubuntu:latest ./hello-docker-mount
这样动态链接的程序就能找到对应的依赖库,正常运行。
方案3:先启动常驻容器,再执行挂载的程序
如果你的核心需求是让容器持续运行以便后续用docker exec交互,而非必须在启动时就运行挂载的程序,那可以先启动一个轻量级的常驻进程(比如tail -f /dev/null或sleep infinity),之后再进入容器执行你的程序:
# 启动后台运行的容器,用tail保持进程常驻 docker run -d --name foo --rm -v /home/flash:/home/flash -w /home/flash busybox tail -f /dev/null # 后续用exec进入容器执行程序 docker exec -it foo ./hello-docker-mount
这种方式不需要修改镜像,也不需要重新编译程序,完全满足你后续交互的需求,而且几乎所有镜像都支持这类简单的常驻命令。
内容的提问来源于stack exchange,提问作者jnewman

