Kotaro7750's Gehirn
Home About
  • Home
  • Category
  • About

dockerコンテナ内でホストからマウントされたファイルシステムにアクセスするときのパーミッションについて

2022-06-22

TL; DR;

  • コンテナは指定されたユーザー番号(デフォルトでは0番のroot)でコンテナ内のアプリケーションを実行する。このユーザーはコンテナ・ホスト共に存在しないものを指定してもよい。
  • マウントされたホスト上のファイルシステムに対してコンテナ内で書き込むと、コンテナが書き込み時に使用したユーザー番号がそのままホスト上でも使われる
  • bind mountで存在しないディレクトリを指定するとdocker engineが勝手に作ってくれ、その所有者はdocker engineの実行ユーザー(多くの場合root)となる

マウントされたファイルシステムにアクセスするときのパーミッションエラー問題

調べるといろいろ出てくると思いますが、コンテナにファイルシステムをマウント1したとき、ホストマシンとコンテナ間でuidやgidがそのまま使われてしまうことによっていざアプリケーションを動かそうとしたりコンテナが書き込んだデータがroot所有になっていたりする、という問題がlinuxでは生じます2。

この問題に遭遇した時、様々な解決策が講じられていますが、とりあえずそれらは置いておいて、なぜこのような現象が起きるのかを理解するためにいくつか実験を行います。

実験その1 〜特に何も考えず書き込む〜

まずは特に何も考えずbind mountを行ってコンテナ内でマウントされたディレクトリに書き込みを行います。

以下のようなDockerfileを用意して

FROM debian:11-slim

CMD ["touch", "/hogehoge/test.txt"]
$ docker run --rm -v $(pwd)/hogehoge:/hogehoge docker-permission-test

$ ls
Dockerfile  hogehoge

$ ls -l
合計 8
-rw-rw-r-- 1 koutarou koutarou   57  6月 16 21:26 Dockerfile
drwxr-xr-x 2 root     root     4096  6月 16 21:26 hogehoge

$ ls hogehoge -l
合計 0
-rw-r--r-- 1 root root 0  6月 16 21:26 test.txt

マウントした hogehoge ディレクトリにtest.txtというファイルを作るだけです。 hogehogeディレクトリは走らせた時点で存在していないので勝手に(root:rootで)作られ、その中にはこれまたroot:rootなtest.txtができています。

それでは、予めhogehogeディレクトリがある状態で走らせるとどうでしょうか?

$ mkdir hogehoge

$ docker run --rm -v $(pwd)/hogehoge:/hogehoge docker-permission-test

$ ls -l
合計 8
-rw-rw-r-- 1 koutarou koutarou   57  6月 16 21:26 Dockerfile
drwxrwxr-x 2 koutarou koutarou 4096  6月 16 21:30 hogehoge

$ ls hogehoge -l
合計 0
-rw-r--r-- 1 root root 0  6月 16 21:30 test.txt

hogehogeがroot:rootではなくmkdirしたユーザー・グループ所有のものになっています。

実験その2 〜コンテナで実行するユーザーを指定してみる〜

先程はdocker runするときに特にユーザーを意識しませんでしたが、公式ドキュメントにはコンテナ内で実行されるプロセスの実行ユーザーを指定することができると書いてあります。

先ほどと同じDockerfileでdocker runする時にユーザー指定してみるとどうなるでしょうか?

$ mkdir hogehoge

$ chmod 777 hogehoge

$ docker run --rm -u=1001:1001 -v $(pwd)/hogehoge:/hogehoge docker-permission-test

$ ls -l
合計 8
-rw-rw-r-- 1 koutarou koutarou   57  6月 16 21:26 Dockerfile
drwxrwxrwx 2 koutarou koutarou 4096  6月 16 21:37 hogehoge

$ ls -l hogehoge
合計 0
-rw-r--r-- 1 1001 1001 0  6月 16 21:37 test.txt

docker runするときに1001:1001というユーザー・グループで実行するように指定しました。 その結果、test.txtは1001:1001所有になりました。

ドキュメントにはデフォルトではidが0のユーザー(多くの場合はroot)が使われると書いてあります。そのため実験1ではroot:root所有になったと考えられます。 そして指定すると指定通りになりました。 なお、私のホストマシンにはidが1001のユーザー・グループが存在していないため数字での指定となっています。 これを存在する番号で指定すると下のように名前で表示してくれるようになります。

$ docker run --rm -u=117:124 -v $(pwd)/hogehoge:/hogehoge docker-permission-test

$ ls -l hogehoge
合計 0
-rw-r--r-- 1 pulse pulse 0  6月 16 21:41 test.txt

