Docker - cara untuk memberikan akses ke USB host atau perangkat serial?

Jawaban:

210

Ada beberapa opsi. Anda dapat menggunakan --devicebendera yang dapat digunakan untuk mengakses perangkat USB tanpa --privilegedmode:

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

Atau, dengan asumsi perangkat USB Anda tersedia dengan driver yang berfungsi, dll. Pada host di /dev/bus/usb, Anda dapat memasang ini di wadah menggunakan mode hak istimewa dan opsi volume . Sebagai contoh:

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

Perhatikan bahwa seperti namanya, --privilegedadalah tidak aman dan harus ditangani dengan hati-hati.

Ben Whaley
sumber
4
Tidak perlu -v - hak istimewa sudah berarti akses ke semua perangkat
Seni
14
Apakah ada mekanisme seperti ini untuk klien buruh pelabuhan Windows?
Pascal
Menggunakan solusi ini saya tidak melihat perangkat dari kontainer buruh pelabuhan ... Berikut adalah rincian stackoverflow.com/questions/37213812 masalah saya. Menghargai bantuan apapun! Terima kasih.
kashesandr
2
Masih tidak berfungsi jika perangkat USB terhubung setelah Docker sudah berjalan.
Franklin Dattein
1
Maksud saya, itu tidak memetakan perangkat di bawah / tty / USBX meskipun lsusb dapat mencantumkannya.
Franklin Dattein
80

Dengan versi Docker saat ini, Anda dapat menggunakan --deviceflag untuk mencapai apa yang Anda inginkan, tanpa perlu memberikan akses ke semua perangkat USB.

Misalnya, jika Anda ingin membuatnya hanya /dev/ttyUSB0dapat diakses di dalam container Docker Anda, Anda dapat melakukan sesuatu seperti:

docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
Menandai
sumber
3
perhatikan saja bahwa perangkat tidak dapat menjadi symlink saat ini. github.com/docker/docker/issues/13840
wligtenberg
6
menggunakan --devicebendera, bagaimana cara menentukan /dev/<device>perangkat Android yang terkait di mesin host, terutama saat menggunakan Terminal Quickstart Docker (VirtualBox Host) untuk Windows atau Mac?
DanCat
1
Ini berfungsi dengan baik jika nama perangkat Anda tidak pernah berubah. Tetapi jika Anda menggunakan sesuatu yang dinamis yang menggunakan perangkat dalam / dev / bus / usb maka ini tidak akan berfungsi karena nama perangkat berubah ketika Anda mencolokkan dan mencabutnya. Anda akan membutuhkan solusi -v (volume) di atas.
Brad Grissom
1
Aturan udev @DanCat dapat memastikan bahwa perangkat Anda dipasang ke jalur statis
C. Reed
1
Mengapa ada orang yang tertarik memiliki akses ke hanya satu perangkat usb ?? Perangkat USB dimaksudkan untuk terhubung dan terputus dan itu perlu dilakukan selama runtime aplikasi. USB bukanlah SATA atau semacamnya, Anda tidak dapat mengharapkan sesuatu untuk selalu ada di sana ... Dan menurut saya orang tidak hanya memulai aplikasi melalui buruh pelabuhan untuk satu kali berjalan dan menutupnya segera setelah perangkat usb dicabut, bukan? Saya membayangkan lebih seperti aplikasi jenis layanan, bukan stoples tunggal ... Tapi terima kasih, memang itu mungkin membantu beberapa yang sesuai dengan skenario yang sangat terbatas itu
Arturas M
20

--devicebekerja sampai perangkat USB Anda dicabut / dicolokkan dan kemudian berhenti bekerja. Anda harus menggunakan perangkat cgroup. Izinkan untuk menyiasatinya.
Anda bisa saja menggunakan -v /dev:/devtapi itu tidak aman karena memetakan semua perangkat dari host Anda ke dalam wadah, termasuk perangkat disk mentah dan sebagainya. Pada dasarnya ini memungkinkan container untuk mendapatkan root pada host, yang biasanya bukan yang Anda inginkan.
Menggunakan pendekatan cgroups lebih baik dalam hal itu dan berfungsi pada perangkat yang ditambahkan setelah penampung saat dimulai.

Lihat detailnya di sini: Mengakses Perangkat USB Di Docker tanpa menggunakan --privileged

