GitHub Action构建Docker镜像时,文件执行权限为何未保留?
出现这个问题的核心原因主要和Git的权限跟踪机制以及Docker构建的权限继承逻辑有关:
1. Git默认不跟踪文件的执行权限
Git默认只会记录文件的内容和基础元数据,不会自动跟踪文件的执行权限(即x位)。哪怕你在本地给entrypoint.sh添加了执行权限,如果没有通过以下命令将权限变更提交到Git仓库:
git update-index --chmod=+x docker/entrypoint.sh
那么当GitHub Action的runner拉取代码时,checkout出来的entrypoint.sh是没有执行权限的。你在Action中手动执行chmod +x虽然在runner的文件系统中生效了,但Docker构建时可能因为缓存复用或上下文处理的问题,导致COPY到镜像中的文件仍然保留了Git仓库里的原始权限(无执行权)。
2. Docker COPY指令的缓存机制
Docker构建时会复用之前的镜像层缓存,如果之前构建过相同的上下文内容(比如entrypoint.sh的内容没变化),COPY指令会直接复用旧的缓存层,即使你在runner中临时修改了文件权限,也不会更新到镜像里。
解决方法
有几种可靠的方式可以解决这个问题:
永久解决:让Git跟踪执行权限
在本地执行以下命令,将entrypoint.sh的执行权限提交到Git仓库:git update-index --chmod=+x docker/entrypoint.sh git commit -m "Add execute permission to entrypoint.sh" git push这样后续所有拉取代码的环境(包括GitHub Action runner)都会自动获得带执行权限的文件,无需额外操作。
Dockerfile中显式设置权限(你当前的方案)
保留RUN chmod +x /entrypoint.sh这条指令,这是最稳妥的方式——不管构建上下文里的文件权限如何,都能确保镜像内的文件拥有执行权限。使用COPY的
--chmod参数(更高效)
Docker 17.09及以上版本支持在COPY指令中直接设置权限,这样可以减少一层镜像层,提升构建效率:COPY --chmod=0755 entrypoint.sh /
内容的提问来源于stack exchange,提问作者theateist

