Docker-ホストUSBまたはシリアルデバイスへのアクセスを提供する方法?


回答:


194

いくつかのオプションがあります。--device使用できるフラグを使用して、--privilegedモードなしでUSBデバイスにアクセスできます。

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash

または、USBデバイスがのホスト上で動作しているドライバなどで利用可能であると仮定して、特権モードボリュームオプション/dev/bus/usbを使用して、これをコンテナにマウントできます。例えば:

docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash

名前が示すように、これ--privileged安全 ではなく、注意して処理する必要があります。


4
-vは必要ありません-特権はすでにすべてのデバイスへのアクセスを意味します
Art

12
Windows Dockerクライアントにこのようなメカニズムはありますか?
Pascal

このソリューションを使用すると、Dockerコンテナーからのデバイスが表示されません... 問題の詳細については、stackoverflow.com / questions / 37213812をご覧ください。助けてくれてありがとう!ありがとう。
kashesandr 2016年

1
Dockerが既に実行されている後にUSBデバイスが接続されている場合は、まだ機能しません。
フランクリンDattein 16年

つまり、lsusbがデバイスを一覧表示できるにもかかわらず、/ tty / USBXの下のデバイスをマップしません。
フランクリンDattein 16年

78

Dockerの現在のバージョンでは、--deviceすべてのUSBデバイスへのアクセスを許可する必要なしに、フラグを使用して目的を達成できます。

たとえば/dev/ttyUSB0、Dockerコンテナー内でのみアクセスできるようにしたい場合は、次のようにします。

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash

3
現時点では、デバイスがシンボリックリンクになることはできません。github.com/docker/docker/issues/13840
wligtenberg

6
--deviceフラグを使用して/dev/<device>、特にWindowsまたはMacでDocker Quickstart Terminal(VirtualBox Host)を使用している場合、ホストマシン上の関連付けられているAndroidデバイスを特定するにはどうすればよいですか?
DanCat 2015年

1
これは、デバイス名が変更されない場合にうまく機能します。しかし、/ dev / bus / usb内のデバイスを使用する動的なものを使用している場合、プラグを抜いたり抜いたりするとデバイス名が変わるため、これは機能しません。代わりに、上記の-v(ボリューム)ソリューションが必要です。
Brad Grissom

1
@DanCat udevルールにより、デバイスを静的パスにマウントできます
C. Reed

1
なぜ誰もが1つのUSBデバイスへのアクセスに興味があるのでしょうか?USBデバイスは接続され、接続が切断されることを意図しており、アプリの実行中に行う必要があります。USBはSATAでも何かでもありません。何かが常に存在することを期待することはできません...そして、人々は単一実行のためにDockerを介してアプリを起動し、USBデバイスが切断されるとすぐにそれらを終了するとは思いませんか?単一実行のjarではなく、サービスタイプのアプリに似ていると思います...しかし、本当に、その非常に限られたシナリオが適している一部の
ユーザー

17

--deviceUSBデバイスのプラグが抜かれたり、抜かれたりするまで機能します。cgroup devices.allowを使用する必要があります。
そのまま使用することもできます-v /dev:/devが、ホストからコンテナに、ローディスクデバイスなどを含むすべてのデバイスをマッピングするため、安全ではありません。基本的にこれにより、コンテナーはホスト上でrootになることができますが、これは通常は必要ありません。
cgroupsアプローチの使用はその点でより優れており、コンテナーが起動した後に追加されるデバイスで機能します。

詳細はこちら: Dockerで--privilegedを使用せずにUSBデバイスにアクセスする

貼り付けるのは少し難しいですが、簡単に言えば、キャラクターデバイスのメジャー番号を取得してcgroupに送信する必要があります。

189は/ dev / ttyUSB *のメジャー番号で、「ls -l」で取得できます。お使いのシステムと私のシステムでは異なる場合があります。

root@server:~# echo 'c 189:* rwm' > /sys/fs/cgroup/devices/docker/$A*/devices.allow  
(A contains the docker containerID)

次に、次のようにコンテナを起動します。

docker run -v /dev/bus:/dev/bus:ro -v /dev/serial:/dev/serial:ro -i -t --entrypoint /bin/bash debian:amd64