Agak sulit untuk menempelkannya, tetapi secara singkat, Anda perlu mendapatkan nomor mayor untuk perangkat karakter Anda dan mengirimkannya ke cgroup:

189 adalah angka utama dari / dev / ttyUSB *, yang bisa Anda dapatkan dengan 'ls -l'. Ini mungkin berbeda di sistem Anda dari pada milik saya:

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

Kemudian mulai wadah Anda seperti ini:

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

tanpa melakukan ini, perangkat yang baru dicolokkan atau di-boot ulang setelah penampung dimulai, akan mendapatkan ID bus baru dan tidak akan diizinkan akses di penampung.

Marc Merlin
sumber
7
Kepada orang-orang yang menyukai ini, tolong bantu dan katakan apa yang ingin Anda tingkatkan. Saya menulis halaman ini untuk membantu orang lain yang mengalami masalah yang kami lakukan. Saya akan sedikit jujur ​​dengan mengatakan bahwa saya dimatikan untuk mencoba berbagi kembali dan membantu orang-orang di stackoverflow juga: - /
Marc Merlin
Jika Anda membaca jawaban saya, Anda akan melihat bahwa menambahkan volume '-v / dev: / dev' akan memberikan akses ke perangkat yang terhubung secara dinamis.
rrpilot
5
rrpilot: -v / dev: / dev memberi Anda semua / dev, termasuk / dev / sda dan hal-hal lain yang benar-benar tidak ingin Anda tunjukkan ke pengguna root di container. Dengan kata lain, solusi Anda berhasil, tetapi tidak aman. Punyaku mengatasi masalah itu. Saya akan mengedit jawaban saya untuk menunjukkan itu.
Marc Merlin
2
Jawabannya bisa diperbaiki dengan menunjukkan bagaimana cara mendapatkan bilangan mayor dan klarifikasi yang 189harus diganti. Penjelasan tentang apa yang harus dikirim devices.allowdapat ditemukan di sini: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Craig Younkins
2
Ada fitur baru dari Docker yang membuat ini sedikit lebih sederhana: "--device-cgroup-rule" ( docs.docker.com/engine/reference/commandline/create/… )
tianon
16

Saya ingin memperluas jawaban yang sudah diberikan untuk menyertakan dukungan untuk perangkat yang terhubung secara dinamis yang tidak ditangkap dengan /dev/bus/usbdan cara membuatnya berfungsi saat menggunakan host Windows bersama dengan VM boot2docker.

Jika Anda bekerja dengan Windows, Anda harus menambahkan aturan USB apa pun untuk perangkat yang Anda ingin akses Docker dalam manajer VirtualBox. Untuk melakukan ini, Anda dapat menghentikan VM dengan menjalankan:

host:~$ docker-machine stop default

Buka VirtualBox Manager dan tambahkan dukungan USB dengan filter sesuai kebutuhan.

Mulai VM boot2docker:

host:~$ docker-machine start default

Karena perangkat USB terhubung ke VM boot2docker, perintah harus dijalankan dari mesin itu. Buka terminal dengan VM dan jalankan perintah jalankan buruh pelabuhan:

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

Catatan, ketika perintah dijalankan seperti ini, maka hanya perangkat USB yang terhubung sebelumnya yang akan ditangkap. Bendera volume hanya diperlukan jika Anda ingin ini bekerja dengan perangkat yang terhubung setelah penampung dimulai. Dalam hal ini, Anda dapat menggunakan:

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

Catatan, saya harus menggunakan /devalih-alih /dev/bus/usbdalam beberapa kasus untuk menangkap perangkat seperti /dev/sg2. Saya hanya dapat berasumsi bahwa hal yang sama berlaku untuk perangkat seperti /dev/ttyACM0atau /dev/ttyUSB0.

Perintah menjalankan buruh pelabuhan akan bekerja dengan host Linux juga.

rrpilot.dll
sumber
1
Poin bagus dalam pemasangan / dev: / dev sebagai gantinya. Itu memberi lebih banyak fleksibilitas dalam hal menangkap perangkat lain, dan juga membantu dengan elemen dinamis.
kotakotakota
dan juga membahayakan keamanan dan isolasi mesin host Anda.
Exadra37
1
@ Exadra37 Memang ... dan jika itu penting dalam aplikasi Anda, Anda tidak boleh menggunakan ini. Namun, penting untuk dicatat ada beberapa aplikasi di mana Anda tidak peduli dan tidak menggunakan buruh pelabuhan untuk isolasi. Dalam kasus khusus saya, Anda dapat menjalankan aplikasi Linux terpaket di Windows.
rrpilot
5

