MkItYs

MkItYs > ネットワークとサーバを作る > 

images

コンテナを一般ユーザで使う:Linux (Ubuntu) , Docker (Rootless) , GPU, NFS

images

- 2022.10.21

コンテナ(Docker)を一般ユーザで動かす手順ですーーいくつかやり方がありますが、いまはルートレスモードが正式対応となったので、これを導入します。

関連


コンテナを導入する:Docker

検証


OS:Ubuntu 20.04, 22.04
コンテナ:Docker 20.10

概要:コンテナのセキュリティ


コンテナは便利な技術ですが、セキュリティが弱いという面がありますーー原理上、管理ユーザ(root)の権限でコンテナを動かすので、複数の利用者がいる場合(マルチユーザ)、すべてのコンテナにすべての利用者がかんたんにアクセスできてしまうからです。

また利用者が単独で使う場合も、問題はありますーーコンテナ上で作成したファイルをホスト上に置くと、基本的にその所有者も管理ユーザになりますーー一般ユーザでコンテナを動かす場面も多くあるので、この権限の差は、いろいろ面倒なことを引き起こします。

これらの問題を(完全にではありませんが)解決するのが、「ルートレス」と呼ばれる技術です。[※1][※2]


※1
これを提案〜実装したのは、日本の須田瑛大氏です:
https://medium.com/nttlabs/rootless-docker-12decb900fb9
※2
これ以前にもいくつか回避策はありましたが(利用者の任意に任せるなど(--user))、緩く煩雑なものでした。

手順:管理ユーザ:ルートレスキットを導入する


最近のOS(Ubuntu 20.04/22.04)では、ルートレスモードに正式対応したコンテナ(Docker 20.10 -)が、既定で設置されるようになりましたーーこれで、古いパッケージ群を削除する必要もなく、かんたんにルートレスを導入できるようになっています。

まず管理ユーザで、次を実行します:

$ docker --version # バージョンを確認

$ apt install gnupg
$ apt install curl
$ cd /etc/apt
$ cp -p sources.list sources.list_org
$ vi sources.list # リポジトリを追加
deb https://download.docker.com/linux/ubuntu/ focal stable # 次の場合:ubuntu 20.04
deb https://download.docker.com/linux/ubuntu/ jammy stable # 次の場合:ubuntu 22.04
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
$ apt update

$ apt install docker-ce-rootless-extras # 併せて設置される:slirp4netns
$ apt install uidmap

$ systemctl disable --now docker.service
$ systemctl disable --now docker.socket
$ reboot

手順:管理ユーザ:ユーザ名前空間を振り分ける


それぞれの一般ユーザが、コンテナ上でさらに独自の一般ユーザ群を作れるようにするため、カーネルの「ユーザ名前空間」が利用されますーーこれらのIDをホスト側のIDとマッピングするのに、次の設定ファイル群が使われます:

/etc/subuid
/etc/subgid

次の書式で、それぞれの一般ユーザに、使えるIDの範囲を割り当てます:[※1][※2][※3]

https://docs.docker.com/engine/security/rootless/
<user>:<start>:<size>

※1
これを設定しないと、ルートレスモードのコンテナは起動しません。
※2
それぞれの一般ユーザに割り当てるサブID群は、原則、次の範囲です:65536
※3
ユーザを登録するコマンド(useradd, etc. )を使えば、これらのサブIDは自動でマップされます。ただし、すでに登録されているユーザについては、手動で登録することになります。

手順:管理ユーザ:GPUを使う


ルートレスモードでエヌビディア社のGPUを使うときは、次のようにGPUの設定を書き換えます:

https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html
$ cd /etc/nvidia-container-runtime
$ cp -p config.toml config.toml_org
$ sed -i 's/^#no-cgroups = false/no-cgroups = true/' config.toml

手順:管理ユーザ:NFSと連携させる


ルートレスモードにすると、既定では、コンテナの(イメージなどが格納される)「データルート」の置き場所が、それぞれのユーザのホームディレクトリ配下になります。

ホームディレクトリをNFSで共有している場合、これがコンテナの制約に触れることになります(データルートは、NFSで共有するファイルシステムに置けない)。

この制約への対策として、データルートをそれぞれのマシンの配下に置くため、それぞれの一般ユーザで設定を書き換えます:

https://docs.docker.com/engine/security/rootless/
$ cd ${HOME}/.config/docker
$ vi daemon.json
{
  "data-root" : "${directory_data_root}/${USER}/docker"
}

