Device or resource busy

Dockerでprom/blackbox-exporter - Docker Image をベースにしたイメージを作ろうとしたときに/etc/resolv.confを上書きしようとしたらDevice or resource busyというエラーが出て上書きできなかった。

FROM prom/blackbox-exporter:v0.24.0

COPY entrypoint.sh /app/entrypoint.sh
COPY resolv.conf /app/resolv.conf

ENTRYPOINT ["/app/entrypoint.sh"]
cp /app/resolv.conf /etc/resolv.conf

...

Dockerfile/app/resolv.confに置いたファイルを/etc/resolv.confにコピーしようとしている。
コンテナを立ち上げるとDockerのログに以下のメッセージが出てコピーに失敗する。

cp: can't create '/etc/resolv.conf': File exists

sed -i も失敗する

直接書き換える方法としてsed -iを使ってみたが、これも失敗した。

sed -i 's/^nameserver/#nameserver/' /etc/resolv.conf
echo "nameserver 8.8.8.8" >> /etc/resolv.conf

...

以下のエラーメッセージが出た。

sed: can't move '/etc/resolv.confxsK8Gs' to '/etc/resolv.conf': Device or resource busy

sed -i一時ファイルに書き込んでから元のファイルにリネームするため、/etc/resolv.confを上書きしようとしてcpのときと同様のエラーが発生する。

/etc/resolv.confを調べる

dfコマンドを確認すると/etc/resolv.confがマウントされているのがわかる。

$ df
...
/dev/vda1             61202244  11577640  46483280  20% /etc/resolv.conf
/dev/vda1             61202244  11577640  46483280  20% /etc/hostname
/dev/vda1             61202244  11577640  46483280  20% /etc/hosts

hostnamehostsも同じデバイスにマウントされている。
これが原因で/etc/resolv.confを上書きできないと考えられる。

リダイレクトによる変更は成功する

リダイレクトによる変更は成功する。

$ echo "nameserver 8.8.8.8" >> /etc/resolv.conf
$ tail -1 /etc/resolv.conf
nameserver 8.8.8.8

>>とすれば追記となるが、>とすれば上書きとなる。

無理やりの解決策

リダイレクトでは成功するので以下のように書き換える。

conf=$(sed "s/^nameserver/#nameserver/" /etc/resolv.conf)
echo "$conf" > /etc/resolv.conf
echo "nameserver 8.8.8.8" >> /etc/resolv.conf

...

sedは一度結果を変数に格納してからリダイレクトで上書きする。
追記は>>で行う。

これでコンテナ起動時に実行され、/etc/resolv.confは以下のように修正される。

$ cat /etc/resolv.conf
#nameserver 127.0.0.11
options ndots:0
nameserver 8.8.8.8