ครั้งสุดท้ายที่ผมตรวจสอบเทียบท่าไม่ได้มีวิธีการใด ๆ เพื่อให้การเข้าถึงภาชนะเพื่ออนุกรมโฮสต์หรือพอร์ต มีเคล็ดลับที่ช่วยให้ทำเช่นนั้น?
ครั้งสุดท้ายที่ผมตรวจสอบเทียบท่าไม่ได้มีวิธีการใด ๆ เพื่อให้การเข้าถึงภาชนะเพื่ออนุกรมโฮสต์หรือพอร์ต มีเคล็ดลับที่ช่วยให้ทำเช่นนั้น?
คำตอบ:
มีสองตัวเลือก คุณสามารถใช้การ--device
ตั้งค่าสถานะที่ใช้สามารถใช้ในการเข้าถึงอุปกรณ์ USB โดยไม่มี--privileged
โหมด:
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
เป็นที่ไม่ปลอดภัย และควรจะจัดการกับการดูแล
ด้วย Docker รุ่นปัจจุบันคุณสามารถใช้การ--device
ตั้งค่าสถานะเพื่อบรรลุสิ่งที่คุณต้องการโดยไม่จำเป็นต้องให้สิทธิ์การเข้าถึงอุปกรณ์ USB ทั้งหมด
ตัวอย่างเช่นหากคุณต้องการให้/dev/ttyUSB0
เข้าถึงได้เฉพาะภายในคอนเทนเนอร์ Docker ของคุณคุณสามารถทำสิ่งต่อไปนี้:
docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
--device
ตั้งค่าสถานะฉันจะทราบได้อย่างไรว่า/dev/<device>
อุปกรณ์ Android ใดที่เชื่อมโยงกับเครื่องโฮสต์โดยเฉพาะเมื่อใช้ Docker Quickstart Terminal (VirtualBox Host) สำหรับ Windows หรือ Mac
--device
ทำงานได้จนกว่าอุปกรณ์ USB ของคุณจะได้รับการถอดปลั๊ก / เปลี่ยนใหม่แล้วจึงหยุดทำงาน คุณต้องใช้อุปกรณ์ cgroupรับรอบมัน
คุณสามารถใช้-v /dev:/dev
แต่ไม่ปลอดภัยเพราะมันจะจับอุปกรณ์ทั้งหมดจากโฮสต์ของคุณลงในคอนเทนเนอร์รวมถึงอุปกรณ์ดิสก์ดิบและอื่น ๆ โดยทั่วไปสิ่งนี้จะทำให้คอนเทนเนอร์ได้รับรูทบนโฮสต์ซึ่งโดยปกติจะไม่ใช่สิ่งที่คุณต้องการ
การใช้วิธี cgroups ดีกว่าในส่วนนั้นและทำงานบนอุปกรณ์ที่เพิ่มเข้ามาหลังจากที่คอนเทนเนอร์เริ่มทำงาน
ดูรายละเอียดได้ที่นี่: การเข้าถึงอุปกรณ์ 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 รถบัสใหม่และจะไม่ได้รับอนุญาตให้เข้าถึงในคอนเทนเนอร์
189
ต้องเปลี่ยน คำอธิบายของสิ่งที่จะส่งdevices.allow
สามารถพบได้ที่นี่: kernel.org/doc/Documentation/cgroup-v1/devices.txt
ฉันต้องการขยายคำตอบที่ให้ไว้แล้วเพื่อรวมการสนับสนุนสำหรับอุปกรณ์ที่เชื่อมต่อแบบไดนามิกที่ไม่ได้ถ่ายด้วย/dev/bus/usb
และวิธีการทำงานนี้เมื่อใช้โฮสต์ Windows พร้อมกับ boot2docker VM
หากคุณทำงานกับ Windows คุณจะต้องเพิ่มกฎ USB สำหรับอุปกรณ์ที่คุณต้องการให้ Docker เข้าถึงภายในตัวจัดการ VirtualBox ในการทำเช่นนี้คุณสามารถหยุด VM ได้โดยเรียกใช้:
host:~$ docker-machine stop default
เปิดตัวจัดการ VirtualBox และเพิ่มการรองรับ 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
คำสั่งรันนักเทียบท่าจะทำงานกับโฮสต์ Linux ได้เช่นกัน
อีกทางเลือกหนึ่งคือการปรับ udev ซึ่งควบคุมวิธีการติดตั้งอุปกรณ์และสิทธิ์พิเศษ มีประโยชน์ในการอนุญาตการเข้าถึงอุปกรณ์อนุกรมที่ไม่ใช่รูท หากคุณมีอุปกรณ์ที่เชื่อมต่อถาวร--device
ตัวเลือกเป็นวิธีที่ดีที่สุด หากคุณมีอุปกรณ์ชั่วคราวนี่คือสิ่งที่ฉันได้ใช้:
โดยค่าเริ่มต้นอุปกรณ์อนุกรมจะถูกเชื่อมต่อเพื่อให้ผู้ใช้รูทเท่านั้นที่สามารถเข้าถึงอุปกรณ์ได้ เราจำเป็นต้องเพิ่มกฎ udev เพื่อให้ผู้ใช้ที่ไม่ใช่รูทสามารถอ่านได้
สร้างไฟล์ชื่อ /etc/udev/rules.d/99-serial.rules เพิ่มบรรทัดต่อไปนี้ลงในไฟล์:
KERNEL=="ttyUSB[0-9]*",MODE="0666"
MODE = "0666" จะให้สิทธิ์ผู้ใช้ทั้งหมดในการอ่าน / เขียน (แต่ไม่ได้ดำเนินการ) กับอุปกรณ์ ttyUSB ของคุณ นี่เป็นตัวเลือกที่ได้รับอนุญาตมากที่สุดและคุณอาจต้องการ จำกัด ต่อไปนี้ขึ้นอยู่กับข้อกำหนดด้านความปลอดภัยของคุณ คุณสามารถอ่านข้อมูลเพิ่มเติมเกี่ยวกับ udev เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการควบคุมสิ่งที่เกิดขึ้นเมื่อเสียบอุปกรณ์เข้ากับเกตเวย์ Linux
อุปกรณ์ต่อเนื่องมักจะไม่ถาวร (สามารถเสียบและถอดปลั๊กได้ตลอดเวลา) ด้วยเหตุนี้เราจึงไม่สามารถเมานต์ในอุปกรณ์โดยตรงหรือแม้แต่โฟลเดอร์ / dev / serial เพราะสิ่งเหล่านี้อาจหายไปเมื่อสิ่งต่างๆถูกถอดออก แม้ว่าคุณจะเสียบกลับเข้าไปใหม่และอุปกรณ์ก็จะปรากฏขึ้นอีกครั้งในทางเทคนิคแล้วมันเป็นไฟล์ที่แตกต่างจากที่ติดตั้งอยู่ดังนั้น Docker จะไม่เห็นมัน ด้วยเหตุผลนี้เราจึงเมานท์โฟลเดอร์ / dev ทั้งหมดจากโฮสต์ไปยังคอนเทนเนอร์ คุณสามารถทำได้โดยเพิ่มคำสั่งระดับเสียงต่อไปนี้ลงในคำสั่ง Docker run ของคุณ:
-v /dev:/dev
หากอุปกรณ์ของคุณมีการเชื่อมต่ออย่างถาวรจากนั้นใช้ตัวเลือก - อุปกรณ์หรือเมานต์ไดรฟ์ที่เฉพาะเจาะจงมากขึ้นน่าจะเป็นตัวเลือกที่ดีกว่าจากมุมมองด้านความปลอดภัย
หากคุณไม่ได้ใช้ตัวเลือก - อุปกรณ์และติดตั้งในโฟลเดอร์ / dev ทั้งหมดคุณจะต้องเรียกใช้คอนเทนเนอร์เป็นโหมดสิทธิพิเศษ (ฉันจะตรวจสอบสิ่ง cgroup ที่กล่าวถึงด้านบนเพื่อดูว่าสามารถลบได้ ) คุณสามารถทำได้โดยเพิ่มคำสั่งต่อไปนี้ลงในคำสั่งเรียกใช้ Docker ของคุณ:
--privileged
หากอุปกรณ์ของคุณสามารถเสียบและถอดปลั๊กได้ Linux ไม่รับประกันว่าอุปกรณ์นั้นจะติดตั้งในตำแหน่ง ttyUSBxxx เดียวกันเสมอ (โดยเฉพาะถ้าคุณมีอุปกรณ์หลายเครื่อง) โชคดีที่ Linux จะสร้าง symlink ให้กับอุปกรณ์ในโฟลเดอร์ / dev / serial / by-id โดยอัตโนมัติ ไฟล์ในโฟลเดอร์นี้จะมีชื่อเหมือนกันเสมอ
นี่คือบทสรุปด่วนฉันมีบทความบล็อกที่ให้รายละเอียดเพิ่มเติม
เป็นเรื่องยากที่เราจะผูกอุปกรณ์ USB เฉพาะลงใน container 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
ปลอดภัยกว่ามาก แต่จริงๆแล้วมันยากที่จะรู้ว่า devache ของอุปกรณ์เฉพาะคืออะไร
ฉันได้เขียน repo นี้เพื่อแก้ปัญหานี้
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
บางทีมันอาจจะช่วย
ด้วยนักเทียบท่ารุ่นล่าสุดนี่เพียงพอแล้ว:
docker run -ti --privileged ubuntu bash
มันจะให้การเข้าถึงทรัพยากรระบบทั้งหมด (ใน / dev เช่น)
การเพิ่มคำตอบข้างต้นสำหรับผู้ที่ต้องการวิธีที่รวดเร็วในการใช้อุปกรณ์ USB ภายนอก (HDD, แฟลชไดรฟ์) ทำงานภายในตัวเชื่อมต่อและไม่ได้ใช้โหมดพิเศษ:
ค้นหา 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>
จากนั้นคุณสามารถใช้สิ่งนี้เป็นสิ่งที่docker run
ชอบ:
docker run -it -v /media/<mount folder name>:/media/<mount folder name>
หรือในนักเทียบท่าเขียนใต้เล่ม:
services:
whatevermyserviceis:
volumes:
- /media/<mount folder name>:/media/<mount folder name>
และตอนนี้เมื่อคุณเรียกใช้และป้อนคอนเทนเนอร์ของคุณคุณควรจะสามารถเข้าถึงไดรฟ์ภายในคอนเทนเนอร์ที่ /media/<mount folder name>
หมายเหตุ:
หากคุณต้องการเข้าถึงอุปกรณ์ USB ที่สามารถเสียบเข้าไปได้ในขณะที่ตัวเชื่อมต่อคอนเทนเนอร์กำลังทำงานอยู่ตัวอย่างเช่นการเข้าถึงเว็บแคม usb ที่แนบมาที่ / dev / video0 คุณสามารถเพิ่มกฎ cgroup เมื่อเริ่มต้นคอนเทนเนอร์ ตัวเลือกนี้ไม่จำเป็นต้องมี - คอนเทนเนอร์ที่ได้รับการยกเว้นและอนุญาตให้เข้าถึงเฉพาะฮาร์ดแวร์ประเภทใดประเภทหนึ่งเท่านั้น
ตรวจสอบหมายเลขอุปกรณ์ของประเภทอุปกรณ์ที่คุณต้องการเพิ่ม คุณสามารถดูมันขึ้นมาในเอกสารลินุกซ์เคอร์เนล หรือคุณสามารถตรวจสอบอุปกรณ์ของคุณได้ ยกตัวอย่างเช่นในการตรวจสอบจำนวนที่สำคัญอุปกรณ์สำหรับเว็บที่เชื่อมต่อไปยัง / dev / video0 ls -la /dev/video0
คุณสามารถทำ ผลลัพธ์เป็นดังนี้:
crw-rw----+ 1 root video 81, 0 Jul 6 10:22 /dev/video0
โดยที่หมายเลขแรก (81) เป็นหมายเลขหลักของอุปกรณ์ หมายเลขหลักของอุปกรณ์ทั่วไปบางอย่าง:
เพิ่มกฎเมื่อคุณเริ่มคอนเทนเนอร์ docker:
--device-cgroup-rule='c major_number:* rmw'
กฎสำหรับอุปกรณ์ทุกประเภทที่คุณต้องการเข้าถึง-v /run/udev:/run/udev:ro
-v /dev:/dev
ดังนั้นหากต้องการเพิ่มเว็บแคม usb และอุปกรณ์ serial2usb ทั้งหมดลงในคอนเทนเนอร์นักเทียบท่าของคุณให้ทำ:
docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash