Docker镜像创建容器时代码是否复制?容器文件机制解析
Docker镜像分层与容器文件系统原理解答
你遇到的修改server.js后Express服务无响应的问题,和Docker存储机制无关,是Node.js的运行特性导致的:Node进程启动时会把所有加载的代码读到内存中运行,你后续修改磁盘上的server.js文件不会触发热更新,正在运行的服务用的还是启动时加载的旧代码,自然看不到变化。只要重启容器内的Node进程(或者直接重启容器),就能看到修改后的内容。
下面解释你关心的容器创建流程和文件访问逻辑:
核心机制:联合文件系统与写时复制
Docker镜像从设计上就是只读的分层结构,你写的Dockerfile里每一条指令(FROM/COPY/RUN等)构建后都会生成一个独立的只读层,多个层堆叠在一起,通过联合文件系统对外呈现为一个统一的文件系统目录。
针对你提出的两个疑问的明确解答:
- 容器复用镜像时的文件修改处理逻辑
容器启动时不会复制整个镜像的内容,只会在所有只读镜像层的最上方,添加一个当前容器专属的空可写层。容器运行期间所有的文件新增、修改、删除操作,都只会作用在这个独立的可写层上,完全不会改动底下的只读镜像层,这也是同镜像启动的多个容器完全隔离、互不影响的核心原因。
具体操作规则非常直白:- 读文件时:如果可写层有目标文件就直接读;如果没有,就从上往下逐层查找镜像层,找到后直接读取镜像层内的文件,不需要做任何复制操作。
- 改文件时:如果要修改的文件只存在于下层的只读镜像层,Docker会触发写时复制(Copy-on-Write):先把这个目标文件完整复制到最上层的可写层,之后所有对这个文件的修改都只作用在可写层的副本上,下层镜像的原文件不会有任何改动。后续再读取这个文件时,上层的副本会屏蔽下层的原文件,你读到的就是修改后的版本。
- 删文件时:如果要删除的文件在只读镜像层,Docker不会真的删除镜像里的原文件,只会在可写层给这个文件打一个删除标记,后续读取时检测到这个标记就会认为文件不存在,实现删除效果。
- 镜像内容是否会全量复制到容器
默认不会。只有当你主动修改某个镜像内的文件时,才会把这单个文件复制到容器的可写层,其余所有未修改的文件,都直接复用镜像层里的内容,不会额外占用磁盘空间。这也是Docker比传统虚拟机轻量得多的核心原因:就算你用同一个镜像启动100个容器,也只需要存一份镜像的内容,额外占用的只是每个容器可写层里改动部分的存储空间,不会出现多份重复的镜像文件副本。
从镜像创建容器的完整流程
- Docker先检查本地是否存在目标镜像,缺失的话就从配置的镜像仓库拉取,拉取时按层校验,本地已有的层不会重复下载。
- 通过联合文件系统(Linux环境下默认用
overlay2驱动)把所有只读镜像层按构建顺序堆叠挂载,形成一个统一的只读文件系统视图。 - 在只读层的最顶部初始化当前容器专属的空可写层,同时为容器分配独立的进程命名空间、网络命名空间、用户命名空间等隔离资源,实现和宿主机、其他容器的隔离。
- 按照镜像中配置的
WORKDIR、环境变量等参数初始化运行环境,最后执行CMD/ENTRYPOINT指定的启动命令,容器进入运行状态。
容器运行时访问文件的过程对进程是完全透明的:进程感知不到底下的分层结构,看到的就是一个普通的完整文件系统,不管是存在于镜像层的node可执行文件、node_modules依赖包,还是你后来在可写层修改过的server.js,呈现出来的效果和在普通操作系统上访问文件没有区别。
内容的提问来源于stack exchange,提问作者Krishna Vamsi
相关产品推荐
相关产品推荐