これを行わないと、コンテナの起動後に新しく接続または再起動されたデバイスは新しいバスIDを取得し、コンテナへのアクセスが許可されません。


7
これを-1にした人には、改善したいことを助けて言ってください。このページは、私たちが行った問題に遭遇した他の人たちを助けるために書きました。私はスタックオーバーフローについても共有して人々を助けようとするのをやめていると言って正直になります:-/
Marc Merlin

私の答えを読むと、ボリューム「-v / dev:/ dev」を追加すると、動的に接続されたデバイスにアクセスできることがわかります。
rrpilot

5
rrpilot:-v / dev:/ devを使用すると、/ dev / sdaや、コンテナー内のrootユーザーに公開したくない他のものなど、すべての/ devが提供されます。つまり、ソリューションは機能しますが、安全ではありません。鉱山はその問題を回避します。私はそれを指摘するために私の答えを編集します。
Marc Merlin

1
メジャー番号を取得する方法を示し、189置き換える必要があることを明確にすることで、答えをより良くすることができます。送信する内容の説明はdevices.allowここで見つけることができます:kernel.org/doc/Documentation/cgroup-v1/devices.txt
クレイグYounkins

1
この少し簡単になりドッカーの新っぽい機能があります:「--device-のcgroup-ルール」(docs.docker.com/engine/reference/commandline/create/...
tianon

14

既に与えられている答えを拡張して、キャプチャされない動的に接続されたデバイスのサポート/dev/bus/usbと、boot2docker VMと一緒にWindowsホストを使用するときにこれを機能させる方法を含めたいと思いました。

Windowsを使用している場合は、VirtualBoxマネージャー内でDockerにアクセスさせるデバイスのUSBルールを追加する必要があります。これを行うには、次のコマンドを実行してVMを停止します。

host:~$ docker-machine stop default

VirtualBox Managerを開き、必要に応じてフィルターを使用してUSBサポートを追加します。

boot2docker VMを起動します。

host:~$ docker-machine start default

USBデバイスはboot2docker VMに接続されているため、コマンドはそのマシンから実行する必要があります。VMでターミナルを開き、docker runコマンドを実行します。

host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash

このコマンドをこのように実行すると、以前に接続されたUSBデバイスのみがキャプチャされます。ボリュームフラグは、コンテナの起動後に接続されたデバイスでこれを機能させる場合にのみ必要です。その場合、以下を使用できます。

docker@default:~$ docker run -it --privileged -v /dev:/dev ubuntu bash

注:のようなデバイスをキャプチャする/devには/dev/bus/usb、場合によってはの代わりにを使用する必要がありました/dev/sg2。同じことが/dev/ttyACM0やなどのデバイスにも当てはまると思い/dev/ttyUSB0ます。

docker runコマンドはLinuxホストでも動作します。


代わりに/ dev:/ devをマウントするのは良い点です。これにより、他のデバイスのキャプチャに関してより多くの柔軟性が得られ、動的要素にも役立ちます。
コタコタコタ

また、ホストマシンのセキュリティと分離を危険にさらします。
Exadra37

@ Exadra37それは...そしてそれがあなたのアプリケーションで重要であるなら、あなたはこれを使うべきではありません。ただし、気にする必要がなく、分離にdockerを使用していないアプリケーションがあることに注意することが重要です。私の特定のケースでは、パッケージ化されたLinuxアプリケーションをWindowsで実行できます。
rrpilot

3

もう1つのオプションは、デバイスのマウント方法と権限を制御するudevを調整することです。シリアルデバイスへの非ルートアクセスを許可するのに役立ちます。デバイスを永続的に接続している--device場合は、このオプションが最善の方法です。エフェメラルデバイスをお持ちの場合は、以下を使用しています。

1. udevルールを設定する

デフォルトでは、シリアルデバイスはマウントされているため、ルートユーザーのみがデバイスにアクセスできます。root以外のユーザーが読み取れるように、udevルールを追加する必要があります。

/etc/udev/rules.d/99-serial.rulesという名前のファイルを作成します。そのファイルに次の行を追加します。

KERNEL=="ttyUSB[0-9]*",MODE="0666"

MODE = "0666"は、すべてのユーザーにttyUSBデバイスへの読み取り/書き込み(実行は不可)アクセス許可を与えます。これは最も寛容なオプションであり、セキュリティ要件によってはこれをさらに制限したい場合があります。udevを読んで、デバイスがLinuxゲートウェイに接続されたときに何が起こるかを制御する方法について詳しく知ることができます。

2. / devフォルダにホストからコンテナにマウントします

多くの場合、シリアルデバイスは一時的なものです(いつでもプラグを差し込んだり外したりできます)。このため、直接デバイスまたは/ dev / serialフォルダーにマウントすることはできません。プラグを抜くと、それらが消える可能性があるためです。それらを再び差し込んでデバイスが再び表示されても、技術的にはマウントされたファイルとは異なるファイルであるため、Dockerはそれを認識しません。このため、ホストからコンテナに/ devフォルダ全体をマウントします。これを行うには、Docker runコマンドに次のボリュームコマンドを追加します。

-v /dev:/dev

デバイスが永続的に接続されている場合、-deviceオプションまたはより具体的なボリュームマウントを使用することは、セキュリティの観点からはおそらくより良いオプションです。

3.特権モードでコンテナを実行します

--deviceオプションを使用せず、/ devフォルダー全体にマウントした場合は、コンテナーを特権モードで実行する必要があります(上記のcgroupをチェックして、これを削除できるかどうかを確認します)。これを行うには、Docker runコマンドに次を追加します。

--privileged

4. / dev / serial / by-idフォルダーからデバイスにアクセスします

デバイスを接続したり取り外したりできる場合、Linuxは常に同じttyUSBxxxの場所にマウントされることを保証しません(特に複数のデバイスがある場合)。幸い、Linuxは/ dev / serial / by-idフォルダー内のデバイスへのシンボリックリンクを自動的に作成します。このフォルダ内のファイルには常に同じ名前が付けられます。

これは簡単な要約です。詳細を説明するブログ記事があります。


2

特定のUSBデバイスを、これも特定のDockerコンテナーにバインドするのは困難です。ご覧のとおり、実現するための推奨方法は次のとおりです。

docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash

すべてのデバイスをこのコンテナにバインドします。安全ではありません。すべてのコンテナは、それらすべての操作を許可されています。

別の方法は、devpathによってデバイスをバインドすることです。次のようになります。

docker run -t -i --privileged -v /dev/bus/usb/001/002:/dev/bus/usb/001/002 ubuntu bash

または--device(より良い、いいえprivileged):

docker run -t -i --device /dev/bus/usb/001/002 ubuntu bash

より安全です。しかし、実際には特定のデバイスのdevpathが何であるかを知ることは困難です。

私はこの問題を解決するためにこのレポを書きました。

https://github.com/williamfzc/usb2container

このサーバーをデプロイした後、HTTPリクエストを介して、接続されているすべてのデバイスの情報を簡単に取得できます。

curl 127.0.0.1:9410/api/device

そして得る:

{
    "/devices/pci0000:00/0000:00:14.0/usb1/1-13": {
        "ACTION": "add",
        "DEVPATH": "/devices/pci0000:00/0000:00:14.0/usb1/1-13",
        "DEVTYPE": "usb_device",
        "DRIVER": "usb",
        "ID_BUS": "usb",
        "ID_FOR_SEAT": "xxxxx",
        "ID_MODEL": "xxxxx",
        "ID_MODEL_ID": "xxxxx",
        "ID_PATH": "xxxxx",
        "ID_PATH_TAG": "xxxxx",
        "ID_REVISION": "xxxxx",
        "ID_SERIAL": "xxxxx",
        "ID_SERIAL_SHORT": "xxxxx",
        "ID_USB_INTERFACES": "xxxxx",
        "ID_VENDOR": "xxxxx",
        "ID_VENDOR_ENC": "xxxxx",
        "ID_VENDOR_FROM_DATABASE": "",
        "ID_VENDOR_ID": "xxxxx",
        "INTERFACE": "",
        "MAJOR": "189",
        "MINOR": "119",
        "MODALIAS": "",
        "PRODUCT": "xxxxx",
        "SEQNUM": "xxxxx",
        "SUBSYSTEM": "usb",
        "TAGS": "",
        "TYPE": "0/0/0",
        "USEC_INITIALIZED": "xxxxx",
        "adb_user": "",
        "_empty": false,
        "DEVNAME": "/dev/bus/usb/001/120",
        "BUSNUM": "001",
        "DEVNUM": "120",
        "ID_MODEL_ENC": "xxxxx"
    },
    ...
}

コンテナにバインドします。たとえば、このデバイスのDEVNAMEは次のようになります/dev/bus/usb/001/120

docker run -t -i --device /dev/bus/usb/001/120 ubuntu bash

多分それは役立つでしょう。


0

最新バージョンのdockerでは、これで十分です。

docker run -ti --privileged ubuntu bash

すべてのシステムリソースへのアクセスを提供します(たとえば/ dev内)


2
priviledgedはセキュリティのために使うにはひどいオプションです。
Marc Merlin、

2
Arduino関連のものなどのプログラミングに使用する場合、このソリューションは優れています
Jose Cabrera Zuniga

0

上記の回答に加えて、Docker内ではなく、外部USBデバイス(HDD、フラッシュドライブ)をすばやく使用したい場合 Docker内で機能し、特権モードを使用せをすばやく使用したい場合:

ホスト上のデバイスへのdevpathを見つけます:

sudo fdisk -l

ドライブの容量によって、リストから簡単に認識できます。このパスをコピーします(次の例ではです/dev/sda2)。

Disque /dev/sda2 : 554,5 Go, 57151488 octets, 111624 secteurs
Unités : secteur de 1 × 512 = 512 octets
Taille de secteur (logique / physique) : 512 octets / 512 octets
taille d'E/S (minimale / optimale) : 512 octets / 512 octets

このdevpathをマウントします(推奨/media)。

sudo mount <drive path> /media/<mount folder name>

次に、これをparamとして使用して、次のdocker runようにします。

docker run -it -v /media/<mount folder name>:/media/<mount folder name>

またはdocker composeでボリュームの下に:

services:
  whatevermyserviceis:
    volumes:
      - /media/<mount folder name>:/media/<mount folder name>

そして今、あなたが実行してコンテナに入るとき、あなたはコンテナ内のドライブにアクセスできるはずです /media/<mount folder name>

免責事項:

  1. これはおそらくウェブカメラなどのシリアルデバイスでは機能しません。USBストレージドライブでのみテストしました。
  2. デバイスを定期的に再接続および切断する必要がある場合、この方法は煩わしく、マウントパスをリセットしてコンテナを再起動しない限り機能しません。
  3. ドキュメントで規定されているように私はドッカー17.06 +を使用しました

0

Dockerコンテナーの実行中にプラグインできるUSBデバイスに動的にアクセスする場合、たとえば/ dev / video0で接続されたばかりのUSB Webカメラにアクセスする場合は、コンテナーの起動時にcgroupルールを追加できます。このオプションは--privilegedコンテナを必要とせず、特定のタイプのハードウェアへのアクセスのみを許可します。

ステップ1

追加するデバイスタイプのデバイスメジャー番号を確認します。Linuxカーネルのドキュメントで調べることができます。または、デバイスで確認できます。たとえば、/ dev / video0に接続されているWebカメラのデバイスメジャー番号を確認するには、を実行しls -la /dev/video0ます。これにより、次のような結果になります。

crw-rw----+ 1 root video 81, 0 Jul  6 10:22 /dev/video0

最初の数字(81)はデバイスのメジャー番号です。いくつかの一般的なデバイスのメジャー番号:

  • 81:USBウェブカメラ
  • 188:USBからシリアルへのコンバーター

ステップ2

Dockerコンテナーを起動するときにルールを追加します。

  • 追加する --device-cgroup-rule='c major_number:* rmw'アクセスするすべてのタイプのデバイスにルールをます
  • udev情報へのアクセスを追加して、DockerコンテナがUSBデバイスの詳細情報を取得できるようにします -v /run/udev:/run/udev:ro
  • / devボリュームをdockerコンテナーにマップします -v /dev:/dev

要約

したがって、すべてのusb webcamとserial2usbデバイスをdockerコンテナーに追加するには、次のようにします。

docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.