Dockerと--userns-remap、ホストとコンテナ間でデータを共有するためのボリューム権限を管理する方法は?


96

Dockerでは、コンテナー内で作成されたファイルは、ホストからそれらを検査している間、予測できない所有権を持つ傾向があります。ボリューム上のファイルの所有者はデフォルトでroot(uid 0)ですが、root以外のユーザーアカウントがコンテナーに関与してファイルシステムに書き込むとすぐに、所有者はホストの観点から多かれ少なかれランダムになります。

dockerコマンドを呼び出しているのと同じユーザーアカウントを使用して、ホストからボリュームデータにアクセスする必要がある場合に問題になります。

一般的な回避策は次のとおりです。

  • Dockerfiles(非移植可能)での作成時にユーザーにuIDを強制する
  • ホストユーザーのUIDをdocker run環境変数としてコマンドに渡し、chownエントリポイントスクリプトのボリュームでいくつかのコマンドを実行します。

これらのソリューションはどちらも、コンテナー外の実際のアクセス許可をある程度制御できます。

私は、ユーザーの名前空間がこの問題の最終的な解決策になると期待していました。最近リリースされたバージョン1.10と--userns-remapをデスクトップアカウントに設定して、いくつかのテストを実行しました。ただし、マウントされたボリュームのファイル所有権を処理しやすくすることができるかどうかはわかりません。実際には逆になる可能性があります。

この基本的なコンテナを開始するとします

docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit

そして、ホストからのコンテンツを検査します:

ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/

-rw-r--r-- 1 100000 100000 6 Feb  8 19:43 test.txt

この番号「100000」はホストユーザーのサブUIDですが、ユーザーのUIDに対応していないため、権限がないとtest.txtを編集できません。このサブユーザーは、docker以外の実際の通常のユーザーとは親和性がないようです。マッピングされていません。

この投稿で前述した、ホストとコンテナ間でUIDを調整することで構成されていた回避策UID->sub-UIDは、名前空間で発生するマッピングのために機能しなくなりました。

次に、(セキュリティを向上させるために)ユーザー名前空間を有効にしてdockerを実行する一方で、dockerを実行しているホストユーザーがボリュームで生成されたファイルを所有できるようにする方法はありますか?


ホストとコンテナー間でボリュームを共有する場合、ユーザーの名前空間はソリューションの一部にはならないだろうと思います。2番目のオプション(「ホストユーザーのUIDを環境変数としてdocker runコマンドに渡してから、エントリポイントスクリプトのボリュームでいくつかのchownコマンドを実行する」)がおそらく最善の解決策です。
larsks 2016年

4
Docker自体は、ホストにマウントされた書き込み可能なボリュームの使用を推奨していないようです。私はクラウドサービスを実行しておらず、自分の信頼できるイメージのみを使用しているので、ユーザーNSのセキュリティ上の利点がそれほど便利さを犠牲にする価値があるかどうか疑問に思っています。
ステファンC.

@StéphaneC。おそらくより良いアプローチを見つけましたか?
EightyEight 2016年

4
残念ながら、いいえ。ユーザーの名前空間を使用せず、ホストからUIDを渡すことは、依然として私の選択の選択肢です。将来、ユーザーをマッピングする適切な方法があることを願っています。私はそれを疑っていますが、それでも私は目を開いています。
ステファンC.

回答:


46

ユーザーとグループを事前に準備できる場合は、ホストユーザーがコンテナー内の名前空間付きユーザーに対応するように、特定の方法でUIDとGIDを割り当てることができます。