Jika Anda ingin mengakses perangkat USB secara dinamis yang dapat dicolokkan saat penampung buruh pelabuhan sudah berjalan, misalnya mengakses webcam usb yang baru saja terpasang di / dev / video0, Anda dapat menambahkan aturan cgroup saat memulai penampung. Opsi ini tidak memerlukan kontainer --privileged dan hanya mengizinkan akses ke jenis perangkat keras tertentu.

Langkah 1

Periksa nomor utama perangkat dari jenis perangkat yang ingin Anda tambahkan. Anda dapat mencarinya di dokumentasi kernel linux . Atau Anda dapat memeriksanya untuk perangkat Anda. Misalnya untuk memeriksa nomor utama perangkat untuk webcam yang terhubung ke / dev / video0, Anda dapat melakukan ls -la /dev/video0. Ini menghasilkan sesuatu seperti:

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

Dimana angka pertama (81) adalah angka utama perangkat. Beberapa nomor utama perangkat umum:

  • 81: webcam usb
  • 188: usb ke konverter serial

Langkah 2

Tambahkan aturan saat Anda memulai container buruh pelabuhan:

  • Tambahkan --device-cgroup-rule='c major_number:* rmw'aturan untuk setiap jenis perangkat yang ingin Anda akses
  • Tambahkan akses ke informasi udev sehingga kontainer buruh pelabuhan bisa mendapatkan info lebih lanjut tentang perangkat usb Anda dengan -v /run/udev:/run/udev:ro
  • Petakan / dev volume ke kontainer buruh pelabuhan Anda dengan -v /dev:/dev

Bungkus

Jadi untuk menambahkan semua webcam usb dan perangkat serial2usb ke container docker Anda, lakukan:

docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash
Wout_bb
sumber
2

Pilihan lainnya adalah menyesuaikan udev, yang mengontrol bagaimana perangkat dipasang dan dengan hak istimewa apa. Berguna untuk mengizinkan akses non-root ke perangkat serial. Jika Anda memiliki perangkat yang terpasang secara permanen, --deviceopsinya adalah cara terbaik untuk pergi. Jika Anda memiliki perangkat singkat, inilah yang telah saya gunakan:

1. Tetapkan aturan udev

Secara default, perangkat serial dipasang sehingga hanya pengguna root yang dapat mengakses perangkat. Kita perlu menambahkan aturan udev agar dapat dibaca oleh pengguna non-root.

Buat file bernama /etc/udev/rules.d/99-serial.rules. Tambahkan baris berikut ke file itu:

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

MODE = "0666" akan memberikan izin baca / tulis (tetapi tidak mengeksekusi) ke perangkat ttyUSB Anda kepada semua pengguna. Ini adalah opsi yang paling permisif, dan Anda mungkin ingin membatasinya lebih lanjut tergantung pada persyaratan keamanan Anda. Anda dapat membaca di udev untuk mempelajari lebih lanjut tentang mengontrol apa yang terjadi ketika perangkat dicolokkan ke gateway Linux.

2. Pasang folder / dev dari host ke container

Perangkat serial sering kali bersifat sementara (dapat dicolokkan dan dicabut setiap saat). Karena itu, kami tidak dapat memasang di perangkat langsung atau bahkan folder / dev / serial, karena folder tersebut dapat hilang ketika ada yang dicabut. Bahkan jika Anda menyambungkannya kembali dan perangkat muncul lagi, secara teknis itu adalah file yang berbeda dari yang dipasang, jadi Docker tidak akan melihatnya. Untuk alasan ini, kami memasang seluruh folder / dev dari host ke container. Anda dapat melakukan ini dengan menambahkan perintah volume berikut ke perintah jalankan Docker Anda:

-v /dev:/dev

Jika perangkat Anda terpasang secara permanen, menggunakan opsi --device atau pemasangan volume yang lebih spesifik kemungkinan merupakan opsi yang lebih baik dari perspektif keamanan.

