現象
CentOSなDockerコンテナであらかじめ作っておいたユーザアカウントのユーザIDをusermodコマンドで変更しようとすると次のようなエラーに遭遇しました。
[root@e0f1f3c6fe33 /]# id testuser
uid=1000(testuser) gid=100(users) groups=100(users)
[root@e0f1f3c6fe33 /]# usermod -u 1001 testuser
failed to change mailbox owner: Read-only file system
念のためメール保存ファイルのユーザIDを確認するとusermod実行前の1000のまま変わっていません。
[root@e0f1f3c6fe33 /]# id testuser
uid=1001(testuser) gid=100(users) groups=100(users)
[root@e0f1f3c6fe33 /]# ls -lnd /var/spool/mail{,/testuser}
drwxrwxr-x 2 0 12 4096 Aug 17 08:00 /var/spool/mail
-rw-rw---- 1 1000 12 0 Aug 17 08:00 /var/spool/mail/testuser
このファイルのパーミッションは660だし、chownコマンドだとエラーなくユーザIDを変えられること、そもそもこのusermodコマンド実行時にホームディレクトリのユーザIDは問題なく変更が完了していることからファイルシステムが読み込み専用というわけではないはずです。
調査
straceコマンドで追っかけてみました。
open("/var/spool/mail/testuser", O_RDONLY|O_NONBLOCK) = 4
fstat(4, {st_mode=S_IFREG|0660, st_size=0, ...}) = 0
fchown(4, 1001, 4294967295) = -1 EROFS (Read-only file system)
O_RDONLY|O_NONBLOCK
でオープンした対象ユーザのメール保存ファイルをfchown()
を使ってユーザID変更しようとしたところでEROFS
くらってることがわかります。この問題はDockerのストレージドライバにOverlayFSを使っているときのみ起こります。AuFS/DeviceMapper/Btrfs/ZFSでは発生しません。
OverlayFSのドキュメントを見てみるとまさにこの問題に関する記述がありました。
https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
On a file opened with O_RDONLY fchmod(2), fchown(2), futimesat(2) and
fsetxattr(2) will fail with EROFS.
どうやら既知の問題のようです。usermod.cのソースコード をみると、たしかに1724行目でO_RDONLY
でオープンしたfdを1745行目でfchown()
してますね。ちなみにホームディレクトリのユーザID書き換えではlchown()
が使われていました。
対応策
このエラーにおける対策としては、コンテナを実行中、もしくはDockerイメージを作る際に次のような処置が考えられます。
- 1. 事前にメール保存ファイルをカレントレイヤにcopy-upしておく
- touch /var/spool/mail/<USERNAME> で下層レイヤからcopy-upしておいてからusermodコマンドを実行する
- 2. メール保存ファイルが不要ならば消してしまう
- rm /var/spool/mail/<USERNAME> して消してからusermodコマンドを実行する
- 3. そもそもメール保存ファイルを作らない
- useraddコマンドでユーザを作るときに-rオプションを使うなり /etc/default/useradd ファイルにCREATE_MAIL_SPOOL=noを記述するなりしてメール保存ファイルを作らないようにする。ちなみにDebian系ディストリは CREATE_MAIL_SPOOL=no がデフォルト。
- 4. エラーを無視する
- メール保存ファイルの所有者権限がなくとも動作に支障なければ無視するのもありですね。