记录一次docker文件挂载困扰了我4个小时的问题。
Dynamic Grid是selenium-grid 4.0最新添加的功能。它能够按需启动 Docker 容器,这意味着它会在后台为每个新的会话请求启动一个 Docker 容器,在那里执行测试,当测试完成时,容器会被丢弃。
在部署selenium-grid镜像时需要将一个配置文件挂载到服务启动容器中,即为下面的config.toml

version: "3"
services:
  node-docker:
    image: selenium/node-docker:4.0.0
    volumes:
      - ./assets:/opt/selenium/assets
      - ./config.toml:/opt/bin/config.toml

在windows下的docker-compose中这样部署是没问题的,但在linux上,因为docker版本问题没有docker-compose只能通过docker原生命令去启动容器。于是我的命令改成了这样:

docker run -d \
-v ./assets:/opt/selenium/assets \
-v ./config.toml:/opt/bin/config.toml \
selenium/node-docker:4.0.0

看似没有问题,把命令执行一下:

docker: Error response from daemon: create ./assets: "./assets" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
See 'docker run --help'.

报了错误,意思是不可以使用.作为路径的开头,必须使用绝对路径。于是做了更改:

docker run -d \
-v $pwd/assets:/opt/selenium/assets \
-v $pwd/config.toml:/opt/bin/config.toml \
selenium/node-docker:4.0.0

重新执行:

docker 只有mondb一直重启 docker mounted from_容器


这次镜像成功构造了,但在启动镜像时仍旧报错:提示没有找到这个配置文件。很奇怪,我查了一下其他同学的说法:

-v mount 文件(或文件夹)时,docker 记录的是该文件的 inode,并用 inode 追踪。当用 vim 编辑了文件后,这个文件的 inode 就变了,也就是说这个 default.conf 文件已经不是运行 docker run 时的那个 default.conf 文件了,容器中自然也就没了新的改动。 同时该 issue 的 opener 使用的是 sed -i 修改,也会使 inode 发生变化,sed -i 的机制是创建一个新的临时文件,修改完后在重命名。对此,官方的建议是挂载文件夹,而不是文件。

根据他的说法我选择先从镜像中cp下来/opt/bin/config.toml文件夹中的所有文件,然后再把整个/opt/bin的文件挂载到镜像中。
执行如下命令cp文件到本地:

docker cp node-docker:/opt/bin ./

然后再执行一下代码:

docker run -d \
-v $pwd/assets:/opt/selenium/assets \
-v $pwd/bin:/opt/bin \
selenium/node-docker:4.0.0

docker 只有mondb一直重启 docker mounted from_容器_02


这次说找不到/opt/bin/entry_point.sh文件,这个文件应该在bin下,我在本地看了一下bin的目录并没有缺少这个文件啊。

docker 只有mondb一直重启 docker mounted from_linux_03


在百度google查了好久挂载文件的问题都没有遇到类似的状况,我想到之前打包镜像时有一个命令叫docker inspect,之前是用来检查镜像是否commit成功而不是使用的原始的镜像。是在没办法我试了一下:

docker inspect node-docker

果然好用,在里面有个叫mount也就是挂载情况的对应json字段:

docker 只有mondb一直重启 docker mounted from_容器_04


可以发现挂载文件的情况是把根目录下的bin挂载到了镜像中,可我们回顾一下我们的命令没错啊,使用的是$pwd去动态挂载,挂载的结果上看是挂载失败了,这个$pwd命令整个都没有输出。在cmd里试一下:

docker 只有mondb一直重启 docker mounted from_docker 只有mondb一直重启_05


空空如也啥都没有,心态炸了。回想起前天学的linux shell命令处理,是需要在$pwd加上()的,这样才视为pwd是个命令,然后把pwd带回的路径返回输出。而我这样直接去使用$pwdlinux当这个pwd为一个变量,从本地去找这个变量,我们没有定义他当然就空空如也呀。于是我按照docker-compose的格式重新挂载文件试一下好不好用:

docker 只有mondb一直重启 docker mounted from_运维_06


成功了!

总结

linux中想使用相对路径挂载文件,可以使用$(pwd)命令代替./docker inspect命令可以检查当前镜像/容器的状态

心得

其实最终如何解决是很重要,更重要的是这个过程中掌握了shell命令在实际开发场景的具体应用以及docker的一些细节方法,通过这些方法,相信可以解决以后遇见的绝大部分相似的问题,再也不会让人头秃了!