Running the Rails debugger in a Docker container using RubyMine

note from Sun Apr 24, 2016

UPDATE: I have an updated follow up post on Docker, debugging and RubyMine, but using the more up-to-date Docker for Mac.

I was recently setting up my development environment on a Mac for a for project that used Docker containers. My prefered editor/IDE is RubyMine, where I get a great integrated debugging tool. There were a couple of gotchas in getting all the parts working with running the debugger inside the Docker container, but at the end it's pretty straightforward.

The basic idea

The basic idea behind remote debugging is that the application runs in debug mode on a remote server (or in a Docker container in our case), while listening for debugging info on a specified port. When execution hits a specified breakpoint, the debugger sends stack frame info back to the IDE, which is listening on another specified port for this info. The key to this is that your source code exists in both environments and that there is a mapping between the two. If your Docker development environment is set up correctly, it should automatically "copy" your working directory into the container when you launch it, so you are already halfway there.


Before you start

Get the IP address for your Docker container. You'll need this later.

$ docker-machine ip default


Project configuration

Add "ruby-debug-ide" and "debase" gems to your Gemfile. You will have to remove "byebug" as it will interfere with debugging.

group :development, :test do
  gem 'ruby-debug-ide'
  gem 'debase'
  # gem 'byebug'


RubyMine configuration

Go to Run -> Edit Configurations...

Add a new "Ruby remote debug". Fill in the fields with the following:

Remote host: your docker container's ip address, in our case,

Remote port: 1234

Remote root folder: /app/yourApp (or whatever your application's root directory is in your docker container)

Local port: 26162

Local root folder: path to the folder of your project on your local machine

At the top of the dialog box is "Server command" field. Take note of this as it will contain the basic debug command and options you will run in the Docker container:

rdebug-ide --host --port 1234 --dispatcher-port 26162 -- $COMMAND$

Click "OK" to save the new configuration.

(More info on remote debugging can be found on the JetBrains site .)


Run the debugger in the Docker container

You will need to pass through port 1234 from your local environment into the container. I like to open a bash shell into the container.

$ docker-compose run -p 1234:1234 -p 3000:3000 default bash

Install the bundle, if necessary:

$ bundle

Run the debugger using the "Server command" from above as a guide. You may or may not need bundle exec depending on your setup. You will most likely need to bind the rails server to the right IP addresses to make it work. I simply use all IP addresses to make it easier.

$ bundle exec rdebug-ide --host --port 1234 --dispatcher-port 26162 -- /app/yourApp/bin/rails s -b -p 3000 -e development


Run remote debugging in RubyMine

Go to the "Run" menu and select the new Debug configuration that you set up.

Put a break point somewhere in your code and voilà! Integrated IDE debugging with a Docker container.


What's up with all the "Stack frame is not available" messages :(

When you hit a breakpoint, you will most likely see your current frame in the Debugger's "Frame" panel, but nearly everything else will be greyed out. If you scroll down, you'll see that some stack frames are available, but most are not. The reason is that the location for the project files is mapped between your local environment and the container environment as set in the "Ruby remote debug", BUT the locations of the gems are not. All the greyed out "not available" frames are ones that point to files in various gems. Basically, the debugger sends file location and line number info back to RubyMine, but when RubyMine looks for the file with the given path, it's not there because it is the location of the gems inside the Docker container. Unfortunately, the debugger gem and RubyMine combination does not have a way to specify separate local and remote paths for the gems. There is a short discussion related to this on the JetBrains support forum here.

One solution is to bundle the gems into vendor gems in your project, but I didn't like that one would be unecessarily including external dependencies into the project.

The solution that I've found that works pretty cleanly is to create an empty directory on your local system that matches the location of the gems in the container, and simply symlink the local gems directory to where RubyMine will be looking for them. It's not always possible to do it this way, nor is it always practical. But it does work and it's fairly easy to implement in situations where you can.

$ mkdir /same/path/as/container/gem/directory
$ ln -s /path/to/your/local/gems/direcotry same/path/as/container/gem/directory

This should take care of most of the "Stack frame is not available" issues. There will be some edge cases where the stack frames will not match up due to platform differences.



And there you have it! Your beautiful RubyMine IDE is now (mostly) happily remotely debugging your rails app running in a Docker container.

tags: #docker #dockercontainer #rubyonrails #ruby-debug-ide #debugging

Docker Containers

I'm still relatively new to the world of Docker containers. Here are two O'Reilly books that have lots of useful info.


Docker is constantly improving, evolving and changing. Here is a book that has some more up-to-date info, as well as a concise step-by-step tutorial to get up and running.


Rails books

This is the grandaddy of the Ruby on Rails books. Most Rails developers I know (including myself) started with this one.

I also like the Rails Recipes book from the same publisher, as it gives real world problems that I can relate to and then sample solutions. There doesn't seem to be a Rails 4 edition yet. Here is the most recent one that I've found.