"Device or resource busy" when i try move /etc/resolv.conf in ubuntu:18.04. How fix it?

d.j*_*.er 3 ubuntu docker resolv

I have a VPN client in my Docker container (ubuntu:18.04).

The client must do the following:

mv /etc/resolv.conf /etc/resolv.conf.orig
Run Code Online (Sandbox Code Playgroud)

Then the client should create new /etc/resolv.conf with their DNS servers. However, the move fails with an error:

mv: cannot move '/etc/resolv.conf' to '/etc/resolv.conf.orig': Device or resource busy
Run Code Online (Sandbox Code Playgroud)

Can this be fixed? Thank you advance.

P.S.: I can 't change the VPN client code.

Dan*_*ver 7

在 Docker 容器中,该/etc/resolv.conf文件不是普通的常规文件。Docker 以一种特殊的方式管理它:容器引擎将特定于容器的配置写入容器外部的文件中,并将其绑定挂载/etc/resolv.conf容器内部。

当您的 VPN 客户端运行时mv /etc/resolv.conf /etc/resolv.conf.orig,事情归结为rename(2)系统调用(或来自该系列的类似调用),并且,根据此系统调用的联机帮助页,EBUSY( Device or resource busy) 错误可能由几个原因返回,包括原始文件是挂载点:

EBUSY

重命名失败,因为 oldpath 或 newpath 是某个进程正在使用的目录(可能作为当前工作目录,或作为根目录,或者因为它已打开以供读取)或正在被系统使用(例如作为挂载点),而系统认为这是一个错误。(请注意,在这种情况下不需要返回 EBUSY——无论如何进行重命名并没有错——但如果系统不能以其他方式处理这种情况,则允许返回 EBUSY。)

虽然有评论说在这种情况下不能保证会产生错误,但它似乎总是为绑定安装目标触发(我想这可能发生在这里):

$ touch sourcefile destfile
$ sudo mount --bind sourcefile destfile
$ mv destfile anotherfile
mv: cannot move 'destfile' to 'anotherfile': Device or resource busy
Run Code Online (Sandbox Code Playgroud)

因此,类似地,您不能/etc/resolv.conf在容器内移动,因为它是一个绑定安装,并且没有直接的解决方案。

鉴于绑定挂载/etc/resolv.conf是读写挂载,而不是只读挂载,仍然可以覆盖此文件:

$ touch sourcefile destfile
$ sudo mount --bind sourcefile destfile
$ mv destfile anotherfile
mv: cannot move 'destfile' to 'anotherfile': Device or resource busy
Run Code Online (Sandbox Code Playgroud)

因此,可能的解决方法是尝试将此文件复制.orig备份,然后重写原始文件,而不是重命名原始文件,然后重新创建它。

不幸的是,这不符合您的限制 ( I can 't change the VPN client code.),所以我敢打赌您在这里不走运。


use*_*105 5

任何需要将文件移动到/etc/resolv.conf fails in docker container. The workaround is to rewrite the original file instead of moving or renaming a modified version onto it.

例如,在bash出现提示时使用以下命令:

(rc=$(sed 's/^\(nameserver 192\.168\.\)/# \1/' /etc/resolv.conf)
     echo "$rc" > /etc/resolv.conf)
Run Code Online (Sandbox Code Playgroud)

这可以通过重写来实现/etc/resolv.conf as follows:

  • 读取并修改当前内容/etc/resov.conf through the stream editor, sed
  • 此示例中的 sed 脚本用于注释掉以以下内容开头的行nameserver 192.168.
  • 将更新的内容保存在变量中,rc
  • /etc/resolv.conf用更新的内容覆盖原始文件"$rc"

命令列表放在括号中是为了在子 shell 中进行操作,以避免变量名污染当前 shell 的命名空间rc, just in case it happens to be in use.

请注意,此命令不需要sudo,因为它利用了容器内默认可用的超级用户权限。否则,使用

sudo sh -c 'rc=$(sed 's/^\(nameserver 192\.168\.\)/# \1/' /etc/resolv.conf); echo "$rc" > /etc/resolv.conf'
Run Code Online (Sandbox Code Playgroud)

作为Michael Johansen clarifies below.

注意sed -i (editing in-place) involves moving the updated file onto the original and will not work.

vi但是,如果容器中存在可视化编辑器,则可以直接编辑和/etc/resolv.conf保存原始文件vi,从而可以进行编辑和保存。vi

  • 请在您的答案中附上解释,以帮助读者理解其工作原理并解决问题。您可以单击答案底部的编辑按钮来添加解释。此外,您可能会发现阅读[如何回答](https://stackoverflow.com/help/how-to-answer)很有帮助 (2认同)