3. Jalankan wadah dalam mode hak istimewa

Jika Anda tidak menggunakan opsi --device dan dipasang di seluruh / dev folder, Anda akan diminta untuk menjalankan kontainer dalam mode privileged (saya akan memeriksa hal-hal cgroup yang disebutkan di atas untuk melihat apakah ini dapat dihapus ). Anda dapat melakukan ini dengan menambahkan yang berikut ini ke perintah jalankan Docker Anda:

--privileged

4. Akses perangkat dari folder / dev / serial / by-id

Jika perangkat Anda dapat dicolokkan dan dicabut, Linux tidak menjamin perangkat akan selalu dipasang di lokasi ttyUSBxxx yang sama (terutama jika Anda memiliki banyak perangkat). Untungnya, Linux akan membuat symlink secara otomatis ke perangkat di folder / dev / serial / by-id. File dalam folder ini akan selalu diberi nama yang sama.

Ini adalah ikhtisar singkat, saya memiliki artikel blog yang menjelaskan lebih detail.

BadCanyon
sumber
2

Sulit bagi kami untuk mengikat perangkat USB tertentu ke wadah buruh pelabuhan yang juga spesifik. Seperti yang Anda lihat, cara yang disarankan untuk mencapainya adalah:

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

Ini akan mengikat semua perangkat ke wadah ini. Tidak aman. Setiap kontainer diberikan untuk mengoperasikan semuanya.

Cara lain adalah mengikat perangkat dengan devpath. Ini mungkin terlihat seperti:

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

atau --device(lebih baik, tidak privileged):

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

Jauh lebih aman. Tetapi sebenarnya sulit untuk mengetahui apa itu devpath perangkat tertentu.

Saya telah menulis repo ini untuk mengatasi masalah ini.

https://github.com/williamfzc/usb2container

Setelah menerapkan server ini, Anda dapat dengan mudah mendapatkan semua informasi perangkat yang terhubung melalui permintaan HTTP:

curl 127.0.0.1:9410/api/device

dan dapatkan:

{
    "/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"
    },
    ...
}

dan mengikatnya ke wadah Anda. Misalnya, Anda dapat melihat DEVNAME perangkat ini adalah /dev/bus/usb/001/120:

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

Mungkin itu akan membantu.

williamfzc.dll
sumber
1

Dengan versi buruh pelabuhan terbaru, ini sudah cukup:

docker run -ti --privileged ubuntu bash

Ini akan memberikan akses ke semua sumber daya sistem (dalam / dev misalnya)

Thomas Grimault
sumber
2
priviledged adalah pilihan yang buruk untuk digunakan untuk keamanan, meskipun ya, itu berhasil.
Marc Merlin
2
Jika digunakan untuk memprogram hal-hal seperti hal-hal terkait Arduino, solusi ini bagus
Jose Cabrera Zuniga
0

Menambah jawaban di atas, bagi yang ingin cara cepat menggunakan perangkat USB eksternal (HDD, flash drive) yang berfungsi di dalam buruh pelabuhan, dan tidak menggunakan mode priviledged:

Temukan devpath ke perangkat Anda di host:

sudo fdisk -l

Anda dapat mengenali drive Anda berdasarkan kapasitasnya dengan mudah dari daftar. Salin jalur ini (untuk contoh berikut /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

Pasang jalur dev ini (lebih disukai /media):

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

Anda kemudian dapat menggunakan ini sebagai parameter untuk docker runmenyukai:

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

atau di buruh pelabuhan menulis di bawah volume:

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

Dan sekarang ketika Anda menjalankan dan memasuki penampung Anda, Anda harus dapat mengakses drive di dalam penampung di /media/<mount folder name>

PENOLAKAN:

  1. Ini mungkin tidak akan bekerja untuk perangkat serial seperti webcam dll. Saya hanya menguji ini untuk drive penyimpanan USB.
  2. Jika Anda perlu menyambungkan kembali dan memutuskan perangkat secara teratur, metode ini akan mengganggu, dan juga tidak akan berfungsi kecuali Anda mengatur ulang jalur pemasangan dan memulai ulang penampung.
  3. Saya menggunakan buruh pelabuhan 17.06 + seperti yang ditentukan dalam dokumen
toing_toing
sumber