返回目录

单个文件挂进容器,改了宿主机文件容器里却没变

场景

Docker Compose 里把一个配置文件单独挂进容器:

services:
  caddy:
    image: caddy:2-alpine
    volumes:
      - /etc/myapp/Caddyfile:/etc/caddy/Caddyfile:ro

在宿主机上用 sed -i 改了 Caddyfile,再让容器重新加载配置,发现什么都没变。进容器 cat /etc/caddy/Caddyfile 一看,还是改之前的内容。

原因

每个文件在磁盘上有一个编号,叫 inode。单个文件挂载时,容器绑定的是挂载那一刻那个编号对应的文件,跟路径名无关。

sed -i 和不少编辑器保存文件的做法是:先写一个新文件,再改名盖掉原来的。新文件的编号变了,宿主机上同一个路径已经指向新文件,容器里挂着的却还是旧的那个。

用 ls -i 能看到编号,改之前和改之后各看一次就清楚了:

$ ls -i Caddyfile
1312234 Caddyfile
$ sed -i 's/old/new/' Caddyfile
$ ls -i Caddyfile
1312240 Caddyfile    # 编号变了

几种解决办法

目录也有同样的问题

挂目录时,如果把整个目录用 mv 换掉(比如发布静态网页时“新目录改名替换旧目录”),容器里看到的还是旧目录,道理一样。

我现在的做法是挂上一级目录,比如把 /srv/site-root 挂进去,网页放在它下面的 site/ 里。发布时先把新文件解压到 site.new/,再改名替换 site/。挂载点本身没换,容器里能看到新内容,替换也是一瞬间完成。