それぞれのマシンでは、データルートの置き場所となるフォルダを作ります。そして一般ユーザに、(自身のフォルダを作れるよう)書き込みのアクセス権を与えておきます。[※1]


※1
それぞれのマシンでデータルートの置き場所を統一するには、シンボリックリンクを使うしかありません(ストレージの構成に柔軟に対応するにはーーハードリンクも使えないので)。ただこれもコンテナの制約に触れるようで、NFSとの共存はやっかいですね……
https://drgripa1.hatenablog.com/entry/2021/05/08/195822

手順:一般ユーザ:初期設定をする


それぞれの一般ユーザで、次を実行します:[※1]

$ dockerd-rootless-setuptool.sh install

$ systemctl --user status docker
$ systemctl --user start docker # 起動していないなら

※1
既定のシェルがsh/bash でない場合、次の環境変数を、ログイン時に有効にするような設定が必要になるかもしれません:
DOCKER_HOST=unix:///run/user/${UID}/docker.sock

手順:一般ユーザ:コンテナで(Xウィンドウ依存の)GUIアプリを使う


ルートレスモードでは、ホスト側のネットワークリソースを占有できません。そのため、コンテナ上で動くGUIアプリを使うには、コンテナ側でSSHサーバを動かす必要があります:[※1]

Xクライアントの設定(リモートホスト:コンテナ:マルチユーザの場合)

※1
むしろこれが、Xフォワーディングでは適切な対応のしかたですが……

手順:一般ユーザ/管理ユーザ:ログアウトしたあとも、コンテナを稼働させておく


一般ユーザがログアウトしたあともコンテナを稼働させておくようにするには、(管理ユーザの権限で)次を実行します:[※1][※2]

$ loginctl enable-linger ${USER} # そのユーザのサービスを稼働させ続ける
$ loginctl disable-linger ${USER} # ログアウトでサービスが停止するようにする

※1
一般ユーザにこの権限(管理ユーザになる権限)を与える場合は、これらの操作の手順と影響について、相応の説明が必要になるはずです。
※2
あるいは、ログアウトしたあともセッションを維持するアプリ(tmux, etc.)を使う、という選択肢もあります。

補足:NFSと連携させる[非推奨(これはただの実験です)


なおデータルートのNFSにおける制約については、次のような回避策が言及されていたりもします:

https://www.reddit.com/r/docker/comments/iqhzxm/dataroot_on_a_nfs_filesystem_is_it_possible/

たしかにNFSマウントしたファルダ上にイメージファイルを作り、それをループバックマウントすれば、エラーは出なくなります[下記]。

しかしこのやり方は問題がありますーーOSからはあくまでローカルにマウントしているようにみえるので、複数のNFSクライアント/コンテナがこのイメージを共有すると、どのような挙動になるのか予測がつきませんーーあくまで単独ユーザでの実験の範囲にとどめるべきものです。


手順:一般ユーザで:

コンテナイメージを作成( → 失敗):

$ docker pull ubuntu:latest
latest: Pulling from library/ubuntu
cf92e523b49e: Extracting  30.43MB/30.43MB
failed to register layer: ApplyLayer exit status 1 stdout:  stderr: lchown /etc/gshadow: operation not permitted

いったんログアウト。

手順:管理ユーザで/NFSサーバ側:

NFSエクスポートしたフォルダに、イメージファイルを作成:

$ cd ${dir_exported}
$ dd if=/dev/zero of=${user}.img bs=1M count=1000
$ mkfs.ext4 ${user}.img
手順:管理ユーザで/NFSクライアント側:

NFSマウントしたフォルダ上のイメージファイルを、ループバックマウント:

$ mkdir ${dir_loopbak}
$ mount -t ext4 -o loop ${dir_mounted}/${user}.img ${dir_loopbak}

対象ユーザのホームディレクトリを、イメージファイル上のフォルダに変更:

$ cd ${dir_loopbak}
$ cp -pr ${dir_mounted}/${user} .
$ usermod -d ${dir_loopbak}/${user} ${user}
手順:一般ユーザで:

再度ログイン、コンテナイメージを作成( → 成功):

$ docker pull ubuntu:latest
latest: Pulling from library/ubuntu
cf92e523b49e: Pull complete 
Digest: sha256:35fb073f9e56eb84041b0745cb714eff0f7b225ea9e024f703cab56aaa5c7720
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

コンテナの起動やコミットなども、いちおう可能。