Kiedy ostatnio sprawdzałem, Docker nie miał żadnych środków, aby dać kontenerowi dostęp do portu szeregowego lub USB hosta . Czy jest jakaś sztuczka, która na to pozwala?
Kiedy ostatnio sprawdzałem, Docker nie miał żadnych środków, aby dać kontenerowi dostęp do portu szeregowego lub USB hosta . Czy jest jakaś sztuczka, która na to pozwala?
Odpowiedzi:
Jest kilka opcji. Możesz użyć --deviceflagi, która może użyć, aby uzyskać dostęp do urządzeń USB bez --privilegedtrybu:
docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
Alternatywnie, zakładając, że twoje urządzenie USB jest dostępne z działającymi sterownikami itp. Na hoście w /dev/bus/usb, możesz to zamontować w kontenerze przy użyciu trybu uprzywilejowanego i opcji woluminów . Na przykład:
docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash
Zauważ, że jak sama nazwa wskazuje, --privilegedjest niepewny i należy obchodzić się z nim ostrożnie.
W obecnych wersjach Dockera możesz użyć --deviceflagi, aby osiągnąć to, co chcesz, bez konieczności udzielania dostępu do wszystkich urządzeń USB.
Na przykład, jeśli chcesz, aby był /dev/ttyUSB0dostępny tylko w kontenerze Docker, możesz zrobić coś takiego:
docker run -t -i --device=/dev/ttyUSB0 ubuntu bash
--deviceflagi, jak określić, które /dev/<device>z urządzeń z systemem Android jest skojarzone z hostem, zwłaszcza w przypadku korzystania z terminala Docker Quickstart (Host VirtualBox) dla systemu Windows lub Mac?
--devicedziała do momentu odłączenia / ponownego podłączenia urządzenia USB, a następnie przestaje działać. Musisz użyć urządzeń cgroup .allow ominąć to.
Możesz po prostu użyć, -v /dev:/devale jest to niebezpieczne, ponieważ mapuje wszystkie urządzenia z twojego hosta do kontenera, w tym surowe urządzenia dyskowe i tak dalej. Zasadniczo umożliwia to kontenerowi uzyskanie roota na hoście, co zwykle nie jest tym, czego chcesz.
Korzystanie z podejścia cgroups jest lepsze pod tym względem i działa na urządzeniach, które są dodawane po uruchomieniu kontenera.
Zobacz szczegóły tutaj: Dostęp do urządzeń USB w Dockerze bez użycia --privileged
Trochę trudno to wkleić, ale w skrócie, musisz zdobyć główny numer urządzenia postaci i wysłać go do cgroup:
189 to główna liczba / dev / ttyUSB *, którą można uzyskać za pomocą 'ls -l'. W Twoim systemie może wyglądać inaczej niż w moim:
root@server:~# echo 'c 189:* rwm' > /sys/fs/cgroup/devices/docker/$A*/devices.allow
(A contains the docker containerID)
Następnie uruchom kontener w ten sposób:
docker run -v /dev/bus:/dev/bus:ro -v /dev/serial:/dev/serial:ro -i -t --entrypoint /bin/bash debian:amd64
bez tego każde nowo podłączone lub ponownie uruchomione urządzenie po uruchomieniu kontenera otrzyma nowy identyfikator magistrali i nie będzie miało dostępu do kontenera.
189należy go zastąpić. Opis tego, co należy wysłać, devices.allowmożna znaleźć tutaj: kernel.org/doc/Documentation/cgroup-v1/devices.txt
Chciałem rozszerzyć odpowiedzi już udzielone, aby uwzględnić obsługę dynamicznie podłączonych urządzeń, które nie są przechwytywane, /dev/bus/usbi jak to działa, gdy używam hosta Windows wraz z maszyną wirtualną boot2docker.
Jeśli pracujesz z systemem Windows, musisz dodać reguły USB dla urządzeń, do których chcesz mieć dostęp Docker w menedżerze VirtualBox. Aby to zrobić, możesz zatrzymać maszynę wirtualną, uruchamiając:
host:~$ docker-machine stop default
Otwórz VirtualBox Manager i dodaj obsługę USB z filtrami zgodnie z wymaganiami.
Uruchom maszynę wirtualną boot2docker:
host:~$ docker-machine start default
Ponieważ urządzenia USB są podłączone do maszyny wirtualnej boot2docker, polecenia muszą być uruchamiane z tej maszyny. Otwórz terminal z maszyną wirtualną i uruchom polecenie docker run:
host:~$ docker-machine ssh
docker@default:~$ docker run -it --privileged ubuntu bash
Uwaga, gdy polecenie zostanie uruchomione w ten sposób, przechwycone zostaną tylko wcześniej podłączone urządzenia USB. Flaga woluminów jest wymagana tylko wtedy, gdy chcesz, aby działała z urządzeniami podłączonymi po uruchomieniu kontenera. W takim przypadku możesz użyć:
docker@default:~$ docker run -it --privileged -v /dev:/dev ubuntu bash
Uwaga, w niektórych przypadkach musiałem użyć /devzamiast tego, /dev/bus/usbaby przechwycić urządzenie takie jak /dev/sg2. Mogę tylko założyć, że to samo dotyczy urządzeń takich jak /dev/ttyACM0lub /dev/ttyUSB0.
Polecenia uruchamiania dockera będą działać również z hostem Linux.
Inną opcją jest dostosowanie udev, który kontroluje sposób montowania urządzeń i jakie uprawnienia. Przydatne, aby umożliwić innym użytkownikom dostęp do urządzeń szeregowych. Jeśli masz urządzenia podłączone na stałe, ta --deviceopcja jest najlepszym rozwiązaniem. Jeśli masz urządzenia efemeryczne, oto czego używam:
Domyślnie urządzenia szeregowe są montowane tak, aby tylko użytkownicy root mieli dostęp do urządzenia. Musimy dodać regułę udev, aby były czytelne dla użytkowników innych niż root.
Utwórz plik o nazwie /etc/udev/rules.d/99-serial.rules. Dodaj następujący wiersz do tego pliku:
KERNEL=="ttyUSB[0-9]*",MODE="0666"
MODE = "0666" da wszystkim użytkownikom uprawnienia do odczytu / zapisu (ale nie wykonywania) na urządzeniach ttyUSB. Jest to najbardziej dopuszczalna opcja i możesz chcieć ją jeszcze bardziej ograniczyć w zależności od wymagań bezpieczeństwa. Możesz przeczytać o udev, aby dowiedzieć się więcej o kontrolowaniu tego, co się dzieje, gdy urządzenie jest podłączone do bramy Linuksa.
Urządzenia szeregowe są często efemeryczne (można je podłączać i odłączać w dowolnym momencie). Z tego powodu nie możemy zamontować w urządzeniu bezpośrednim ani nawet w folderze / dev / serial, ponieważ mogą one zniknąć po odłączeniu urządzeń. Nawet jeśli podłączysz je ponownie, a urządzenie pojawi się ponownie, technicznie rzecz biorąc, jest to inny plik niż ten, który został zamontowany, więc Docker go nie zobaczy. Z tego powodu montujemy cały folder / dev z hosta do kontenera. Możesz to zrobić, dodając następujące polecenie głośności do polecenia uruchamiania platformy Docker:
-v /dev:/dev
Jeśli urządzenie jest podłączone na stałe, użycie opcji --device lub bardziej szczegółowego podłączenia woluminu jest prawdopodobnie lepszą opcją z punktu widzenia bezpieczeństwa.
Jeśli nie użyłeś opcji --device i zamontowano w całym folderze / dev, będziesz musiał uruchomić kontener w trybie uprzywilejowanym (mam zamiar sprawdzić wspomniane powyżej rzeczy cgroup aby sprawdzić czy da się to usunąć ). Możesz to zrobić, dodając następujące polecenie do polecenia uruchamiania platformy Docker:
--privileged
Jeśli twoje urządzenie można podłączyć i odłączyć, Linux nie gwarantuje, że będzie zawsze zamontowane w tej samej lokalizacji ttyUSBxxx (zwłaszcza jeśli masz wiele urządzeń). Na szczęście Linux automatycznie utworzy dowiązanie symboliczne do urządzenia w folderze / dev / serial / by-id. Plik w tym folderze zawsze będzie miał taką samą nazwę.
To jest krótkie podsumowanie, mam artykuł na blogu, który zawiera więcej szczegółów.
Trudno nam powiązać określone urządzenie USB z kontenerem docker, który również jest specyficzny. Jak widać, zalecanym sposobem osiągnięcia tego celu jest:
docker run -t -i --privileged -v /dev/bus/usb:/dev/bus/usb ubuntu bash
Spowoduje to powiązanie wszystkich urządzeń z tym kontenerem. To niebezpieczne. Do obsługi wszystkich przyznano każdy kontener.
Innym sposobem jest wiązanie urządzeń przez devpath. Może to wyglądać tak:
docker run -t -i --privileged -v /dev/bus/usb/001/002:/dev/bus/usb/001/002 ubuntu bash
lub --device(lepiej nie privileged):
docker run -t -i --device /dev/bus/usb/001/002 ubuntu bash
Bezpieczniejsze. Ale tak naprawdę trudno jest wiedzieć, jaka jest ścieżka devpath konkretnego urządzenia.
Napisałem to repozytorium, aby rozwiązać ten problem.
https://github.com/williamfzc/usb2container
Po wdrożeniu tego serwera możesz łatwo uzyskać informacje o wszystkich podłączonych urządzeniach za pośrednictwem żądania HTTP:
curl 127.0.0.1:9410/api/device
i dostać:
{
"/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"
},
...
}
i przywiąż je do swoich pojemników. Na przykład możesz zobaczyć DEVNAME tego urządzenia /dev/bus/usb/001/120:
docker run -t -i --device /dev/bus/usb/001/120 ubuntu bash
Może to pomoże.
Przy najnowszych wersjach dockera to wystarczy:
docker run -ti --privileged ubuntu bash
Zapewni dostęp do wszystkich zasobów systemowych (na przykład w / dev)
Dodając do powyższych odpowiedzi, dla tych, którzy chcą w szybki sposób korzystać z zewnętrznego urządzenia USB (HDD, pendrive) pracującego wewnątrz dockera, a nie korzystających z trybu uprzywilejowanego:
Znajdź devpath do swojego urządzenia na hoście:
sudo fdisk -l
Możesz łatwo rozpoznać swój dysk po jego pojemności na liście. Skopiuj tę ścieżkę (w poniższym przykładzie jest to /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
Zamontuj tę devpath (najlepiej /media):
sudo mount <drive path> /media/<mount folder name>
Możesz następnie użyć tego jako parametru do polubienia docker run:
docker run -it -v /media/<mount folder name>:/media/<mount folder name>
lub w docker compose under volume:
services:
whatevermyserviceis:
volumes:
- /media/<mount folder name>:/media/<mount folder name>
A teraz, gdy uruchomisz i wejdziesz do kontenera, powinieneś mieć dostęp do dysku wewnątrz kontenera pod adresem /media/<mount folder name>
ZRZECZENIE SIĘ:
Jeśli chcesz dynamicznie uzyskiwać dostęp do urządzeń USB, które można podłączyć, gdy kontener docker jest już uruchomiony, na przykład uzyskać dostęp do właśnie podłączonej kamery internetowej USB pod adresem / dev / video0, możesz dodać regułę cgroup podczas uruchamiania kontenera. Ta opcja nie wymaga --przywilejowanego kontenera i zezwala tylko na dostęp do określonych typów sprzętu.
Sprawdź numer główny urządzenia typu urządzenia, które chcesz dodać. Możesz to sprawdzić w dokumentacji jądra Linuksa . Lub możesz to sprawdzić dla swojego urządzenia. Na przykład, aby sprawdzić główny numer urządzenia dla kamery internetowej podłączonej do / dev / video0, możesz wykonać ls -la /dev/video0. Powoduje to coś takiego:
crw-rw----+ 1 root video 81, 0 Jul 6 10:22 /dev/video0
Gdzie pierwsza liczba (81) to główny numer urządzenia. Niektóre popularne numery główne urządzeń:
Dodaj reguły po uruchomieniu kontenera Dockera:
--device-cgroup-rule='c major_number:* rmw'regułę dla każdego typu urządzenia, do którego chcesz uzyskać dostęp-v /run/udev:/run/udev:ro-v /dev:/devAby więc dodać wszystkie kamery internetowe USB i urządzenia serial2usb do kontenera Docker, wykonaj:
docker run -it -v /dev:/dev --device-cgroup-rule='c 188:* rmw' --device-cgroup-rule='c 81:* rmw' ubuntu bash