解析问题思路:
1. 首先,我们要先了解一个事实:docker 在使用 -v 来挂载 data volume 时,不论是在 host 端还是container 内部,
若是其文档或是目录不存在,则会自动建立它
2. 可以复现问题的命令下法,复现 read-only 的报错信息
$ docker run \
-v /dev:/dev:ro \
-v /root/termination-log:/dev/termination-log:rw \
-it centos /bin/bash
上述命令的逻辑是:
(1) 把 host 端的 /dev 对应到 container 内的 /dev, 权限为 read-only
(2) 把 host 端的 /root/termination-log 对应到 container 内的 /dev/termination-log, 权限为 read-write
(3) 以 -it 参数, centos 镜像, 执行 /bin/bash 的方式启动
3. 如果去掉 /dev:/dev:ro, 可以成功进入容器, 在容器中可以看到 /dev/termination-log 确实是 host 端上 /root/termination-log 的内容, (如果在容器中看文档内容遇到 Permission denied 的话,在 host 端以 setenforce 0 把 selinux 设为 permissive mode 即可)
$ docker run \
-v /root/termination-log:/dev/termination-log:rw \
-it centos /bin/bash
4. 如果是加上 /dev:/dev:rw, 也是可以成功进入容器, 在容器中也可以看到 /dev/termination-log 确实是 host 端上 /root/termination-log 的内容, 有趣的是... 退出容器后,会在 host 端出现 /dev/termination-log 这个空档案
docker run \
-v /dev:/dev:rw \
-v /root/termination-log:/dev/termination-log:rw \
-it centos /bin/bash
解析问题原因:
1. docker 挂载 data volume 时,若是其文档或是目录不存在,则会自动建立它
2. centos镜像本身起初并没有 /dev/termination-log 这个文档,所以会建立它
3. 由于 /dev:/dev:rw 的设定,所以可以在 /dev 下写东西,而容器内建立 /dev/termination-log 的动作会恰好让 host 端的 /dev/termination-log 被建立出来 (空档案)
4. 真正进入容器前,/root/termination-log:/dev/termination-log:rw 会做好对应,所以在容器中看到的是 host 端的 /root/termination-log;而 host 端的 /dev/termination-log 就这样凭空出现了
5. 如果在 host 端先建立 /dev/termination-log 文档,才执行下面有使用 /dev:/dev:ro 的命令,那么也是可以成功进入容器
$ docker run \
-v /dev:/dev:ro \
-v /root/termination-log:/dev/termination-log:rw \
-it centos /bin/bash
6. 从前面的实验与分析可以知道,因为host端已经有 /dev/termination-log,又因为 /dev:/dev 的关系,所以, docker 在容器内的 /dev 下看到了 termination-log 文档,故不会在容器内再自动创建 /dev/termination-log,自然就不会踩到 /dev:/dev:ro 的 read-only 限制而报错
综上:
将/dev以 ro 权限挂载进来,/dev/termination-log就会报read-only,本来应该是必现的错误,但因为osd pod以 rw 方式挂载了/dev导致host上生成了/dev/termination-log文件,所以其他以 ro 挂载/dev的pod才绕过了错误。
所以,应该不需要再调查是谁删除了出问题节点上的/dev/termination-log,因为这个文件本来不该存在host上
workaround :凡是以ro方式挂载/dev的容器,都要在yaml里加上 terminationMessagePath: /tmp/termination-log