记一次 docker 文件挂载宿主机修改未同步容器问题

288 阅读5分钟

最近在使用 docker 挂载文件时,发现一个问题,在宿主机更新挂载文件,容器内并未同步。但是重启容器后,容器内又更新了文件。

容器举个例子

以下以 nginx 容器举个例子

version: '3'
services:
  nginx:
    image: nginx:latest
    container_name: my-nginx
    volumes:
      - /root/docker-compose/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - /root/docker-compose/nginx/index.html:/usr/share/nginx/html/index.html
    ports:
      - "80:80"
      - "443:443"

输出容器内 nginx index 页面内容

docker exec my-nginx cat /usr/share/nginx/html/index.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

修改宿主机上 index 页面内容

vi index.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Hello World!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

再次查看容器内 index 页面内容,发现内容并未同步更新。

docker exec my-nginx cat /usr/share/nginx/html/index.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

原因分析

Docker 挂载文件时,挂载的是文件的 inode,而不是路径。当你用 Vim 编辑并保存文件时,它会创建一个新文件并替换原文件,从而改变 inode。由于 inode 改变,容器内的文件没有更新。重启容器时,会挂载新的 inode。

接下来验证一下,首先先重启下容器,让原本的更新生效。

docker exec my-nginx cat /usr/share/nginx/html/index.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Hello World!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

接下来查看一下宿主机 index.html 的 inode,可以看到 inode 值 = 5349362

stat index.html

  文件:index.html
  大小:298           块:8          IO 块:4096   普通文件
设备:略    Inode:5349362     硬链接:1
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
最近访问:2024-11-17 00:17:02.430672510 +0800
最近更改:2024-11-17 00:16:59.236639833 +0800
最近改动:2024-11-17 00:16:59.238639854 +0800
创建时间:-

再看一下容器里 index.html 的 inode,可以看到 inode 值和宿主机是一样的。

docker exec my-nginx stat /usr/share/nginx/html/index.html

  File: /usr/share/nginx/html/index.html
  Size: 298           Blocks: 8          IO Block: 4096   regular file
Device: 252,1    Inode: 5349362     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2024-11-16 16:17:02.430672510 +0000
Modify: 2024-11-16 16:16:59.236639833 +0000
Change: 2024-11-16 16:16:59.238639854 +0000
 Birth: 2024-11-16 16:16:59.236639833 +0000

接下来通过 vi 修改宿主机 index.html 文件

vi index.html

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Hello World!!!!!!!</h1>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

之后再看看宿主机 index.html 对应 inode,发现宿主机的 inode 值已经发生变化。

stat index.html

  文件:index.html
  大小:304           块:8          IO 块:4096   普通文件
设备:略    Inode:4878009     硬链接:1
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
最近访问:2024-11-17 00:40:32.826158500 +0800
最近更改:2024-11-17 00:40:24.556072681 +0800
最近改动:2024-11-17 00:40:24.558072702 +0800
创建时间:-

再看看容器内 index.html 对应 inode 值,发现容器内 inode 值还是旧值。因此,宿主机更新文件内容并未同步到容器内。

docker exec my-nginx stat /usr/share/nginx/html/index.html
  
  File: /usr/share/nginx/html/index.html
  Size: 298           Blocks: 8          IO Block: 4096   regular file
Device: 252,1    Inode: 5349362     Links: 0
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2024-11-16 16:17:02.430672510 +0000
Modify: 2024-11-16 16:16:59.236639833 +0000
Change: 2024-11-16 16:40:24.558072702 +0000
 Birth: 2024-11-16 16:16:59.236639833 +0000

解决方案

  1. 调整宿主机文件权限为 664,网上有些文章写着是需要将文件权限改成 777,亲测,只需要将组权限改成读写既可以,接下来在测试一下。

    chmod 664 index.html
    
    vi index.html
    
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
    </style>
    </head>
    <body>
    <h1>Hello World!!!</h1>
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    
    stat index.html
    
      文件:index.html
      大小:300           块:8          IO 块:4096   普通文件
    设备:略    Inode:4878009     硬链接:1
    权限:(0664/-rw-rw-r--)  Uid:(    0/    root)   Gid:(    0/    root)
    最近访问:2024-11-17 00:46:38.674904905 +0800
    最近更改:2024-11-17 00:47:00.742129147 +0800
    最近改动:2024-11-17 00:47:00.743129157 +0800
    创建时间:-
    

    可以看见,将文件权限设置成 664 后,可以避免 vi 编辑器更新导致 inode 变更问题。

  2. 使用挂载目录,挂载目录即使文件 inode 发生变更,容器内也能同步新的 inode