~tsvallender

My name is Trevor, I’m a software engineer specialising in Ruby on Rails. I’m also a dad, geek and tabletop gamer.

Profile photo of Trevor Vallender

Debugging Rails apps running inside Docker with VS Code

13 March 2022 (Updated on 2022-04-02)

Since starting in my new developer position, I have been struggling to create a good debugging setup for our development environment. Now that I seem to have cracked it, I’m documenting below how to do it.

The development environment

The specific environments we work in work in generally use:

And this combination has made it somewhat harder to get things running.

Notes

I’ve not tested this setup extensively and am fully expecting it to be somewhat brittle. For one, earlier (< 2.0) versions of Ruby apparently require different gems installed.

Prerequisites

For this setup to work, we will need the ruby-debug-ide and debase gems installed in the project’s DEVELOPMENT environment.

docker-compose.yml

Next we need to tell Docker how to run the debugger for us to attach to. The key parts are included below, and you should note;

Update: On setting up debugging again using the procedure documented here I began to hit problems with the server hanging whenever I had breakpoints set. The environment variables I’m setting below limit concurrency in Puma and may or may not be necessary for your project.

  debug:
    <<: *backend
    command: bin/bundle exec rdebug-ide --host 0.0.0.0 --port 1234 -- bin/bundle exec puma -b 'ssl://0.0.0.0:3000?key=config/certs/localhost.key&cert=config/certs/localhost.crt' -b 'tcp://0.0.0.0:3001' -C ./config/puma.rb
    ports:
      - "1234:1234"
      - "3000:3000"
      - "3001:3001"
      - "443:3000"
      - "26162:26162"
    environment:
      WEB_CONCURRENCY: 0
      RAILS_MAX_THREADS: 1

  debug_rspec:
    <<: *backend
    command: bin/bundle exec rdebug-ide --host 0.0.0.0 --port 1234 -- bin/bundle exec rspec
    ports:
      - "1234:1234"
      - "3000:3000"
      - "3001:3001"
      - "443:3000"
      - "26162:26162"

dip.yml

Now we add information to our dip.yml so we can launch the debugger. I’ve ommitted the irrelevant parts here, but this is organised as subcommands under rails and rspec.

  rails:
    
    subcommands:
      
      debug:
        description: Debug Rails server
        service: debug
        compose:
          run_options: [service-ports]

  rspec:
    
    subcommands:
      debug:
        description: Debug RSpec specs
        service: debug_rspec
        compose:
          run_options: [service-ports]

launch.json

So now we’re able to launch the debugger, the final step is to be able to connect to it. From Run and Debug in Visual Studio Code, click on the cog icon to open your launch.json file, and add the below information.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug in Docker",
      "type": "Ruby",
      "request": "attach",
      "remoteHost": "0.0.0.0",
      "remotePort": "1234",
      "remoteWorkspaceRoot": "/app",
      "cwd": "${workspaceRoot}",
      "showDebuggerOutput": true
    },
    {
      "name": "Debug RSpec in Docker",
      "type": "Ruby",
      "request": "attach",
      "remoteHost": "0.0.0.0",
      "remotePort": "1234",
      "remoteWorkspaceRoot": "/app",
      "cwd": "${workspaceRoot}",
      "showDebuggerOutput": true
    },
  ]
}

Putting it all together

So now, you can start up your debugger at the command line by running dip rails debug (or dip rspec debug), then in Run and Debug in Visual Studio Code, choose Debug in Docker (or Debug RSpec in Docker) and hit the play button. You should see the server start at the command line, and can now go ahead and set breakpoints and inspect variables using Code’s debugging features.

Debugger running in VS Code

I will update this page in the future with any additional information I find.

Enjoy!