Dockerfile内でchownが効かない場合に疑うべき環境について
該当する方は誰もいない可能性がありますが、もし同じことで困っている人が今後現れたときの助けになればと思って、失敗談を残しておきます。
何が起こったか
Dockerfile 内で任意のディレクトリやファイルに対してchownコマンドでコンテナ内に存在するどのユーザーの権限にもならない。
RUN useradd app && mkdir /app && chown app /app
のような記述でイメージのビルドをすると、エラーにならずビルドは正常終了しているのに、コンテナ内のオーナーは root のままになってしまう。
環境
$ docker -v
Docker version 20.10.5, build 55c4c88
$ docker-compose -v
docker-compose version 1.27.4, build 40524192
$ uname -a
Linux 5.4.0-66-generic #74~18.04.2-Ubuntu SMP Fri Feb 5 11:17:31 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
これ以外の重要な情報として、
「Dockerのデータディレクトリ (data-root) を、OSが起動しているディスクとは 別の マウントしたディスクに指定している」
ことが前提となります。
「data-rootを別のディスクに指定している」とは
ここでは仮に以下のような構成だとします。
- SSDのディスクが2つ存在して、OSから認識されている。
- ディスクsdaにOSがインストールされている
- ディスクsdbが /docker にマウントされている
dockerの設定
/etc/docker/daemon.json の内容は以下のようになっています。
{
"data-root": "/docker",
"userns-remap": "1000:1000"
}
data-root
$ sudo ls -al /docker/
drwx-----x 5 root root 4096 3月 11 23:12 .
drwxr-xr-x 72 root root 4096 3月 11 18:12 ..
drwx-----x 13 root root 4096 3月 11 23:12 1000.1000
Dockerfile の記述
RUN useradd -m app
RUN mkdir -p /app && chown -R app /app
RUN apt-get update -y \
&& apt-get install -y libssl-dev pkg-config locales \
&& locale-gen ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG="ja_JP.UTF-8" \
LANGUAGE="ja_JP:ja" \
LC_ALL="ja_JP.UTF-8"
RUN apt-get update \
&& apt-get install -y -q \
ca-certificates \
locales \
git \
wget \
default-libmysqlclient-dev \
curl \
gnupg \
apt-transport-https\
libssl-dev \
pkg-config \
python3 \
python3-pip \
&& echo "ja_JP UTF-8" > /etc/locale.gen \
&& locale-gen
USER app
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install --upgrade pip && pip3 install -r requirements.txt
ビルドすると以下のようなエラーが出力されます。
Step 14/22 : COPY requirements.txt requirements.txt
---> a78fdd6ebc1b
Step 15/22 : RUN pip3 install --upgrade pip && pip3 install -r requirements.txt
---> Running in ad84b43d16f3
The directory '/home/app/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/app/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting pip
Downloading https://files.pythonhosted.org/packages/fe/ef/60d7ba03b5c442309ef42e7d69959f73aacccd0d86008362a681c4698e83/pip-21.0.1-py3-none-any.whl (1.5MB)
Installing collected packages: pip
Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/home/app/.local'
Check the permissions.
/home/app 以下のパーミッションはどうなってるんだ、となるので pip3 installの上の行に
RUN ls -al /home/app
を追記してビルドしてみると
Step 14/23 : RUN ls -al /home/app
---> Running in e20f0febf9a8
total 20
drwxr-xr-x 2 root root 4096 3月 11 14:50 .
drwxr-xr-x 1 root root 4096 3月 11 14:50 ..
-rw-r--r-- 1 root root 220 4月 18 2019 .bash_logout
-rw-r--r-- 1 root root 3526 4月 18 2019 .bashrc
-rw-r--r-- 1 root root 807 4月 18 2019 .profile
root になってますね。
RUN ls -al /home/app
の上の行に以下を追記してビルドしてみます。
USER root
RUN chown -R app /home/app
すると、
Step 14/25 : USER root
---> Running in 3e9229fd60a8
Removing intermediate container 3e9229fd60a8
---> 341a4cba25d9
Step 15/25 : RUN chown -R app /home/app
---> Running in a71e943328d2
Removing intermediate container a71e943328d2
---> 28db48b6506b
Step 16/25 : RUN ls -al /home/app
---> Running in f93a22e927a6
total 20
drwxr-xr-x 1 root root 4096 3月 11 14:50 .
drwxr-xr-x 1 root root 4096 3月 11 14:50 ..
-rw-r--r-- 1 root root 220 4月 18 2019 .bash_logout
-rw-r--r-- 1 root root 3526 4月 18 2019 .bashrc
-rw-r--r-- 1 root root 807 4月 18 2019 .profile
Removing intermediate container f93a22e927a6
---> 8c296aecc075
エラーにならず正常に終了していますが、 ls -al
の出力を見るとやはり root のままになっています。
参考にした記事
下の方にある
Limitations
The following standard Docker features are incompatible with running a Docker daemon with user namespaces enabled:
- Sharing PID or NET namespaces with the host (--pid=host or --network=host).
- External (volume or storage) drivers which are unaware or incapable of using daemon user mappings.
- Using the --privileged mode flag on docker run without also specifying --userns=host.
External (volume or storage) drivers which are unaware or incapable of using daemon user mappings. (デーモンユーザーマッピングを認識しない、または使用できない外部(ボリュームまたはストレージ)ドライバー。)
この1行を見たときに「あれ・・・もしかして」と気づいたのは、調査を開始してから3時間経ったときでした。。
解決
/etc/docker/daemon.json の内容は以下のように変更して dockerd を再起動すると、上記のような不思議な挙動はなくなりました。
{
"data-root": "/var/lib/docker",
"userns-remap": "1000:1000"
}
または、 data-root を指定しないことで、デフォルトの /var/lib/docker 以下にイメージが置かれます。
{
"userns-remap": "1000:1000"
}
そもそも、なんで別のディスクに指定していたの??
dockerってめちゃくちゃディスクの容量を逼迫しません??
ちまちまとイメージを消したりファイルの整理をしたりゴミ箱を空にしたり、やっててもすぐに「ディスクがいっぱいです」ってなりません??
なので 2TB の SSD を鼻息荒く購入したんですよ。
2TB のディスクに docker のお世話をしてもらいたかったんです・・
Discussion