錯誤現象
在docker容器中想要修改/etc/resolv.conf
中的namesever,使用sed命令進行執行時遇到錯誤:
/ # sed -i 's/192.168.1.1/192.168.1.254/g' /etc/resolv.conf
sed: can't move '/etc/resolv.conf73UqmG' to '/etc/resolv.conf': Device or resource busy
但是可以通過vi/vim直接修改這個文件/etc/resolv.conf
這個文件的內容。
問題原因
sed命令的實質並不是修改文件,而是產生一個新的文件替換原有的文件。這里我們做了一個實驗。
我先創建了一個test.txt
的文件,文件內容是123
。然后我使用sed
命令對文件內容進行了替換。再次查看test.txt
。
/ # stat test.txt
File: test.txt
Size: 4 Blocks: 8 IO Block: 4096 regular file
Device: fd28h/64808d Inode: 265 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-07-04 06:28:35.000000000
Modify: 2017-07-04 06:28:17.000000000
Change: 2017-07-04 06:29:03.000000000
/ # cat test.txt
123
/ # sed -i 's/123/321/g' test.txt
/ # stat test.txt
File: test.txt
Size: 4 Blocks: 8 IO Block: 4096 regular file
Device: fd28h/64808d Inode: 266 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-07-04 06:29:31.000000000
Modify: 2017-07-04 06:29:31.000000000
Change: 2017-07-04 06:29:31.000000000
/ # cat test.txt
321
可以看到文件內容被正確修改了,但是同時,文件的inode也修改了。說明了實質上是新生成的文件替換了原有的文件。但是vim/vi是在原文件基礎上修改的,所以inode沒有變化。
在docker中,/etc/resolv.conf
是通過掛載入容器的。所以當你想去刪除這個掛載文件,也就是掛載點時,自然就會報Device or resource busy
。
這個跟是不是特權privilege沒有關系。即使是privilege的容器,也會有這個問題。
/ # rm /etc/resolv.conf
rm: can't remove '/etc/resolv.conf': Device or resource busy
其實不僅僅/etc/resolv.conf
,還有/etc/hostname
,/etc/hosts
等文件都是通過掛載方式掛載到容器中來的。所以想要用sed對他們進行修改,都會遇到這樣的問題。我們可以通過df -h
查看容器內的掛載情況。
/ # df -h
Filesystem Size Used Available Use% Mounted on
/dev/mapper/docker-253:2-807144231-37acfcd86387ddcbc52ef8dac69d919283fc5d9d8ab5f55fd23d1c782e3b1c70
10.0G 33.8M 10.0G 0% /
tmpfs 15.4G 0 15.4G 0% /dev
tmpfs 15.4G 0 15.4G 0% /sys/fs/cgroup
/dev/mapper/centos-home
212.1G 181.8G 30.3G 86% /run/secrets
/dev/mapper/centos-home
212.1G 181.8G 30.3G 86% /dev/termination-log
/dev/mapper/centos-home
212.1G 181.8G 30.3G 86% /etc/resolv.conf
/dev/mapper/centos-home
212.1G 181.8G 30.3G 86% /etc/hostname
/dev/mapper/centos-home
212.1G 181.8G 30.3G 86% /etc/hosts
shm 64.0M 0 64.0M 0% /dev/shm
tmpfs 15.4G 0 15.4G 0% /proc/kcore
tmpfs 15.4G 0 15.4G 0% /proc/timer_stats
如何解決
使用vi固然可以,但是對於批量操作就不是很合適了。可以通過sed和echo的組合命令echo "$(sed 's/192.168.1.1/192.168.1.254/g' /etc/resolv.conf)" > /etc/resolv.conf
即可實現替換。
/ # cat /etc/resolv.conf
search default.svc.games.local svc.games.local games.local
nameserver 192.168.1.1
options ndots:5
/ # echo "$(sed 's/192.168.1.1/192.168.1.254/g' /etc/resolv.conf)" > /etc/resolv.conf
/ # cat /etc/resolv.conf
search default.svc.games.local svc.games.local games.local
nameserver 192.168.1.254
options ndots:5
這里如果使用
sed 's/192.168.1.1/192.168.1.254/g' /etc/resolv.conf > /etc/resolv.conf
是無效的。最終會導致/etc/resolv.conf
內容為空。