Подтвердить что ты не робот

Докер для графических сред?

Проблема

У меня есть набор клиентских машин, которые являются частью корпоративного веб-приложения. Каждая машина запускает идентичное программное обеспечение, которое является веб-клиентом на основе PyQT, который подключается к серверу. Это клиентское программное обеспечение регулярно обновляется, и я хотел бы иметь некоторый инструмент настройки/обеспечения, который позволяет иметь одну и ту же среду на каждом компьютере и, следовательно, обеспечивать легкое развертывание и настройку программного обеспечения на каждой из машин клиентов.

Проблема в том, что я пытался использовать шеф-повара, но для того, чтобы фактически поддерживать знания и навыки шеф-повара (у нас нет специального парня Ops), требуется немало усилий, и, кроме того, рецепт Chef может потерпеть неудачу, если какой-либо сторонний репозиторий больше недоступен (это главный пробник).

Я хотел бы попробовать Docker для решения проблемы, но я до сих пор не знаю, если можно настроить изображения/контейнеры, которые позволяют использовать некоторые графические интерфейсы программного обеспечения для работы.

Вопрос

Можно ли использовать Docker для разработки/создания среды для приложения на основе графического интерфейса (PyQt/QT)? Если да, каковы будут первые шаги для этого?

4b9b3361

Ответ 1

В настоящее время на этот вопрос нет ответа, но он очень высоко оценивается в Google. Другие ответы в основном правильные, но с некоторыми оговорками, которые я усвоил трудным путем, и я хотел бы избавить других от неприятностей.

Ответ, данный Nasser Alshammari, является самым простым (и самым быстрым) подходом к запуску приложений GTK в контейнере Docker - просто смонтируйте сокет для X-сервера в качестве тома Docker и попросите Docker использовать его вместо этого.

docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY TheImage

(Я бы также рекомендовал передать -u <username-within-container>, так как запуск приложений X11 от имени root не всегда работает, и, как правило, не рекомендуется, особенно при совместном использовании сеансов).

Это будет работать для приложений, таких как xterm, а также для приложений на основе GTK. Например, если вы попробуете это с Firefox (который основан на GTK), он будет работать (обратите внимание, что если вы уже запускаете Firefox на хосте, он откроет новое окно на хосте, а не откроет новый экземпляр Firefox изнутри контейнера).

Тем не менее, ваш ответ касается конкретно PyQT. Оказывается, что Qt не поддерживает совместное использование сеансов X таким образом (или, по крайней мере, не поддерживает это хорошо).

Если вы попытаетесь запустить приложение на основе QT таким образом, вы, вероятно, получите ошибку, подобную следующей:

X Error: BadAccess (attempt to access private resource denied) 10
  Extension:    140 (MIT-SHM)
  Minor opcode: 1 (X_ShmAttach)
  Resource id:  0x12d
X Error: BadShmSeg (invalid shared segment parameter) 148
  Extension:    140 (MIT-SHM)
  Minor opcode: 5 (X_ShmCreatePixmap)
  Resource id:  0xb1
X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 62 (X_CopyArea)
  Resource id:  0x2c0000d
X Error: BadDrawable (invalid Pixmap or Window parameter) 9
  Major opcode: 62 (X_CopyArea)
  Resource id:  0x2c0000d

Я говорю "вероятно", потому что я не проверял этот подход с достаточным количеством приложений Qt, чтобы быть уверенным, или копался в исходном коде Qt, чтобы выяснить, почему это не поддерживается. YMMV, и вам может повезти, но если вы хотите запустить приложение на основе Qt из контейнера Docker, вам, возможно, придется пойти по "старомодному" подходу и либо

  1. Запустите sshd в контейнере, включите переадресацию X11, а затем подключитесь к контейнеру, используя ssh -X (более безопасный) или ssh -Y (менее безопасный, используемый, только если вы полностью доверяете контейнеризованному приложению).

  2. Запустите VNC в контейнере и подключитесь к нему с хоста с помощью клиента VNC.

Между этими двумя вариантами я бы порекомендовал первый, но посмотрим, какой из них лучше всего подходит для вашей ситуации.

Ответ 2

Существует множество решений для приложений GUI, работающих в контейнере докеров. Например, вы можете использовать SSH или VNC. Но они добавляют некоторые накладные расходы и задержки. Лучший способ, который я нашел, - это просто передать файл, используемый X-сервером на главной машине, в качестве тома в контейнере. Вот так:

docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY TheImage

Затем все ваши приложения с графическим интерфейсом будут запускаться из контейнера.

Надеюсь, это поможет!

Ответ 3

Мне удалось запустить xeyes в контейнере и увидеть "окно" на X-сервере, запущенном за пределами контейнера. Вот как:

Я использовал Xephyr для запуска вложенного X-сервера. Это не обязательно, но большинство настольных компьютеров Linux не позволяют запускать на них удаленные приложения по умолчанию (здесь, как "исправить" это на ubuntu).

Установить Xephyr:

$ sudo apt-get install xserver-xephyr

Запустить Xephyr:

$ Xephyr -ac -br -noreset -screen 800x600 -host-cursor :1

Это создает новое окно 800x600, которое действует как X-сервер.

Найдите "внешний" адрес вашей машины. Здесь выполняется X-сервер:

$ ifconfig

docker0   Link encap:Ethernet  HWaddr 56:84:7a:fe:97:99  
          inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::5484:7aff:fefe:9799/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:133395 errors:0 dropped:0 overruns:0 frame:0
          TX packets:242570 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:9566682 (9.5 MB)  TX bytes:353001178 (353.0 MB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:650493 errors:0 dropped:0 overruns:0 frame:0
          TX packets:650493 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2506560450 (2.5 GB)  TX bytes:2506560450 (2.5 GB)

wlan0     Link encap:Ethernet  HWaddr c4:85:08:97:b6:de  
          inet addr:192.168.129.159  Bcast:192.168.129.255  Mask:255.255.255.0
          inet6 addr: fe80::c685:8ff:fe97:b6de/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6587370 errors:0 dropped:1 overruns:0 frame:0
          TX packets:3716257 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:7405648745 (7.4 GB)  TX bytes:693693327 (693.6 MB)

Не используйте 127.0.0.1! Вы можете использовать любой из других. Я буду использовать 172.17.42.1.

Создайте файл Docker со следующим содержимым:

FROM ubuntu

RUN apt-get update
RUN apt-get install -y x11-apps

CMD ["/usr/bin/xeyes"]

Постройте его:

$ docker build -t xeyes .

И запустите его:

$ docker run -e DISPLAY=172.17.42.1:1.0 xeyes

Обратите внимание, что я устанавливаю переменную среды DISPLAY туда, где я хочу ее видеть.

Вы можете использовать тот же метод для перенаправления отображения на любой X-сервер.

Ответ 4

Вы можете использовать subuser для упаковки ваших графических приложений. Он также имеет хорошую поддержку для обновления приложений. Вы можете поместить свои Dockerfiles в репозиторий git один раз, а затем просто запустить subuser update all на каждом клиенте, чтобы перестроить изображения, когда их нужно изменить.

Ответ 5

Недавно я попытался запустить приложение PyQt5 в докере. Что я узнал, так это то, что вы не можете запускать приложение от имени пользователя root (вам нужно создать обычного пользователя). Если вы хотите воспроизвести аудио/видео в приложении, вы должны запустить Docker-контейнер с группой "audio" и смонтировать звуковое устройство. Поэтому для запуска моего приложения я использую это:

docker run -it \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v $(pwd)/test:/app \
    -e DISPLAY=$DISPLAY \
    -u myusername \
    --group-add audio \
    --device /dev/snd \
    fadawar/docker-pyqt5-qml-qtmultimedia python3 /app/hello.py

Я провожу некоторое время, пока не выясню, какие пакеты мне нужно добавить в свой контейнер, чтобы запустить в нем приложение PyQt, поэтому я создал несколько Dockerfiles (с простым демонстрационным приложением), чтобы облегчить это другим:

Python 3 + PyQt5: https://github.com/jozo/docker-pyqt5

Python 3 + PyQt5 + QML + QtMultimedia: https://github.com/jozo/docker-pyqt5-qml-qtmultimedia

Ответ 6

Вот основные шаги, которые вы должны выполнить, чтобы все работало нормально,

  1. Чтобы создать и запустить контейнер Docker

    sudo nvidia-docker run -it -d --privileged -e DISPLAY=$DISPLAY --name wakemeeup -v -v/dev: /dev -v/tmp/.X11-unix: /tmp/.X11-unix:rw nvidia/cuda:9.1-cudnn7-devel-ubuntu16.04 bash

  2. Чтобы запустить докер-контейнер

    sudo docker start wakemeup

  3. Присоединить к док-контейнеру

    xhost +local:root 1>/dev/null 2>&1 docker exec -u $USER -it wakemeup/bin/bash xhost -local:root 1>/dev/null 2>&1

  4. MIT-SHM - это расширение X-сервера, которое позволяет быстрее выполнять транзакции с использованием общей памяти. Изоляция Docker, вероятно, блокирует это. Приложения Qt могут быть вынуждены не использовать расширение. Внутри док-контейнера,

    nano ~/.bashrc export QT_X11_NO_MITSHM=1

  5. Источник .bashrc

    source ~/.bashrc

Надеюсь, это поможет

Ответ 7

Решено - PyQt5-GUI в Docker-контейнере:

Включить Qt-Debug $ export QT_DEBUG_PLUGINS=1 ==> воспроизвести ошибку ==> повторно установить/установить No such file or directory -library Нет, указанный в сообщении отладки ==> повторить!

Я также не смог запустить PyQt5-GUI-app в контейнере Docker без получения ошибок и сначала прочитать все сообщения о невозможности запуска Qt в контейнерах Docker. Но я мог бы решить это (по крайней мере, для меня)...

система

Я запускаю свое PyQt5-приложение в контейнере Docker с общим сокетом /tmp/.X11-unix/ и дисплеем для визуализации графического интерфейса:

$ nividia-docker run --interactive --tty --env DISPLAY=$DISPLAY --volume /tmp/.X11-unix/:/tmp/.X11-unix/ <docker_iamge>

ошибка

Инициализация PyQt5.QtWidgets.QApplication всегда приводила к следующей ошибке:

Type "help", "copyright", "credits" or "license" for more information.
>>> from PyQt5.QtWidgets import QApplication
>>> app = QApplication([])
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.

Aborted (core dumped)

В режиме отладки PyCharm возвращается ошибка:

Process finished with exit code 134 (interrupted by signal 6: SIGABRT)

Решение

Общий метод:

  • установить переменную окружения Qt-debug в контейнерном терминале Docker:
   $ export QT_DEBUG_PLUGINS=1
  • воспроизвести ошибку в док-терминале (или в IDE), например:
$ python
Python 3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34) 
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> 
KeyboardInterrupt
>>> from PyQt5.QtWidgets import QApplication, QLabel
>>> app = QApplication([])
  • читать сообщения отладки, напечатанные на терминале, например:
QFactoryLoader::QFactoryLoader() checking directory path "/conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms" ...
QFactoryLoader::QFactoryLoader() looking at "/conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqeglfs.so"
Found metadata in lib /conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqeglfs.so, metadata=
{
    "IID": "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.3",
    "MetaData": {
        "Keys": [
            "eglfs"
        ]
    },
...
...
...
Got keys from plugin meta data ("xcb")
QFactoryLoader::QFactoryLoader() checking directory path "/conda/envs/rapids/bin/platforms" ...
Cannot load library /conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (libxkbcommon-x11.so.0: cannot open shared object file: No such file or directory)
QLibraryPrivate::loadPlugin failed on "/conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so" : "Cannot load library /conda/envs/rapids/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (libxkbcommon-x11.so.0: cannot open shared object file: No such file or directory)"
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.

Aborted (core dumped)
  • найдите <No such file or directory>.so.* и <coud not be loaded> -packages, здесь, например, libxkbcommon-x11.so.0 и libxcb. Затем переустановите соответствующие пакеты/библиотеки (поиск пакетов работает с apt-file --package-only search <filename> или conda/pip search...). В моем случае потребовались следующие библиотеки:
### lib no.1 ###
$ sudo conda install --name <env_name> --force-reinstall libxcb    # or pip install ...
### lib no. 2 ###
$ apt-file --package-only search libxkbcommon-x11.so.0
libxkbcommon-x11-0
$ sudo apt install libxkbcommon-x11-0 

Повторив этот процесс для всех последовательно воспроизводимых отладочных сообщений и установив 2 библиотеки, я теперь могу запускать PyQt5-приложения из контейнера Docker на рабочем столе моей локальной машины.