VirtualBox
Docker
docker-machine

DockerコンテナからUSBデバイスを利用する


はじめに

Dockerゲスト(コンテナ)OSにLinuxを利用したい場合、DockerホストOSはLinuxでなければならない。その為、Docker for MacではmacOS上に仮想マシンを用意し、その上に軽量のLinuxOSを動作させる。

しかしデフォルトで用意されているハイパーバイザ(HyperKit)はホストOS(macOS/Windows)で認識しているUSBデバイスを認識させることができない。Dockerはこのハイパーバイザを変更することができるため、ホストOSのUSBデバイスを認識できるハイパーバイザであるVirtualBoxを利用してDockerコンテナにUSBデバイスを認識させる。


環境

以下の環境で検証した。

% vboxmanage --version

6.0.8r130520

% docker --version
Docker version 18.09.2, build 6247962

% docker-machine --version
docker-machine version 0.16.1, build cce350d7


概要

以下の手順でDockerコンテナにUSB機器を認識させる。


  1. VirtualBox+拡張パックインストール

  2. DockerホストOS用仮想マシン(DockerVM)作成

  3. DockerVMにUSBを認識させる為の設定追加

  4. DockerホストOSでUSBを認識していることを確認

  5. DockerコンテナOSで認識できていることを確認


1. VirtualBox+拡張パックインストール

以下のURLにアクセスし、最新のバイナリを取得、インストールする。

Downloads – Oracle VM VirtualBox

2019-06-12現在の最新は以下が最新。


  • VirtualBox 6.0.8 platform packages

  • VirtualBox 6.0.8 Oracle VM VirtualBox Extension Pack


2. DockerホストOS用仮想マシン(DockerVM)作成

DockerホストOS用仮想マシンをdocker-machineコマンドで作成する。

% docker-machine create -d virtualbox docker-host-default


3. DockerVMにUSBを認識させる為の設定追加

このセクションでは、手順を汎用的かつ簡略化するために、設定の1つである「USB Device Filter」に条件が空のフィルターを登録している。

このフィルターを登録することで、DockerホストOS側で全てのUSB機器を認識できる。

但し、使用しているPCで複数のUSBデバイスを利用している場合、USB機器を抜き差ししたタイミングなどでDockerホストOSに権限を奪われてしまうため、意図せずホストOS側でUSB機器が利用できなくなる。よって、環境に応じてフィルタは適切に設定することを推奨する。

フィルタに条件に設定する場合は、USB機器の情報(例えばVendorIdやProductId)を % vboxmanage list usbhost で確認する。macOSであれば % system_profiler SPUSBDataType でも確認できる。


vboxmanageコマンド (CLI) で設定

% docker-machine stop docker-host-default

Stopping "docker-host-default"...
Machine "docker-host-default" was stopped.

% vboxmanage modifyvm docker-host-default --usb on
% vboxmanage modifyvm docker-host-default --usbehci on
% vboxmanage usbfilter add 0 --target docker-host-default --name 'All Devices'

% docker-machine start docker-host-default


VirtualBox Manager (GUI) で設定


  1. docker-machineコマンドでVMを停止する。

  2. VM(docker-host-default) > Settings > Ports > USB の設定画面で以下のチェックボックスを有効にする。


    • Enable USB Controller

    • USB 2.0 (EHCI) Controller



  3. 同画面の「USB Device Filters」の右の新規作成アイコンを押下し、条件が空のフィルターを作成する。

  4. フィルタが作成されたら、当該デバイスフィルタをダブルクリックし、名前を「All Devices」に変更する。

  5. docker-machineコマンドでVMを起動する。


4. DockerホストOSでUSBを認識していることを確認

% docker-machine ssh docker-host-default

( '>')
/) TC (/ Core is distributed with ABSOLUTELY NO WARRANTY.
(/-_--_-/) www.tinycorelinux.net

docker@docker-host-default:~$ udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

※機器をPCに接続すると以下のようなメッセージが出力されることを確認する。
※例として接続したデバイスはUSBシリアル通信機器。


KERNEL[4332.894758] add /devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/ttyUSB0 (usb-serial)

UDEV [4332.897138] add /devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/ttyUSB0 (usb-serial)

KERNEL[4332.910588] bind /devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/ttyUSB0 (usb-serial)

UDEV [4332.914260] bind /devices/pci0000:00/0000:00:06.0/usb2/2-1/2-1:1.0/ttyUSB0 (usb-serial)

^C (確認できたらCtrl+Cでモニタリング終了)

接続が確認できたら、対応するデバイスファイルが存在することも確認し、ログアウトする。

複数のUSBシリアルデバイスを接続している場合は、ttyUSBXのXの部分の数字が異なる場合があるため注意する。

docker@docker-host-default:~$ ls -l /dev/ttyUSB0

crw-rw---- 1 root staff 188, 0 Jun 12 06:32 /dev/ttyUSB0

docker@docker-host-default:~$ exit
logout

%


5. DockerコンテナOSで認識できていることを確認

まずはじめに、dockerコマンドが先ほど作成したDockerVMを利用できるようにするために環境設定を行う。

DockerイメージやコンテナはDockerVM毎に別々に管理されているため、

このコマンドを忘れるとデフォルトのHyperkitを利用したDockerコンテナを起動することになるので注意する。

% eval $(docker-machine env docker-host-default)

続いて、DockerコンテナOSで確認するために適当なLinuxOSイメージを取得する。

% docker pull debian:9.9-slim

9.9-slim: Pulling from library/debian
fc7181108d40: Pull complete
Digest: sha256:9490c476443a3869e39c2897fa66c91daf5dcbbfca53c976dac7bbdc45775b28
Status: Downloaded newer image for debian:9.9-slim

USB機器を接続し、コンテナを起動する。

その際 --device でDockerホストOSが認識しているデバイスファイルをDockerコンテナOS上で読み書き可能にする。

% docker run --rm --device /dev/ttyUSB0 -it debian:9.9-slim /bin/bash

root@2a8988dafd77:/# ls -l /dev/ttyUSB0
crw-rw---- 1 root staff 188, 0 Jun 12 05:46 /dev/ttyUSB0
root@2a8988dafd77:/# exit
exit

USB機器を接続していない場合は以下のようにエラーが出力される。

% docker run --rm --device /dev/ttyUSB0 -it debian:9.9-slim /bin/bash

docker: Error response from daemon: linux runtime spec devices: error gathering device information while adding custom device "/dev/ttyUSB0": no such file or directory.
ERRO[0000] error waiting for container: context canceled


おわりに

USB Device Fileterの設定を検証している際、ホストOS側で認識していたUSB機器を抜き差しすることでホストOS側から機器が利用できなくなったり、フィルタの設定を変更しても、DockerホストOSが起動しているVMを再起動しないとそれが反映されなかったりと、設定の影響を確認するのに手間取った。

また記事に直接関係ないが、DockerホストOSでシステムの情報を確認しようとすると、OSがTinycorelinuxだったり、基本的なコマンドがGNU版ではなくBusyBoxだったりして、少し戸惑った。BusyBoxは調べてみると歴史は古いようで、Linuxの奥深さに触れるいい機会になった。

macOSでしか検証していないけど、おそらくWindowsでも同じ手順で認識させることができそう。


参考