1.はじめに
Dockerコンテナから、以下を同時に対応しようとして失敗した例です。
こんなことする人はあまり居ないと思うので、自分用の覚え書きとして残します。
やりたかったこと
過去に試したこちらの記事を参考に、
- ROS2のデバッグはDockerコンテナ内で行う
- Dockerコンテナ内からRaspberryPiやJetsonのGPIO等デバイスを制御する
- →(root権限必要)
- 開発対象のソースファイルは、ホストOSに置いて、sambaやssh経由でWindows上からソースを編集する
- →(一般ユーザ権限のままとしたい)
- Dockerコンテナ内から生成したファイルへの読み書きもしたい
- →(書き出すとrootになっちゃうので、自動的に一般ユーザに書き換えたい)
失敗の考察
- デバイスの制御には、ホストOSのroot権限が必要なこと
- ファイルの読み書きのパーミッションを一般ユーザにマッピングする設定を有効化すると、ホストOS側にアプローチするユーザと連動する(即ちホスト側から見ると一般ユーザになる)
- 上記が矛盾するので、結果として上手くいかなかったかな?
暫定処置
Dockerコンテナ内から生成したファイルは、パーミッション666
で扱う・・・
2.試したこと
どれも、当初の目的は達成できませんでしたが・・・--device
や--privileged
を使わなければ上手くいきます。良い勉強になりました
環境
- Jetson Nano
- Ubuntu Linux 18.04 (JETSON標準のOS)
$ uname -a Linux jetsonn 4.9.140-tegra #1 SMP PREEMPT Mon Dec 9 22:47:42 PST 2019 aarch64 aarch64 aarch64 GNU/Linux $ docker --version Docker version 19.03.6, build 369ce74a3c
(1)userns-remap
機能
参考:
Docker→ホストOSへの読み書きの際に、ユーザID/グループIDを指定の数だけオフセットして読み書きする方法です。
設定箇所
/etc/docker/daemon.json
に追記。
(ファイルが無ければ新規に作ってOK)
$ sudo nano /etc/docker/daemon.json
{ "runtimes": { "nvidia": { "path": "nvidia-container-runtime", "runtimeArgs": [] } } ,"userns-remap": "default" ### ↑ここを追記。先頭のコンマは、これより前の行に設定が入っているときに必要です }
ここで一旦、Dockerを再起動します。 再起動によって、この後編集するファイルに、自動的にひな形が追加されます。
$ sudo systemctl restart docker.service
続いて2つのファイルを編集します。
ユーザID/グループIDを指定の数だけオフセットするので、その数を指定します。
$ sudo nano /etc/subuid
編集前
dockremap:100000:65536
編集後
dockremap:1000:65536
ホストOS側の自分のUIDが1000の筈ですので、その値に修正します。
続いてもう一つのファイル。
$ sudo nano /etc/subgid
編集前
dockremap:100000:65536
編集後
dockremap:1000:65536
ホストOS側の自分のGIDが1000の筈ですので、その値に修正します。
ここでDockerを再起動します。
$ sudo systemctl restart docker.service
結果1
ユーザが変わってるので、イメージを作り直す必要があります。 こちらを参考にして下さい。
続いて、前述の参考資料のこちらと同じやり方で、コンテナを起動してみます。
$ docker run --name ros2 -h rosdk -v /home/user/gitwork:/root/gitwork -w /root/gitwork --de vice /dev/gpiomem --device /dev/i2c-1 --device /dev/ttyACM0 --privileged --rm -e TZ=Asia/Tokyo -it rosmine docker: Error response from daemon: privileged mode is incompatible with user namespaces. You must run the container in the host namespace when running privileged mode. See 'docker run --help'.
エラーが出てしまいます。
--privileged
オプションや--device
を指定するときに制限があるようです。
これは、オプションに--userns=host
を指定すると解消出来ます。
$ docker run --name ros2 -h rosdk -v /home/user/gitwork:/root/gitwork -w /root/gitwork --de vice /dev/gpiomem --device /dev/i2c-1 --device /dev/ttyACM0 --privileged --rm --userns=host -e TZ=Asia/Tokyo -it rosmine root@rosdk:~/gitwork#
無事にコンテナが起動しますが、この状態でファイルhoge
を作ると・・・
root@rosdk:~/gitwork# touch hoge root@rosdk:~/gitwork# ls -la total 44 drwxrwxr-x 11 1000 1000 4096 Jan 3 12:06 . drwx------ 1 1000 1000 4096 Jan 3 12:04 .. -rw-r--r-- 1 root root 0 Jan 3 12:06 hoge
コンテナを抜けて、ファイルのパーミッションを確認します。
$ ls ~/gitwork/ -la 合計 44 drwxrwxr-x 11 myasu myasu 4096 1月 3 12:06 . drwxr-xr-x 26 myasu myasu 4096 1月 3 01:48 .. -rw-r--r-- 1 root root 0 1月 3 12:06 hoge
あぁ、rootになっちゃってる・・・
結果2
実際には全く解決にはなってないのですが、オプション--userns=host
を使わずコンテナを起動するには、--privileged
オプションや--device
の指定を外します。
$ docker run --name ros2 -h rosdk -v /home/myasu/gitwork:/root/gitwork -w /root/gitwork --rm -e TZ=Asia/Tokyo -it rosmine root@rosdk:~/gitwork# ls -la total 44 drwxrwxr-x 11 root root 4096 Jan 3 12:06 . drwx------ 1 root root 4096 Jan 3 12:11 .. -rw-r--r-- 1 nobody nogroup 0 Jan 3 12:06 hoge
結果1で作ったファイルhoge
が、root
ではなく、nobody
になってます。
改めてファイルhogege
をつくります。
root@rosdk:~/gitwork# touch hogege root@rosdk:~/gitwork# ls -la total 44 drwxrwxr-x 11 root root 4096 Jan 3 12:11 . drwx------ 1 root root 4096 Jan 3 12:11 .. -rw-r--r-- 1 nobody nogroup 0 Jan 3 12:06 hoge -rw-r--r-- 1 root root 0 Jan 3 12:11 hogege
コンテナから抜けて、ホストOS側でユーザを確認します。
root@rosdk:~/gitwork# exit exit myasu@jetsonn:~/gitwork/docker/rosdk$ ls ~/gitwork/ -la 合計 44 drwxrwxr-x 11 myasu myasu 4096 1月 3 12:11 . drwxr-xr-x 26 myasu myasu 4096 1月 3 01:48 .. -rw-r--r-- 1 root root 0 1月 3 12:06 hoge -rw-r--r-- 1 myasu myasu 0 1月 3 12:11 hogege
ファイルhogege
のユーザが、一般ユーザになってます。
なので、userns-remap
機能を使う事自体は、今回の目的以外では有効です。
(2)-u
オプションの指定と/etc/passwdと/etc/groupをコンテナにマウント
参考: - dockerでvolumeをマウントしたときのファイルのowner問題 - Qiita
この方法に従って、コンテナを起動してみます。
$ docker run --name ros2 -h rosdk -v /home/myasu/gitwork:/var/gitwork --device /dev/gpiomem --device /dev/i2c-1 --device /dev/ttyACM0 -v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro -u $(id -u $USER):$(id -g $U SER) --privileged --rm -e TZ=Asia/Tokyo -it rosmine docker: Error response from daemon: privileged mode is incompatible with user namespaces. You must run the container in the host namespace when running privileged mode. See 'docker run --help'.
--privileged
オプションや--device
の指定に引っかかるようです。
指定を外せば起動しますが、今回の目的には適いません。 (コンテナ内から生成するファイルは、きちんと一般ユーザで作られます)
$ docker run --name ros2 -h rosdk -v /home/myasu/gitwork:/var/gitwork -v /etc/group:/etc/gro up:ro -v /etc/passwd:/etc/passwd:ro -u $(id -u $USER):$(id -g $USER) --rm -e TZ=Asia/Tokyo -it rosmine
(3)ENTRYPOINTでuseraddでユーザーを作る
参考: - dockerでvolumeをマウントしたときのファイルのowner問題 - Qiita
こちらの方法も、(2)と同じ結果になります。
3.おわりに
と言うわけで、新年早々のブログが”失敗”ネタになってしまいましたが、Dockerの知見が得られたと言うことで・・・