I'm starting with Docker, but I don't know how to configure PyCharm to use a python interpreter located in a container.
It was easy to setup with Vagrant, but there's apparently no official way to do it with Docker yet.
Should I prepare special Docker image with exposed ssh port? How to do that more easily?
UPDATE: PyCharm 2017.1 has a solution for this problem, see this blog entry
Here is how I solved the problem. My circumstances are that I was assigned to do an intervention on a specific area of a web app that used docker-compose to create a set of four containers. Docker-compose is a kind of meta docker that manages multiple docker containers from one command. I did not want to mangle their existing setup since so many things depend on it. But since I was working on one specific part in one of the images I decided that I would extend one of the containers with ssh so that I could debug from PyCharm. Further, I wanted the app to run as normal when started and only by forcing it to quit and then connecting to it from PyCharm would I have a debuggable component. Here is what I did on my mac that uses boot2docker (on VirtualBox) to setup docker correctly.
First, I need to extend the target container, called
jqworker
. I am going to use"supervisior"
to do the heavy lifting of managing things.Supervisor lets me run multiple tasks from one command, in this case the original command and SSHD. Yes, everyone says that SSHD in docker is evil and containers should this and that and blah blah, but programming is about solving problems, not conforming to arbitrary dicta that ignore context. We need SSH to debug code and are not deploying this to the field, which is one reason we are extending the existing container instead of adding this in to the deployment structure. I am running it locally so that I can debug the code in context.
Here is the supervisord.conf file, note that I am using the supervisor-stdout package to direct output to supervisor instead of logging the data as I prefer to see it all in one place:
I have a build directory containing the above two files, and from a terminal in there I build the
Dockerfile
with:This adds it so that I can call it from
docker
ordocker-compose
. Don't skip the trailing dot!Since the app uses
docker-compose
to run a set of containers, the existingWORKER
container will be replaced with one that solves my problems. But first I want to show that in another part of mydocker-compose.yml
I define a mapping from the containers to my local hard drive, this is one of a number of volumes being mapped:Then the actual definition for my container, which references the above
VOLUMES
:This maps the SSH port to a known port that is available in the VM, recall I am using
boot2docker
which rides on VirtualBox, but the needs to be mapped out to where PyCharm can get at it. In VirtualBox, open theboot2docker
VM and chooseAdapter 1
. Sometimes the "Attached to:" combo unselects itself, so watch for that. In my case it should haveNAT
selected.Click "Port Forwarding" and map the inner port to the a port on localhost, I choose to use the same port number. It should be something like, Name:
ssh_mapped
; Protocol:TCP
; Host IP:127.0.0.1
; Host Port:7722
; Guest IP:; Guest Port:7722
. Note: be careful not to change the boot2docker `ssh' setting or you will eventually be unable to start the VM correctly.So, at this point we have a container that extends my target container. It runs ssh on port 22 and maps it to 7722 since other containers might want to use 22, and is visible in the VirtualBox environment. VirtualBox maps 7722 to 7722 to the localhost and you can ssh into the container with:
Which will then prompt for the password, 'soup4nuts' and you should be able to locate something specific to your container to verify that it is the right one and that everything works OK. I would not mess with root if I were deploying this anywhere but my local machine, so be warned. This is only for debugging locally and you should think twice or thrice about doing this on a live site.
At this point you can probably figure the rest of it out if you have used PyCharm's remote debugging. But here is how I set it up:
First, recall that I have
docker-compose.yml
mapping the project directory:In my container
/opt/applications/myproject
is actually/Users/me/source/myproject
on my local hard drive. So, this is the root of my project. My PyCharm sees this directory as the project root and I want PyCharm to write the.pycharm_helpers
here so that it persists between sessions. I am managing source code on the mac side of things, but PyCharm thinks it is a unixy box elsewhere. Yes, it is a bit of kludge until JetBrains incorporates a Docker solution.First, go to the Project X/Project Structure and create a Content Root of the local mapping, in my case that means
/Users/me/source/myproject
Later, come back and add
.pycharm_helpers
to the excluded set, we don't want this to end up in source control or confuse PyCharm.Go to the Build, Execution, Deployment tab, pick Deployment and create a new Deployment of SFTP type. The host is localhost, the port 7722, the root path is
/opt/applications/myproject
and the username isroot
and password issoup4nuts
and I checked the option to save the password. I named my Deployment 'dockercompose' so that I would be able to pick it out later.On the Deployment Mappings tab I set the local path to
/Users/me/source/myproject
and deployment and web path to a single '/' but since my code doesn't correspond to a URL and I don't use this to debug, it is a placeholder in the Web Path setting. I don't know how you might set yours.On the Project X/Project Interpreter tab, create a new Remote Python Interpreter. You can pick the Deployment Configuration and choose the 'dockercompose' configuration we created above. The host URL should fill in as 'ssh://root@localhost:7722' and the Python Interpreter Path will likely be
/usr/bin/python
. We need to set the PyCharm Helpers Path as the default will not survive the container being redone. I actually went to my project local directory and created a.pycharm_helpers
directory in the root, then set the path here as/opt/applications/myproject/.pycharm_helpers
and when I hit the OK button it copied the files "up" to the directory. I don't know if it will create it automatically or not.Don't forget that the
.pycharm_helpers
directory should probably be excluded on the project roots tab.At this point you can go to the Build, Execution, Deployment tab, and under Console/Python Console, pick the remote interpreter we created above and set the working directory to
/opt/applications/myproject
and you can run your Python Console in the container if you like.Now you need to create a Run Configuration so that you can remotely debug your python code. Make a new Python configuration and set the script to the one that used to start the python code in the container. Mine, from the supervisor setup, above is:
So I set the script to
/opt/applications/myproject/worker.py
and the parameters to-A args
.Choose the remote interpreter we created above, and the working directory as needed, for me it is
/opt/applications/myproject
and for me that does the job.Now I want to enter my container and stop the worker.py script so I can start up a debug version. Of course, if you like you can ignore running the script by default and only use the container for debugging.
I could open a ssh session to stop the script, but docker provides a useful command that will do the work for me by passing it into the environment.
As my process is named 'worker'. Note that you can restart by replacing the
stop
command withstart
.Now, in PyCharm start a debug session with the Run Configuration created above. It should connect and start things up and give you console output in the window. Since we killed the one that Supervision originally started it is no longer connected.
This was a seat of the pants operation, so there may be errors and incorrect assumptions I didn't notice. Particularly, the PyCharm setup required a few iterations, so the order may be incorrect, try going through it again if it fails. This is a lot of stuff and easy to skip something critical.
It's not yet here, but shortly this should no longer be a problem, since
source: http://blog.jetbrains.com/pycharm/2015/03/feature-spotlight-python-remote-development-with-pycharm/#comment-187772
You can get a bit crazy by installing pycharm in the container and just running it from there. You'd have to do this by "docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=:0.0 pycharm-image" but it should work just fine. But remember that all of pycharm and your source would be in that container as well. So save, commit, and push early and often.
I don't think it's so bad to include SSH inside your container if you really need it. Yes, it's not essential in other use cases since the introduction of
docker exec
but since Intellij/PyCharm only support remote interpreter via SSH, it's OK.You can use
phusion/baseimage
as a good starting point to build your own container with SSH and any version of Python you need (it comes by default with PY3).Theoretically, it would be ideal to keep using Vagrant for this task as well, since it allows you to create a workflow that will work both on Windows/OS X machines (by using boot2docker) and Linux (native Docker).
Practically I wasn't able to make it work on OS X because of the double NAT layer you have to pass in order to get into the SSH service, and it looks like it's not possible to add extra interface to the Vagrant boot2docker box (Vagrant 1.7.2).
I haven't tried this, but I would try creating a Bash script which calls
docker exec ...
, as in @Anto's answer.Then, install the BashSupport extension. Now create a new run configuration which runs your script as a Bash script.
Steps specific to PyCharm Professional Edition 2017.2(however they may work with PyCharm CE)
Here are a couple steps I took to get my setup working
Step 1: Environment
A few assumptions of the structure of your (or anyone who might be reading this) project:
bleh
as a my project name only as an example./Users/myfunkyusername/Projects/bleh
.api
service as shown later in thedocker-compose.yml
fileNote We're also going to assume a content of your
api
's one and onlyDockerfile
is as suchNote We're assuming your one and only
docker-compose.yml
has these contentsStep 2: Create Docker-Machine
Create docker-machine specifically for the
bleh
projectStep 3: connect remote interpreter
PyCharm
/Preferences
/Build, Execution, Deployment
/Docker
click+
Docker machine
radio button and highlightbleh
's docker machine in the pull downApply
PyCharm
/Preferences
/Project:bleh
/Project Interpreter
Project Interpreter
field and selectAdd Remote
Docker
radio buttonServer
field, select previously created docker machine for this projectbleh_api
)Python interpreter path
neededOK
Step 4: configure remote debugger
Run
/Edit Configurations
select+
to add a configurationPython
Script
field, use location of script file on the docker container that will be run (in this example it's/usr/bin/bleh/__main__.py
as we're giving the absolute location of our target script)Script parameters
field, supply CLI parameters, if any (mimics theDockerfile
's lastCMD
command, which is--cfg=/etc/bleh/config.ini
)Python Interpreter
field, select your previously established remote python interpreterWorking directory
field, select the directory whereScript
is located within the Docker container (e.g/usr/bin/bleh
)Path mappings
field, click the...
and select local (e.g/Users/myfunkyusername/Projects/bleh/api/src
) and remote (e.g/usr/bin/bleh
) as aboveDocker container settings
field, click...
bleh_api:latest
)Dockerfile
(e.g 8080/8080 and expose to0.0.0.0
using thetcp
protocol, now I haven't shown what your app structure is, but let's assume that you were sane and within your app are also specifying8080
as the port where your'e serving your data./usr/bin/bleh
//Users/myfunkyusername/Projects/bleh/api/src
Network mode
(thanks Piotr) is set to<name_of_project_directory>_<name_of_network_from_compose_file>
(e.gbleh_default
, you can confirm withdocker network ls
from within the correctdocker-machine
)Step 5: Bask in the Sun or Bash your head some more
These are the steps that got me to a working docker and PyCharm setup.
I don't pretend to be correct in each of these steps. I will gladly update any errors/improvements you find.