ここで注意してほしいのは、コンテナには117番のユーザーや124番のグループは存在していないのにホストマシンでlsした結果適切な名前で表示されているということです。 つまり、コンテナは指定されたら指定の通りの実行ユーザーでファイルシステムにアクセスを行いますが、そのアクセスはホストマシンのファイルシステムにもそのまま適用されるということです。 よって、dockerはコンテナとホストマシンの間で特にユーザー・グループの変換を行わず、単純にファイルシステムに番号だけを書き残すということが分かります。

なお、ユーザーの指定はdocker runするときだけでなく、下のようにDockerfileにも書くことができます。

FROM debian:11-slim
USER 1001:1001

CMD ["touch", "/hogehoge/test.txt"]

実験その3 〜mkdirせずにマウントしたディレクトリに対してユーザー指定したコンテナでアクセスする〜

実験2では手動でmkdirしていましたが、これをdockerに任せるとどうなるでしょうか?ユーザー指定したのでそのパーミッションで作ってくれるのでしょうか?

$ docker run --rm -u=1001:1001 -v $(pwd)/hogehoge:/hogehoge docker-permission-test
touch: cannot touch '/hogehoge/test.txt': Permission denied

$ ls -l
合計 8
-rw-rw-r-- 1 koutarou koutarou   57  6月 16 21:57 Dockerfile
drwxr-xr-x 2 root     root     4096  6月 16 21:57 hogehoge

permission deniedエラーが出てコンテナ実行はエラーに終わりました。 また、hogehogeディレクトリはroot:root所有となっています。

実験2までの知見から、「1001番のユーザー」(名前を意識していないのであえてこういう表記にしています)がroot:rootで766なディレクトリに対してファイルを作ろうとしたのでエラーが出たのだ、ということが推測され、恐らく実際その通りです。

ここまでは割と自明なのですが、当初の希望的観測では、ユーザー指定したらそのパーミッションでディレクトリを作ってくれるのではとしていました。 どうもこれは成り立たなかったようです。

公式ドキュメントによると、マウントするディレクトリが存在しなかった場合にはその都度作られる、としています。 誰が作っているかは書いてなさそうでしたが恐らくdockerの中核であるdocker engineだと思われます。 docker engine自体はrootで動いているので新しく作られたディレクトリはroot:root所有になるということです。

勝手にユーザーを推定してくれても親切じゃないかとも思いますが、よく考えてみるとdocker runで指定しないでもDockerfileに書いてイメージ自体に実行ユーザーを設定することもできますし3、存在しない番号を指定するみたいなこともできてしまうのでdocker engineに任せるというのが自然ですね。

Footnotes

  1. 公式ドキュメント的にはbind mountというらしいです。docker管理領域の中に作ってくれるvolumeとは区別されるものです ↩

  2. 正確にはunix系コンテナとunix系ホストだと思う。windows系が絡んでくるとどうなるんだろう? ↩

  3. というかdocker runのuオプション自体それを上書きするという挙動です ↩

Related Posts

スケーラブルなOpenTelemetry CollectorパイプラインをKubernetes上に構築する

スケーラブルなOpenTelemetry CollectorパイプラインをKubernetes上に構築する

2025-04-14

OpenTelemetry Certified Associate ( OTCA ) を取得した

OpenTelemetry Certified Associate ( OTCA ) を取得した

2025-04-13

Packerで実現するKVMでのイミュータブルインフラストラクチャ

Packerで実現するKVMでのイミュータブルインフラストラクチャ

2024-09-27

New Posts

スケーラブルなOpenTelemetry CollectorパイプラインをKubernetes上に構築する

スケーラブルなOpenTelemetry CollectorパイプラインをKubernetes上に構築する

2025-04-14

OpenTelemetry Certified Associate ( OTCA ) を取得した

OpenTelemetry Certified Associate ( OTCA ) を取得した

2025-04-13

Golangのnet/httpの実装からHTTP1.1クライアントでのTCPコネクションの挙動を確かめる

Golangのnet/httpの実装からHTTP1.1クライアントでのTCPコネクションの挙動を確かめる

2025-03-21

ToC

  • TL; DR;
  • マウントされたファイルシステムにアクセスするときのパーミッションエラー問題
  • 実験その1 〜特に何も考えず書き込む〜
  • 実験その2 〜コンテナで実行するユーザーを指定してみる〜
  • 実験その3 〜mkdirせずにマウントしたディレクトリに対してユーザー指定したコンテナでアクセスする〜
  • Footnotes

Ads

Ads

Privacy Policy