SSH ipcluster with local and remote engines

I needed distributed computation using as many different IPs as possible. I decided to use ipython for my task and it's ipcluster command. Unfortunately I've found several problems with this usage.

For example, you cannot specify port and username for SSH connection. Additionally, there is problem if you want to run python from some specific virtualenv, which is different on every machine. Hence, here is what I ended up doing.

In my configuration there was main_host, where the main Hub is running. I created new parallel profile using ipython profile create --parallel distcomp. This creates all the necessary configuration files. Additionally, I wanted to use several cores on this main machine too. Then there are host1, host2, ..., hostN which are explicitly for engines (over SSH).

Step-by-step

Configuring SSH

Open .ssh/config and add configuration for each host. Every host should have at least it's port (can be ommited if it is 22), username, hostname and identity key.

Here is an example of mine:

    Host host1
      HostName host1.example.com
      IdentityFile /home/username/.ssh/host1
      User bob
      Port 1933

    Host host2
      HostName host2.example.com
      IdentityFile /home/username/.ssh/host2
      User alice
      Port 4931

    ...

    Host hostN
      HostName hostN.example.com
      IdentityFile /home/username/.ssh/hostN
      User adam
      Port 1033

Where identity files can be generated by ssh-keygen -t dsa with no pass phrase (just press enter). It will create two files keynamehostX and keynamehostX.pub. Go to hostX environment and copy the content of keynamehostX to /home/hostXusername/.ssh/authorized_keys.

Additionally, if you want to run some engines on the same machine as is ipcluster running (in my case it's main_host), you need to add ssh record for localhost. Again, create key and then copy it's public part to authorized_keys. Then add this to .ssh/config:

    Host main_host
      Hostname localhost
      IdentityFile /home/username/.ssh/main_host_key
      User username

Configuring ipcluster

Open ~/.ipython/profile_distcomp/ipcluster_config.py and find part with SSHEngineSetLauncher configuration. There you need to add this:

c.SSHEngineSetLauncher.engine_cmd = ['/tmp/dist_python', '-m', 'IPython.parallel.engine']  
c.SSHEngineSetLauncher.engines = {"main_host": 4,  
                                       'host1' : 2,
                                        ...
                                       'hostN' : 4}

This will create 4 engines on the main_host, 2 engines on host1 etc. Now it is necessary to create link in /tmp/dist_python to python version of your virtualenv on each host. Let's say that you have virtualenv on host1 as follows /home/bob/virtualenv_for_distrubuted_computation/bin/python. Then you need to go to /tmp and create ln -s /home/bob/virtualenv_for_distrubuted_computation/bin/python dist_python. Everyone should have permissions for writing to /tmp. Of course, you need to have ipython installed in each virtuaelnv.

Running ipcluster and ipython notebook

All you need to do now is to run ipcluster by this command: ipcluster start --profile=distcomp. If you want to run ipython notebook, do it like this: ipython notebook --profile=distcomp.

Now you can check if everything is working by creating new notebook and using e.g. this:

from IPython.parallel import Client  
rc = Client()  
print("Number of cores:", len(rc.ids))

def testingfunc():  
    import os
    q = os.getcwdb()

    import getpass
    u = getpass.getuser()

    return(q, u)

rc[:].apply_sync(testingfunc)  

And that's it!