次に例を示します(Ubuntu 14.04、Docker 1.10):

  1. 固定の数値IDを持つユーザーを作成します。

    useradd -u 5000 ns1
    
    groupadd -g 500000 ns1-root
    groupadd -g 501000 ns1-user1
    
    useradd -u 500000 -g ns1-root ns1-root
    useradd -u 501000 -g ns1-user1 ns1-user1 -m
    
  2. /etc/subuidおよび/etc/subgidファイル内の自動生成された従属ID範囲を手動で編集します。

    ns1:500000:65536
    

    (ノートはレコードのために存在しないns1-rootns1-user1に起因するMAX_UIDMAX_GIDの制限で/etc/login.defs

  3. でユーザー名前空間を有効にする/etc/default/docker

    DOCKER_OPTS="--userns-remap=ns1"
    

    デーモンを再起動しservice docker restart/var/lib/docker/500000.500000ディレクトリが作成されていることを確認します。

    あなたが持っている今、内部コンテナrootuser1、ホスト上で-ns1-rootns1-user1、一致するIDを持ちます

    更新: root以外のユーザーがコンテナー内に固定ID(user1 1000:1000など)を持っていることを保証するには、イメージのビルド中にそれらを明示的に作成します。

試乗:

  1. ボリュームディレクトリを準備します

    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
  2. コンテナからお試しください

    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
  3. ホストからお試しください

    passwd ns1-root
    login ns1-root
    cat /vol1/file
    echo "can write" >> /vol1/file
    

ポータブルではなく、ハックのように見えますが、機能します。


3
非常に興味深く、+ 1に値します。ただし、イメージ内のuser1にUID 1000が割り当てられていることを確認する必要があります。そうしないと、ホストでUID501000を受信するかどうかを確認できません。ところでsubUID lower bound + UID in image、IDが1000に設定されたユーザーで多くの異なるイメージを実行している場合、式は常に正しいと確信していますか?
ステファンC.

@StéphaneC。いい視点ね!画像内のIDの修正に関するメモを追加しました。公式については、私は自分の画像でさらに実験し、何か見つけたら答えを更新します
amartynov 2016年

1
ユーザーとグループをホストとコンテナーに手動で配置する場合、本当に「ユーザー名前空間」機能が必要ですか?
トリスタン

1
作成する名前空間は、ホストユーザーとコンテナーユーザーを分離しますが、特に公式イメージ(mysqlのような)が明示的なuidなしでユーザーを作成する場合は、コンテナーに複数の名前空間が必要になる場合があります。--userns-remapオプションが1つだけを期待している場合、複数の名前空間をどのように処理しますか?
トリスタン

2
@amartynov「ns1」ユーザーのUID(5000)を指定するのに苦労した理由をお聞きしますか?これは、subuidファイルとsubgidファイルで参照する名前(UIDではない)であるため、このユーザーが取得するUIDは重要ではないようです。5000と500000の類似性が示唆するように、私はいくつかの関係を失っていますか?
Jollymorphic 2017年

2

回避策の1つは、ビルド時にユーザーのuidを動的に割り当ててホストに一致させることです。

Dockerfile

FROM ubuntu
# Defines argument which can be passed during build time.
ARG UID=1000
# Create a user with given UID.
RUN useradd -d /home/ubuntu -ms /bin/bash -g root -G sudo -u $UID ubuntu
# Switch to ubuntu user by default.
USER ubuntu
# Check the current uid of the user.
RUN id
# ...

次に、次のようにビルドします。

docker build --build-arg UID=$UID -t mycontainer .

そして実行する:

docker run mycontainer

既存のコンテナがある場合は、次のラッパーコンテナを作成しますDockerfile

FROM someexistingcontainer
ARG UID=1000
USER root
# This assumes you've the existing user ubuntu.
RUN usermod -u $UID ubuntu
USER ubuntu

これは次のようにラップできますdocker-compose.yml

version: '3.4'
services:
  myservice:
    command: id
    image: myservice
    build:
      context: .
    volumes:
    - /data:/data:rw

次に、次のようにビルドして実行します。

docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice

1
私は不親切に見えたくありませんが、これは実際には元の質問にリストされている回避策の1つですが、解決策ではなく、ユーザーの名前空間とは関係ありません。
ステファン

@StéphaneC。この関連する質問にコメントできますか?stackoverflow.com/questions/60274418/...
overexchange

-1

docker cpコマンドを使用すると、権限の問題を回避できます。

所有権は、宛先のユーザーとプライマリグループに設定されます。たとえば、コンテナにコピーされたファイルUID:GIDは、rootユーザーで作成されます。ローカルマシンにコピーされたファイルUID:GIDは、docker cpコマンドを呼び出したユーザーのによって作成されます。

これが使用に切り替えられた例docker cpです:

$ docker run -ti -v /data debian:jessie /bin/bash
root@e33bb735a70f:/# echo 'hello' > /data/test.txt
root@e33bb735a70f:/# exit
exit
$ docker volume ls
DRIVER              VOLUME NAME
local               f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
$ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
total 4
-rw-r--r-- 1 100000 100000 6 Oct  6 10:34 test.txt
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
e33bb735a70f        debian:jessie       "/bin/bash"         About a minute ago   Exited (0) About a minute ago                       determined_hypatia
$ docker cp determined_hypatia:/data/test.txt .
$ ls -l test.txt 
-rw-r--r-- 1 don don 6 Oct  6 10:34 test.txt
$ cat test.txt
hello
$ 

ただし、コンテナからファイルを読み取るだけの場合は、名前付きボリュームは必要ありません。この例では、名前付きボリュームの代わりに名前付きコンテナーを使用します。

$ docker run -ti --name sandbox1 debian:jessie /bin/bash
root@93d098233cf3:/# echo 'howdy' > /tmp/test.txt
root@93d098233cf3:/# exit
exit
$ docker cp sandbox1:/tmp/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct  6 10:52 test.txt
$ cat test.txt
howdy
$ 

この質問で説明されているように、ファイルをコンテナにコピーする場合は、名前付きボリュームが便利です。


ただしdocker cp、データの複製が含まれます。さらに、ドキュメントによると、データをコンテナーにコピーするときに、rootユーザーに従って所有権IDを設定します。これは、コンテナー化されたアプリを実行しているアカウントではないことがよくあります。それが私たちの問題をどのように解決するのかわかりません。
ステファンC.

そうです、@Stéphane、データの複製が含まれます。ただし、ファイルのコピーを作成すると、ホストとコンテナーで異なる所有権とアクセス許可を割り当てることができます。docker cptarアーカイブをコンテナにストリーミングしたりコンテナからストリーミングしたりするときに、ファイルの所有権を完全に制御できます。ストリーミング時にtarファイルの各エントリの所有権と権限を調整できるため、rootユーザーに限定されません。
ドンカークビー2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.