Docker Compose构建失败却返回0退出码,Makefile仍执行touch命令
问题
在Makefile的docker.build目标中定义了如下命令:
docker.build: BUILDKIT_PROGRESS=plain docker compose build && touch docker.build || rm -f docker.build
当Dockerfile的构建阶段(比如gateway-builder阶段执行RUN exit 1这类失败命令)出现错误时,控制台明明显示构建失败,但Make却执行了touch docker.build而非rm -f docker.build。使用Docker 23.0.5,尝试过Make 4.3和4.4.1版本,询问该问题的原因。
原因分析
这个问题由两方面因素共同导致:
- Shell逻辑运算符的执行规则:你写的
A && B || C命令等价于(A && B) || C,只有当A(即docker compose build)执行失败(退出码非0)时,才会触发||后的rm操作;如果A返回退出码0,就会执行touch操作。 - Docker 23.0.5的BuildKit退出码问题:在该版本中,当使用BuildKit进行多阶段构建时,若某个中间构建阶段(如
gateway-builder)执行失败,docker compose build会在控制台输出失败日志,但错误地返回退出码0。这让Shell误以为A执行成功,因此执行了touch docker.build,而非预期的删除操作。
你可以直接在终端执行BUILDKIT_PROGRESS=plain docker compose build; echo $?验证:如果构建失败但输出的退出码是0,就可以确认是这个问题。
解决方法
改用if-else逻辑代替&&/||的组合,直接判断命令的退出码,确保逻辑不受异常退出码影响:
docker.build: BUILDKIT_PROGRESS=plain docker compose build; \ if [ $$? -eq 0 ]; then \ touch docker.build; \ else \ rm -f docker.build; \ fi
内容的提问来源于stack exchange,提问作者user3534080
相关产品推荐
相关产品推荐

