56

I have a rails app running in a docker container in development environment.

When I try to debug it with placing binding.pry somewhere in the code and attaching to the container I can see the pry prompt in the output but it doesn't pause on it and I can't interact with it like it was without docker container.

So how do I debug a containerized app?

fey
  • 1,289
  • 1
  • 10
  • 20

6 Answers6

81

If you're using docker-compose, you can add these flags to docker-compose.yml:

app:
  tty: true
  stdin_open: true

And then attach to your process with docker attach project_app_1. pry-rails works here now. Ensure less is installed on your container for the optimal pry experience.

cf. https://github.com/docker/compose/issues/423#issuecomment-141995398

Lev Lukomsky
  • 6,346
  • 4
  • 34
  • 24
Gabe Kopley
  • 16,281
  • 5
  • 47
  • 60
  • Any idea how to run this in a local k8s deployment? I'm running minikube and deploying with skaffold. – E.E.33 Oct 18 '19 at 12:30
34

to use pry you have to run it differently:

docker-compose run --service-ports web

check out this article for more info:

http://blog.carbonfive.com/2015/03/17/docker-rails-docker-compose-together-in-your-development-workflow/

Terri Chu
  • 457
  • 4
  • 3
  • 2
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Pete B. May 12 '16 at 14:28
  • This solution was not adequate for me because other of my services depend on being linked to the right instance of this service I want to debug. – Gabe Kopley May 16 '16 at 23:06
  • what is --service-ports for? – Arnold Roa Sep 25 '20 at 16:34
  • For me this is working solution. Adding `stdin_open`, `tty` to docker-compose file have issue - for some reason new logs not printed to terminal if service was inactive for a minute or so (there are multiple issues on `docker-compose` and `moby` repos), this command allowing to debug and keep our logs stream alive. – zooblin Jul 19 '21 at 05:05
22

as Gabe Kopley answer, assume your rails container is called app, set stdin_open and tty to true:

app:
  stdin_open: true
  tty: true

and I wrote a bash script to make life easier, save it to bin/dev:

#!/bin/bash
docker-compose up -d && docker attach $(docker-compose ps -q app)

don't forget to make dev be executable by chmod +x bin/dev

In your terminal, type bin/dev, it will automatically run up containers and attach the app container. when binding.pry called, you can type to the terminal directly.

Yi Feng Xie
  • 4,378
  • 1
  • 26
  • 29
  • 1
    Attach command gives me '"docker attach" requires exactly 1 argument.' when I'm running `docker-compose run app rails c` in parallel with server. You may use `docker attach $(docker-compose ps | grep app_1 | awk '{print $1}')` to fix it – Aleksander Ryhlitski Apr 16 '19 at 17:03
  • 1
    thanks that worked fine. I wonder though, how can I interact with the terminal? My text doesn't get printed when I type instantly untill I send the command – Gilg Him Feb 09 '21 at 21:59
8

I had this same issue when I was running pry in Passenger. Try changing "pry-rails" in the Gemfile to gem "pry-remote", which will initiate a dRuby, or distributed protocol with no dependencies.

Where you want to stop the code in execution call "binding.remote_pry" as opposed to "binding.pry"

Then just call remote-pry in the console to access it. It should work the same. In your test environment just the usual binding.pry works fine.

kalyco
  • 81
  • 3
  • For anyone building CircleCI config.yml files, using Docker locally (ie: Docker Desktop), using the "circleci local execute', and wants to debug Ruby code, the gem pry-remote is a lifesaver! I am able to spin up my CircleCI jobs, stop at breakpoints in the containers, and use standard pry commands. A real gem!! – Martin Sommer Feb 04 '21 at 01:34
5

If you don't use docker-compose though, you can simply run the container with -it option.

For example:

docker run -v /Users/adam/Documents/Rails/Blog/:/usr/src/app -p 3000:3000 -it blog
Adam Sibik
  • 885
  • 9
  • 13
3

If you are running in under alpine linux aka ruby-*-alpine you need to install package ncurses wich includes infocmp.

If that's the reason you will have this in your error log:

bin/rails: No such file or directory - infocmp                                                              
Error: undefined method `split' for nil:NilClass 
...
bin/rails:4:in `<main>'                                                                                                                 
FATAL: Pry failed to get user input using `Readline`.                                                       
To fix this you may be able to pass input and output file descriptors to pry directly. e.g.                                    
  Pry.config.input = STDIN                                                                                   
  Pry.config.output = STDOUT                                                                           
  binding.pry    

To fix it, on your Dockerfile add:

RUN apk add ncurses

Although You probably already had an apk add line, so just add ncurses there.

then you can do

Arnold Roa
  • 7,335
  • 5
  • 50
  • 69