Docker构建时如何从主机获取deb包用于镜像安装?
这个问题的核心是你没搞懂Docker构建上下文的机制——ADD/COPY命令根本不能直接访问主机任意路径的文件,它们只能读取构建上下文目录里的内容。
当你执行docker build时,Docker会把你指定的上下文目录(默认是当前工作目录)里的所有文件打包,发给后台的Docker守护进程,守护进程只能从这个打包的文件里拿东西。你写的ADD /opt/...,Docker会误以为你要从构建上下文的根目录下找opt文件夹,而不是主机的/opt,自然找不到文件。
下面给你三种解决办法,按需选择:
1. 最直接:把deb包挪到Dockerfile所在目录
把/opt/jdk-14.0.2_linux-x64_bin.deb复制到你的Dockerfile所在的文件夹,然后修改Dockerfile里的ADD命令:
RUN mkdir /install_files ADD jdk-14.0.2_linux-x64_bin.deb /install_files/ RUN dpkg -i /install_files/jdk-14.0.2_linux-x64_bin.deb
之后正常执行docker build .就行,这时候Docker能在上下文里找到这个包。
2. 指定构建上下文为/opt(不想挪文件的话)
如果不想移动文件,可以直接把构建上下文设为/opt,这样Docker会把/opt下的所有文件作为上下文发给守护进程。执行build命令时这么写:
docker build -t your-image-name /opt
同时Dockerfile里的ADD命令改成:
RUN mkdir /install_files ADD jdk-14.0.2_linux-x64_bin.deb /install_files/ RUN dpkg -i /install_files/jdk-14.0.2_linux-x64_bin.deb
不过要注意,这种方式会把/opt下所有文件都打包,要是/opt里有大文件或者敏感内容,会拖慢构建速度,还有安全风险,谨慎使用。
3. 用BuildKit挂载(最佳实践,适合大文件)
Docker BuildKit支持构建时直接挂载主机文件,不用把文件加入上下文。先启用BuildKit:
export DOCKER_BUILDKIT=1
然后修改Dockerfile,用--mount参数挂载主机的deb包:
RUN mkdir /install_files RUN --mount=type=bind,source=/opt/jdk-14.0.2_linux-x64_bin.deb,target=/install_files/jdk-14.0.2_linux-x64_bin.deb \ dpkg -i /install_files/jdk-14.0.2_linux-x64_bin.deb
之后正常执行docker build .就可以了。这种方式不会把deb包打包进上下文,省时间省资源,也不用移动文件,特别适合大体积的安装包。
内容的提问来源于stack exchange,提问作者Gauthier

