Je commence par Docker, mais je ne sais pas comment configurer PyCharm pour utiliser un interpréteur python situé dans un conteneur.
C'était facile à configurer avec Vagrant , mais il n'y a apparemment aucun moyen officiel de le faire avec Docker pour l'instant.
Dois-je préparer une image Docker spéciale avec le port ssh exposé? Comment faire cela plus facilement?
MISE À JOUR: PyCharm 2017.1 a une solution à ce problème, voir ceci entrée de blog
Voici comment j'ai résolu le problème. Ma situation est que j'ai été affecté à une intervention sur une zone spécifique d'une application Web qui a utilisé docker-compose pour créer un ensemble de quatre conteneurs. Docker-compose est une sorte de méta-docker qui gère plusieurs conteneurs de docker à partir d'une seule commande. Je ne voulais pas modifier leur configuration existante car tant de choses en dépendent. Mais comme je travaillais sur une partie spécifique de l'une des images, j'ai décidé d'étendre l'un des conteneurs avec ssh afin de pouvoir déboguer à partir de PyCharm. De plus, je voulais que l'application s'exécute normalement lorsqu'elle est démarrée et ce n'est qu'en la forçant à quitter puis en s'y connectant à partir de PyCharm que j'aurais un composant débogable. Voici ce que j'ai fait sur mon mac qui utilise boot2docker (sur VirtualBox) pour configurer correctement docker.
Tout d'abord, je dois étendre le conteneur cible, appelé jqworker
. Je vais utiliser "supervisior"
pour faire le gros du travail de gestion des choses.
FROM jqworker
# Get supervisor to control multiple processes, sshd to allow connections.
# And supervisor-stdout allows us to send the output to the main docker output.
RUN apt-get update && apt-get install -y supervisor openssh-server python-pip \
&& pip install supervisor-stdout \
&& mkdir -p /var/run/sshd \
&& mkdir -p /var/log/supervisor \
&& mkdir -p /etc/supervisor/conf.d
COPY ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Fix up SSH, probably should rip this out in real deploy situations.
RUN echo 'root:soup4nuts' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
# Expose SSH on 22, but this gets mapped to some other address.
EXPOSE 22
# Replace old entrypoint with supervisiord, starts both sshd and worker.py
ENTRYPOINT ["/usr/bin/supervisord"]
Le superviseur me permet d'exécuter plusieurs tâches à partir d'une seule commande, dans ce cas, la commande d'origine et SSHD. Oui, tout le monde dit que SSHD dans docker est mauvais et que les conteneurs devraient ceci et cela et bla bla, mais la programmation consiste à résoudre des problèmes, pas à se conformer à des dicta arbitraires qui ignorent le contexte. Nous avons besoin de SSH pour déboguer le code et ne le déployons pas sur le terrain, ce qui est une des raisons pour lesquelles nous étendons le conteneur existant au lieu de l'ajouter à la structure de déploiement. Je l'exécute localement afin de pouvoir déboguer le code dans son contexte.
Voici le fichier supervisord.conf, notez que j'utilise le package supervisor-stdout pour diriger la sortie vers le superviseur au lieu de consigner les données car je préfère tout voir en un seul endroit:
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:worker]
command=python /opt/applications/myproject/worker.py -A args
directory=/opt/applications/myproject
stdout_events_enabled=true
stderr_events_enabled=true
[eventlistener:stdout]
command = supervisor_stdout
buffer_size = 100
events = PROCESS_LOG
result_handler = supervisor_stdout:event_handler
J'ai un répertoire de construction contenant les deux fichiers ci-dessus, et à partir d'un terminal là-dedans, je construis le Dockerfile
avec:
docker build -t fgkrqworker .
Cela l'ajoute pour que je puisse l'appeler depuis docker
ou docker-compose
. Ne sautez pas le point de fuite!
Étant donné que l'application utilise docker-compose
pour exécuter un ensemble de conteneurs, le conteneur WORKER
existant sera remplacé par un conteneur qui résout mes problèmes. Mais je veux d'abord montrer que dans une autre partie de mon docker-compose.yml
Je définis un mappage des conteneurs vers mon disque dur local, c'est l'un des nombreux volumes mappés:
volumes: &VOLUMES
? /Users/me/source/myproject:/opt/applications/myproject
Ensuite, la définition réelle de mon conteneur, qui fait référence au VOLUMES
ci-dessus:
jqworker: &WORKER
image: fgkrqworker
privileged: true
stdin_open: true
detach: true
tty: true
volumes:
<<: *VOLUMES
ports:
- "7722:22"
Cela mappe le port SSH à un port connu qui est disponible dans la machine virtuelle, rappelez-vous que j'utilise boot2docker
qui s'appuie sur VirtualBox, mais doit être cartographié là où PyCharm peut y accéder. Dans VirtualBox, ouvrez le boot2docker
VM et choisissez Adapter 1
. Parfois, le combo "Attaché à:" se désélectionne, alors faites attention à cela. Dans mon cas, il devrait avoir NAT
sélectionné.
Cliquez sur "Port Forwarding" et mappez le port interne au port a sur localhost, je choisis d'utiliser le même numéro de port. Cela devrait ressembler à: Nom: ssh_mapped
; Protocole: TCP
; IP hôte: 127.0.0.1
; Port hôte:7722
; IP invité :; Port invité: 7722
. Remarque: veillez à ne pas modifier le paramètre boot2docker `ssh 'sinon vous ne pourrez pas démarrer correctement le VM.
Donc, à ce stade, nous avons un conteneur qui étend mon conteneur cible. Il exécute ssh sur le port 22 et le mappe sur 7722 car d'autres conteneurs peuvent vouloir utiliser 22, et est visible dans l'environnement VirtualBox. VirtualBox mappe 7722 à 7722 à l'hôte local et vous pouvez ssh dans le conteneur avec:
ssh root@localhost -p 7722
Ce qui vous demandera ensuite le mot de passe, 'soup4nuts' et vous devriez pouvoir localiser quelque chose de spécifique à votre conteneur pour vérifier qu'il est le bon et que tout fonctionne bien. Je ne jouerais pas avec root si je déployais cela ailleurs que sur ma machine locale, alors soyez averti. Ceci est uniquement pour le débogage local et vous devriez y réfléchir deux fois ou trois fois pour le faire sur un site en direct .
À ce stade, vous pouvez probablement comprendre le reste si vous avez utilisé le débogage à distance de PyCharm. Mais voici comment je l'ai configuré:
Tout d'abord, rappelez-vous que j'ai docker-compose.yml
mappage du répertoire du projet:
? /Users/me/source/myproject:/opt/applications/myproject
Dans mon conteneur /opt/applications/myproject
est en fait /Users/me/source/myproject
sur mon disque dur local. C'est donc la racine de mon projet. Mon PyCharm voit ce répertoire comme la racine du projet et je veux que PyCharm écrive le .pycharm_helpers
ici pour qu'il persiste entre les sessions. Je gère le code source du côté mac, mais PyCharm pense que c'est une boîte unixy ailleurs. Oui, c'est un peu compliqué jusqu'à ce que JetBrains incorpore une solution Docker.
Tout d'abord, accédez à Project X/Project Structure et créez une racine de contenu du mappage local, dans mon cas, cela signifie /Users/me/source/myproject
Plus tard, revenez et ajoutez .pycharm_helpers
à l'ensemble exclu, nous ne voulons pas que cela se retrouve dans le contrôle de source ou confondre PyCharm.
Accédez à l'onglet Build, Execution, Deployment, choisissez Deployment et créez un nouveau Deployment de type SFTP. L'hôte est localhost, le port 7722, le chemin racine est /opt/applications/myproject
et le nom d'utilisateur est root
et le mot de passe est soup4nuts
et j'ai coché l'option pour enregistrer le mot de passe. J'ai nommé mon déploiement "dockercompose" afin de pouvoir le récupérer plus tard.
Dans l'onglet Mappages de déploiement, j'ai défini le chemin local sur /Users/me/source/myproject
et le déploiement et le chemin Web vers un seul '/', mais comme mon code ne correspond pas à une URL et que je ne l'utilise pas pour le débogage, il s'agit d'un espace réservé dans le paramètre Chemin d'accès Web. Je ne sais pas comment vous pourriez définir le vôtre.
Dans l'onglet Project X/Project Interpreter, créez un nouvel interpréteur distant Python. Vous pouvez choisir la configuration de déploiement et choisir la configuration 'dockercompose' que nous avons créée ci-dessus. L'URL de l'hôte doit remplir comme ' ssh: // root @ localhost: 7722 'et le chemin de l'interpréteur Python sera probablement /usr/bin/python
. Nous devons définir le chemin des aides PyCharm car la valeur par défaut ne survivra pas au conteneur en cours de refonte. En fait, je suis allé dans le répertoire local de mon projet et j'ai créé un .pycharm_helpers
répertoire à la racine, puis définissez le chemin ici comme /opt/applications/myproject/.pycharm_helpers
et quand j'ai appuyé sur le bouton OK, il a copié les fichiers "vers le haut" dans le répertoire. Je ne sais pas s'il va le créer automatiquement ou non.
N'oubliez pas que le .pycharm_helpers
le répertoire devrait probablement être exclu dans l'onglet racines du projet.
À ce stade, vous pouvez accéder à l'onglet Build, Execution, Deployment et sous Console/Python Console, choisissez l'interpréteur distant que nous avons créé ci-dessus et définissez le répertoire de travail sur /opt/applications/myproject
et vous pouvez exécuter votre Python console dans le conteneur si vous le souhaitez.
Vous devez maintenant créer une configuration d'exécution afin de pouvoir déboguer à distance votre code python. Créez une nouvelle configuration Python et définissez le script sur celui qui a utilisé pour démarrer le code python dans le conteneur. Le mien, à partir de la configuration du superviseur, ci-dessus est:
/opt/applications/myproject/worker.py -A args
J'ai donc défini le script sur /opt/applications/myproject/worker.py
et les paramètres à -A args
.
Choisissez l'interpréteur distant que nous avons créé ci-dessus et le répertoire de travail selon vos besoins, pour moi c'est /opt/applications/myproject
et pour moi ça fait le boulot.
Maintenant, je veux entrer dans mon conteneur et arrêter le script worker.py pour pouvoir démarrer une version de débogage. Bien sûr, si vous le souhaitez, vous pouvez ignorer l'exécution du script par défaut et utiliser uniquement le conteneur pour le débogage.
Je pourrais ouvrir une session ssh pour arrêter le script, mais docker fournit une commande utile qui fera le travail pour moi en la passant dans l'environnement.
$> docker exec -i -t supervisorctl stop worker
Comme mon processus est nommé "travailleur". Notez que vous pouvez redémarrer en remplaçant la commande stop
par start
.
Maintenant, dans PyCharm, démarrez une session de débogage avec la configuration d'exécution créée ci-dessus. Il devrait se connecter et démarrer les choses et vous donner la sortie de la console dans la fenêtre. Depuis que nous avons tué celui que Supervision avait initialement commencé, il n'est plus connecté.
C'était un siège de l'opération du pantalon, donc il peut y avoir des erreurs et des hypothèses incorrectes que je n'ai pas remarquées. En particulier, la configuration de PyCharm a nécessité quelques itérations, donc l'ordre peut être incorrect, essayez de le refaire s'il échoue. C'est beaucoup de choses et il est facile de sauter quelque chose de critique.
Ce n'est pas encore là, mais sous peu, cela ne devrait plus être un problème, car
La prise en charge de Docker sera introduite dans PyCharm à partir de PyCharm 4.1 EAP (début avril)
Si tout ce dont vous avez besoin est de déboguer du code qui est lancé à l'intérieur du conteneur Docker, vous pouvez utiliser la fonction serveur de débogage python de pycharm. Quant à moi, c'est moins gênant que d'accéder à l'interpréteur distant via SSH. L'inconvénient de cette solution est que pour la saisie semi-automatique et tout ce genre de choses, vous devriez avoir une copie locale de l'interpréteur du conteneur et le marquer comme interprète du projet (fonctionne pour la saisie semi-automatique, mais je ne suis pas sûr qu'il soit possible de déboguer du code à partir de bibliothèques tierces dans ce cas) ou rendre les fichiers d'interprétation du conteneur visibles par pycharm (non testés du tout). Notez également que Python est fonctionnalité de l'édition professionnelle .
Ce que vous devez faire pour déboguer via Python serveur de débogage:
1) assurez-vous que le répertoire avec votre projet est ajouté dans le conteneur. Cela pourrait ressembler à cette ligne dans Dockerfile:
ADD . /path/in/container
2) copiez pycharm-debug.Egg
(pycharm-debug-py3k.Egg
pour Python3) depuis le répertoire où pycharm est installé sur votre hôte vers le répertoire du conteneur, qui se trouve dans le PYTHONPATH du conteneur. Le chemin vers pycharm-debug.Egg sur l'hôte du développeur peut être:
/Applications/PyCharm.app/Contents/pycharm-debug.Egg
/opt/pycharm/pycharm-debug.Egg
3) créer une configuration Run/Debug pour lancer Python serveur de débogage sur l'hôte comme décrit dans To configure a remote debug server
section de docs . Le port est le port de n'importe quel hôte de votre choix, mais IP est l'adresse à laquelle l'hôte est accessible à partir du conteneur. Il pourrait être:
ifconfig
, pour moi c'est: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
N'oubliez pas non plus de spécifier les mappages de chemin entre le chemin du projet sur l'hôte du développeur et le chemin du projet sur le conteneur.
Ce billet de blog pourrait également être utile pour l'étape actuelle
4) lancez cette configuration créée (par exemple, via le bouton Debug
, directement depuis Run
one)
5) créer un script python qui lancerait votre projet et ajouter le code suivant pour l'initialisation du débogage comme premières lignes de ce script. (Assurez-vous que pycharm-debug.Egg
est en PYTHONPATH, ou ce code n'a pas pu import pydevd
):
import pydevd pydevd.settrace('172.17.42.1', suspend=False, port=8765, stdoutToServer=True, stderrToServer=True)
6) Enfin, vous pouvez définir des points d'arrêt et lancer votre application depuis l'hôte, en conteneur via un script créé. Par exemple:
docker-compose run 'container_name' python 'script_name' 'args'
Au démarrage, votre script de lancement se connectera au serveur de débogage Python, qui s'exécute sur l'hôte, et s'arrêtera sur les points d'arrêt. Les fonctionnalités du débogueur seront disponibles comme d'habitude.
Je ne pense pas qu'il soit si mauvais d'inclure SSH dans votre conteneur si vous en avez vraiment besoin. Oui, ce n'est pas indispensable dans d'autres cas d'utilisation depuis l'introduction de docker exec
mais comme Intellij/PyCharm ne prend en charge que l'interpréteur distant via SSH, c'est OK.
Vous pouvez utiliser phusion/baseimage
comme un bon point de départ pour construire votre propre conteneur avec SSH et toute version de Python dont vous avez besoin (il vient par défaut avec PY3).
Théoriquement, il serait idéal de continuer à utiliser Vagrant pour cette tâche également, car il vous permet de créer un flux de travail qui fonctionnera à la fois sur les machines Windows/OS X (en utilisant boot2docker) et Linux (Docker natif).
Pratiquement, je n'ai pas pu le faire fonctionner sur OS X en raison de la double couche NAT que vous devez passer pour accéder au service SSH, et il semble qu'il ne soit pas possible d'ajouter interface supplémentaire à la boîte Vagrant boot2docker (Vagrant 1.7.2).
Afin d'éviter toute surcharge SSH (ce qui est parfaitement logique avec Docker), docker exec
semble définitivement être la voie à suivre.
Malheureusement, je n'ai pas pu le faire fonctionner jusqu'à présent. Ce serait formidable si quelqu'un pouvait remplir les blancs. Voici ce que j'ai fait (en utilisant PyCharm 4.0.4 et Docker 1.4.1):
Créez un fichier nommé python_myproject.sh
contenant les éléments suivants:
#!/bin/bash
docker exec -i myproject_container /path/to/containers/python2.7
Notez que le nom du fichier doit commencer par python
sinon PyCharm se plaindra.
Dans les paramètres de PyCharm, sous Project Interpreter
, ajoutez un nouvel interprète local. Donnez-lui le chemin de votre python_myproject.sh
fichier.
C'est là que je suis coincé. Après un temps de chargement assez long (le lanceur dit "Configuration des fichiers de bibliothèque"), une fenêtre intitulée "Invalid Python SDK" apparaît et dit:
Impossible de configurer un python SDK
dans /path/to/python_myproject.sh.
Le SDK semble invalide.
Dans ~/.PyCharm40/system/log/.idea
:
2015-02-19 17:33:30,569 [ 166966] WARN - ution.process.OSProcessHandler - Cannot kill process tree. Trying to destroy process using Java API. Cmdline:
2015-02-19 17:34:30,628 [ 227025] WARN - ution.process.OSProcessHandler - Cannot kill process tree. Trying to destroy process using Java API. Cmdline:
2015-02-19 17:34:30,653 [ 227050] INFO - rains.python.sdk.PythonSdkType -
Timed out
Étapes spécifiques à PyCharm Professional Edition 2017.2 (mais elles peuvent fonctionner avec PyCharm CE)
Voici quelques étapes que j'ai prises pour faire fonctionner ma configuration
Quelques hypothèses sur la structure de votre projet (ou toute personne qui pourrait lire ce projet):
bleh
├── README.md
├── api
│ ├── Dockerfile <---- this is the one we want to debug
│ ├── config.example.ini
│ └── src
│ ├── __init__.py <---- this is a pycharm project
│ ├── __main__.py <---- this is a pycharm project
│ └── ...
├── proxy
│ ├── Dockerfile
│ ├── config.example.ini
│ └── src
│ ├── ...
│ └── ...
├── webserver
│ ├── Dockerfile
│ ├── config.example.ini
│ └── src
│ ├── ...
│ └── ...
├── frontend
│ ├── Dockerfile
│ ├── config.example.ini
│ └── src
│ ├── ...
│ └── ...
├── db
│ ├── Dockerfile
│ ├── ...
│ └── migrations
│ ├── ...
│ └── ...
└── docker-compose.yml
bleh
comme nom de projet uniquement à titre d'exemple./Users/myfunkyusername/Projects/bleh
.api
comme indiqué plus loin dans le docker-compose.yml
fichier Remarque Nous allons également supposer que le contenu de votre api
est unique et que Dockerfile
est en tant que tel
FROM python
ADD config.example.ini /etc/bleh/config.ini
RUN chmod +x /usr/bin/bleh
COPY ./src /usr/bin/bleh
WORKDIR /usr/bin/bleh
RUN pip install -r requirements.txt
CMD ["sh", "-c", "python -m bleh --cfg=/etc/bleh/config.ini"]
Remarque Nous supposons que vous êtes le seul et unique docker-compose.yml
a ce contenu
version: '2'
services:
api:
build:
context: ./api
depends_on:
- db
expose:
- "8080"
networks:
- default
frontend:
build:
context: ./frontend
ports:
- "80:7000"
networks:
- default
webserver:
build:
context: ./webserver
depends_on:
- frontend
networks:
- default
proxy:
build:
context: ./proxy
ports:
- "80:80"
- "443:443"
depends_on:
- webserver
- api
networks:
- default
db:
build:
context: ./db
expose:
- "3306"
networks:
- default
networks:
default:
driver: bridge
Créer un docker-machine spécialement pour le projet bleh
docker-machine create bleh
PyCharm
/Preferences
/Build, Execution, Deployment
/Docker
cliquez sur +
Docker machine
bouton radio et mettez en surbrillance la machine docker de bleh
dans le menu déroulantApply
PyCharm
/Preferences
/Project:bleh
/Project Interpreter
Project Interpreter
champ et sélectionnez Add Remote
Docker
bouton radioServer
, sélectionnez la machine docker créée précédemment pour ce projetbleh_api
)Python interpreter path
nécessaireOK
Run
/Edit Configurations
sélectionnez +
pour ajouter une configurationPython
Script
, utilisez l'emplacement du fichier de script sur le conteneur Docker qui sera exécuté (dans cet exemple, c'est /usr/bin/bleh/__main__.py
car nous donnons l'emplacement absolu de notre script cible)Script parameters
champ, fournissez les paramètres CLI, le cas échéant (imite la dernière commande Dockerfile
de CMD
, qui est --cfg=/etc/bleh/config.ini
)Python Interpreter
champ, sélectionnez votre télécommande précédemment établie python interprèteWorking directory
, sélectionnez le répertoire dans lequel se trouve Script
dans le conteneur Docker (par exemple /usr/bin/bleh
)Path mappings
champ, cliquez sur le ...
et sélectionnez local (par exemple /Users/myfunkyusername/Projects/bleh/api/src
) et à distance (par exemple /usr/bin/bleh
) comme ci-dessusDocker container settings
champ, cliquez sur ...
bleh_api:latest
)Dockerfile
(par exemple 8080/8080 et exposez à 0.0.0.0
en utilisant le protocole tcp
, maintenant je n'ai pas montré la structure de votre application, mais supposons que vous étiez sain d'esprit et que votre application spécifie également 8080
comme le port où vous servez vos données./usr/bin/bleh
//Users/myfunkyusername/Projects/bleh/api/src
Network mode
( merci Piotr ) est défini sur <name_of_project_directory>_<name_of_network_from_compose_file>
(par exemple bleh_default
, vous pouvez confirmer avec docker network ls
depuis le bon docker-machine
)Ce sont les étapes qui m'ont amené à un docker fonctionnel et à une configuration PyCharm.
Je ne prétends pas avoir raison dans chacune de ces étapes. Je me ferai un plaisir de mettre à jour toutes les erreurs/améliorations que vous trouverez.
Je n'ai pas essayé cela, mais j'essaierais de créer un script Bash qui appelle docker exec ...
, comme dans @ réponse d'Anto .
Ensuite, installez extension BashSupport . Maintenant créez une nouvelle configuration d'exécution qui exécute votre script en tant que script Bash.
Avec Docker 1.3, utilisez la commande exec
pour construire le chemin d'accès à l'interpréteur Python:
Sudo docker exec container_name /usr/bin/python
Voir https://docs.docker.com/reference/commandline/cli/#exec , http://forum.jetbrains.com/thread/PyCharm-2224
Vous pouvez installer SSH à l'intérieur du conteneur, puis exposer le port, mais ce n'est pas ainsi que les conteneurs devraient être utilisés, car vous les feriez gonfler.
Avec PyCharm 5, ils ont ajouté la prise en charge de docker. Vous devez avoir votre docker configuré dans docker-machine.
Si vous n'utilisez pas déjà docker-machine, vous pouvez vous connecter à une machine existante en utilisant le moteur de machine générique et ssh dans un vagrant VM ou à localhost si vous n'exécutez pas les choses dans une VM Je n'ai malheureusement pas trouvé de moyen de contourner le SSH vers localhost.
Je n'ai pas trouvé de moyen de monter des volumes dans l'image docker qu'ils utilisent, de partager des fichiers avec mon arbre de développement, mais cela pourrait être possible.
Vous pouvez devenir un peu fou en installant pycharm dans le conteneur et en l'exécutant à partir de là. Vous devez le faire en "docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY =: 0.0 pycharm-image" mais cela devrait très bien fonctionner. Mais rappelez-vous que pycharm et votre source se trouveraient également dans ce conteneur. Donc, enregistrez, validez et Push tôt et souvent.