Docker构建随机报错:ADD多源文件时目标需为目录且以/结尾
根本原因
报错和ADD entrypoint.sh配置完全无关,你之前的修改方向错误,问题核心出在jar包拷贝的ADD逻辑上:
- Docker的
ADD/COPY指令有明确校验规则:如果源路径匹配到2个及以上文件,目标路径必须是目录且以/结尾,否则直接抛出When using ADD with more than one source file, the destination must be a directory and end with a /错误。 - 你定义的
ARG JAR_FILE='**/*.jar'是递归通配规则,会扫描整个Docker构建上下文下所有后缀为.jar的文件,匹配到的文件数量是随机的:- 当构建上下文干净时(如新分配的云托管代理、工作目录刚完成清理),最终构建生成的业务jar只有1个,ADD指令执行符合单源规则,构建成功。
- 当构建上下文存在残留jar时(如自托管代理未清理的历史构建产物、多模块构建时其他模块输出的jar、构建流程临时生成的附属jar包),通配符会匹配到≥2个jar文件,此时你写的目标路径是单文件形式的
content_mgmt_service.jar(未以/结尾标记为目录),直接触发报错。
单文件作为ADD源时,目标路径写.还是./都符合规则,因此修改entrypoint.sh的目标路径完全无法解决问题。
修复方案
核心思路是避免模糊通配带来的多文件匹配问题,按优先级选择以下方案即可:
- 首选方案:固定jar包路径,弃用递归通配
常规Java应用构建后jar包输出路径是固定的(Maven为target/目录,Gradle为build/libs/目录),直接指定明确路径,同时配合.dockerignore过滤无关文件,避免多余文件进入构建上下文:
修改后的Dockerfile示例:
同时在项目根目录新建FROM amazonlinux:2.0.20181114 RUN yum install -y java-1.8.0-openjdk-headless # 直接匹配固定构建目录下的jar,不使用**递归扫描 COPY target/*.jar content_mgmt_service.jar COPY entrypoint.sh . RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD ["java", "-jar", "/content_mgmt_service.jar"].dockerignore文件,排除无关目录:.git .idea *.md **/target/* !**/target/*-exec.jar - 备选方案:多源场景强制使用目录目标
如果必须使用通配匹配jar,将ADD目标改为目录格式,匹配到多个文件时不会触发校验,后续再通过重命名拿到需要的业务jar:FROM amazonlinux:2.0.20181114 RUN yum install -y java-1.8.0-openjdk-headless ARG JAR_FILE='**/*.jar' # 多源场景目标必须加/标记为目录 ADD ${JAR_FILE} /tmp/jars/ # 过滤出业务可执行jar移动到固定路径,清理临时目录 RUN mv /tmp/jars/*-exec.jar /content_mgmt_service.jar && rm -rf /tmp/jars ADD entrypoint.sh . RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD ["java", "-jar", "/content_mgmt_service.jar"] - 流水线侧兜底配置
- Azure DevOps流水线构建Job开启
clean: true配置,每次构建前强制清空代理工作目录,避免历史产物残留 - Java构建步骤固定执行clean生命周期,比如Maven使用
mvn clean package命令,不要跳过clean阶段直接打包 - 排查阶段可临时给docker build命令加
--no-cache参数,排除构建缓存带来的异常影响
- Azure DevOps流水线构建Job开启
内容的提问来源于stack exchange,提问作者Dilu
相关产品推荐
相关产品推荐

