hotch-potch, Note to self

いろいろ作業記録

Docker GPIO制御とユーザマッピング(失敗)

1.はじめに

Dockerコンテナから、以下を同時に対応しようとして失敗した例です。

こんなことする人はあまり居ないと思うので、自分用の覚え書きとして残します。

やりたかったこと

qiita.com

過去に試したこちらの記事を参考に、

  • ROS2のデバッグはDockerコンテナ内で行う
  • Dockerコンテナ内からRaspberryPiやJetsonのGPIO等デバイスを制御する
    • →(root権限必要)
  • 開発対象のソースファイルは、ホストOSに置いて、sambaやssh経由でWindows上からソースを編集する
    • →(一般ユーザ権限のままとしたい)
  • Dockerコンテナ内から生成したファイルへの読み書きもしたい
    • →(書き出すとrootになっちゃうので、自動的に一般ユーザに書き換えたい)

失敗の考察

  • バイスの制御には、ホストOSのroot権限が必要なこと
  • ファイルの読み書きのパーミッションを一般ユーザにマッピングする設定を有効化すると、ホストOS側にアプローチするユーザと連動する(即ちホスト側から見ると一般ユーザになる)
  • 上記が矛盾するので、結果として上手くいかなかったかな?

暫定処置

Dockerコンテナ内から生成したファイルは、パーミッション666で扱う・・・

2.試したこと

どれも、当初の目的は達成できませんでしたが・・・--device--privilegedを使わなければ上手くいきます。良い勉強になりました

環境

$ 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機能

参考:

  1. Tavi's Travelog - Dockerでのホストとコンテナの権限問題について
  2. docker volume mount時のuser owner問題 - Qiita

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  13 12:06 .
drwxr-xr-x 26 myasu myasu 4096  13 01:48 ..
-rw-r--r--  1 root  root     0  13 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  13 12:11 .
drwxr-xr-x 26 myasu myasu 4096  13 01:48 ..
-rw-r--r--  1 root  root     0  13 12:06 hoge
-rw-r--r--  1 myasu myasu    0  13 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の知見が得られたと言うことで・・・