Problème
J'ai un ensemble de machines clientes qui font partie d'une application Web d'entreprise. Chaque machine exécute un logiciel identique, qui est un client Web basé sur PyQT qui se connecte à un serveur. Ce logiciel client est mis à jour régulièrement et j'aimerais avoir un outil de configuration/provisioning qui permet d'avoir le même environnement sur chaque machine et donc de faciliter le déploiement et la configuration du logiciel sur chacune des machines des clients.
Le problème est que j'ai essayé d'utiliser Chef, mais il faut beaucoup d'efforts pour maintenir les connaissances et les compétences de Chef (nous n'avons pas de gars Ops dédié) et de plus, une recette de Chef peut échouer si un référentiel tiers n'est plus disponible (c'est un bouchon principal).
Je voudrais essayer Docker pour résoudre le problème, mais je je ne sais toujours pas s'il est possible de configurer des images/conteneurs qui permettent à certains logiciels basés sur une interface graphique de fonctionner.
Question
Est-il possible d'utiliser Docker pour avoir un environnement de développement/production pour une application basée sur une interface graphique (PyQt/QT)? Si oui, quelles seraient les premières étapes pour aborder cela?
Actuellement, cette question est sans réponse, mais elle est très bien classée sur Google. Les autres réponses sont pour la plupart correctes, mais avec quelques mises en garde que j'ai apprises à la dure, et je voudrais éviter aux autres des ennuis.
La réponse donnée par Nasser Alshammari est l'approche la plus simple (et la plus rapide) pour exécuter des applications GTK dans un conteneur Docker - montez simplement le socket du serveur X en tant que volume Docker et dites à Docker de l'utiliser à la place.
docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY TheImage
(Je recommanderais également de passer le -u <username-within-container>
flag, car exécuter des applications X11 en tant que root ne fonctionne pas toujours et n'est généralement pas recommandé, surtout lors du partage de sessions).
Cela fonctionnera pour des applications telles que xterm
, ainsi que pour les applications basées sur GTK. Par exemple, si vous essayez ceci avec Firefox (qui est basé sur GTK), cela fonctionnera (notez que si vous exécutez déjà Firefox sur l'hôte, il ouvrira une nouvelle fenêtre dans l'hôte plutôt qu'une nouvelle instance de Firefox). de l'intérieur du conteneur).
Cependant , votre réponse concerne spécifiquement PyQT. Il s'avère que Qt ne prend pas en charge le partage de sessions X de cette manière (ou du moins ne le prend pas bien en charge).
Si vous essayez d'exécuter une application basée sur QT de cette façon, vous obtiendrez probablement une erreur comme celle-ci:
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
Je dis "probablement" parce que je n'ai pas testé cette approche avec suffisamment d'applications Qt pour être sûr, ou creusé suffisamment dans le code source de Qt pour comprendre pourquoi cela n'est pas pris en charge. YMMV, et vous aurez peut-être de la chance, mais si vous cherchez à exécuter une application basée sur Qt à partir d'un conteneur Docker, vous devrez peut-être adopter l'approche "à l'ancienne" et soit
Exécutez sshd dans le conteneur, activez le transfert X11, puis connectez-vous au conteneur à l'aide de ssh -X
(plus sûr) ou ssh -Y
(moins sécurisé, utilisé seulement si vous faites entièrement confiance à l'application conteneurisée).
Exécutez VNC dans le conteneur et connectez-vous à celui-ci à partir de l'hôte avec un client VNC.
Entre ces deux options, je recommanderais la première, mais voyez celle qui convient le mieux à votre situation.
Il existe de nombreuses solutions pour que les applications GUI s'exécutent dans un conteneur Docker. Vous pouvez utiliser SSH ou VNC par exemple. Mais ils ajoutent des frais généraux et des retards. Le meilleur moyen que j'ai trouvé est simplement de passer le fichier utilisé par le serveur X dans la machine hôte en tant que volume dans le conteneur. Comme ça:
docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY TheImage
Ensuite, toutes vos applications GUI s'exécuteront à partir du conteneur.
J'espère que cela t'aides!
Vous pouvez utiliser subuser pour empaqueter vos applications GUI. Il a également un bon support pour la mise à jour des applications. Vous pouvez placer vos Dockerfiles dans un dépôt git une fois, puis exécuter simplement subuser update all
sur chaque client pour reconstruire les images lorsqu'elles doivent être modifiées.
Voici les étapes de base à suivre pour que tout fonctionne bien,
Pour créer et exécuter le conteneur 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
Pour démarrer le conteneur Docker
Sudo docker start wakemeup
Pour attacher au conteneur Docker
xhost +local:root 1>/dev/null 2>&1 docker exec -u $USER -it wakemeup /bin/bash xhost -local:root 1>/dev/null 2>&1
Le MIT-SHM est une extension du serveur X qui permet des transactions plus rapides en utilisant la mémoire partagée. L'isolement de Docker le bloque probablement. Les applications Qt peuvent être forcées de ne pas utiliser l'extension. À l'intérieur du conteneur docker,
nano ~/.bashrc export QT_X11_NO_MITSHM=1
Source .bashrc
source ~/.bashrc
J'espère que cela vous aidera
$ export QT_DEBUG_PLUGINS=1
==> reproduire l'erreur ==> réinstaller la bibliothèque No such file or directory
- répertoriée dans le message de débogage ==> répéter!Je ne pouvais pas non plus exécuter PyQt5-GUI-app dans un conteneur Docker sans recevoir d'erreurs et lire d'abord tous les messages qu'il ne serait pas possible d'exécuter Qt dans des conteneurs Docker. Mais je pourrais le résoudre (au moins pour moi) ...
J'exécute mon application PyQt5 dans un conteneur Docker avec socket /tmp/.X11-unix/
Partagé et affichage pour la visualisation GUI:
$ nividia-docker run --interactive --tty --env DISPLAY=$DISPLAY --volume /tmp/.X11-unix/:/tmp/.X11-unix/ <docker_iamge>
L'initialisation de PyQt5.QtWidgets.QApplication
A toujours conduit à l'erreur suivante:
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)
En mode PyCharm Debug, l'erreur a renvoyé:
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
$ export QT_DEBUG_PLUGINS=1
$ 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.*
et <coud not be loaded>
, par exemple ici libxkbcommon-x11.so.0
Et libxcb
. Réinstallez ensuite les packages/bibliothèques correspondants (la recherche des packages fonctionne avec apt-file --package-only search <filename>
Ou conda/pip search ...
). Dans mon cas, les bibliothèques suivantes étaient requises:### 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
Après avoir répété ce processus pour tous les messages de débogage reproduits séquentiellement et installé les 2 bibliothèques, je peux maintenant exécuter les applications PyQt5 à partir du conteneur Docker sur le bureau de ma machine locale.