Basic Troubleshooting with Docker and Ruby on Rails
Tags: docker, ruby, rails, webdev
Published: 2023-02-24 00:58:55

I just started volunteering with the [Open Food Network](https://github.com/openfoodfoundation/openfoodnetwork) to re-familiarize myself with Ruby on Rails. They are an open source, non-profit, online marketplace for food stores. They provide software to link up independent farmers with hubs and distributors and it all runs on Ruby on Rails. 

Like a lot of web apps, they have a Docker setup to make things easier. Docker helps eliminate the "it works on my computer" problem that can plague other development efforts when certain software packages are not installed, or the wrong version of them is installed.

If you are not familiar, Docker is a piece of software that 'docks' system images on your computer that run a certain version of an OS. They can be customized to install certain packages when you build them. You can them perform tests with RSpec on them or boot up a server and work with the development version of the site and see if your code has the desired effect.

I found troubleshooting a little difficult at first under this setup since you need to pass commands to Docker. You can't simply use `bash` or any other terminal to run them. Also, the server has to be up and running in order to run those commands. This can lead to a lot of frustration.

## Connecting to the DB

My first major hurdle was to connect to the database so I can see more directly what was happening 'under the hood'. Luckily, Docker, by default will forward it's ports to the localhost, so you can access it as if it were running on your own system.

If that is not the case, and the Docker image is not being forwarded to the localhost for whatever reason, you can still find the ip of a Docker image pretty simply. First, we take a look at all the images running locally.

`docker ps`

This will give you a list of images that are currently running that may look a little something like this:

```
CONTAINER ID   IMAGE                     COMMAND                  CREATED        STATUS          PORTS                                       NAMES
697b8685d509   openfoodnetwork_web       "bash -c 'wait-for-i…"   12 hours ago   Up 10 seconds   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   openfoodnetwork_web_1
8ec13ea014c2   openfoodnetwork_worker    "bash -c 'wait-for-i…"   12 hours ago   Up 11 seconds                                               openfoodnetwork_worker_1
9171e4c62f72   postgres:10.19            "docker-entrypoint.s…"   12 hours ago   Up 31 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   openfoodnetwork_db_1
5015b1895607   openfoodnetwork_webpack   "./bin/webpack-dev-s…"   12 hours ago   Up 11 seconds   0.0.0.0:3035->3035/tcp, :::3035->3035/tcp   openfoodnetwork_webpack_1
9067a38ec683   redis                     "docker-entrypoint.s…"   12 hours ago   Up 11 seconds   6379/tcp                                    openfoodnetwork_redis_1
```

From there, you can look up the ip address of any image with the following command:

```
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' _container id_
```

From there you can plug in your details into your favorite database viewer. My personal favorite is [Dbeaver](https://dbeaver.io/), which is regularly updated and makes it very easy to connect to databases.

## Running just the RSpec you want

Another issue I was running into is the enormous test suite that comes with Open Food Network. It can easily take 20-30 minutes to run the entire suite which is simply not possible to do for every little change you want to make. It's much better to just run the specific test you want.

To do this, you can run rspec with a specific line number. The following command will run the spec in `enterprise_relationship_spec.rb` starting at line 258.

```
bundle exec rspec spec/models/enterprise_relationship_spec.rb:258
```

To run it inside your Docker image, you have two options.

### 1. With a Script 
You can create a script that sets up and tears down your Docker image every time you want to run an RSpec. The Open Food Network have [just a script](https://github.com/openfoodfoundation/openfoodnetwork/blob/master/docker/run) if you want to copy it for yourself.

Using the script above you just have to prepend the previous command with `docker/run`

```
docker/run bundle exec rspec spec/models/enterprise_relationship_spec.rb:258
```

### 2. Start Interactive Terminal 
You can also start a container with an interactive terminal much like the terminal on your localhost. 

```
docker exec -it $(docker-compose -f docker-compose.yml ps -q web) /bin/bash
```

Once you have the interactive terminal you can run commands normally as if you were using a terminal on your localhost.

```
bundle exec rspec spec/models/enterprise_relationship_spec.rb:258
```

## Using `binding.pry` on the live server

You can use `binding.pry` anywhere in Rails code to stop the execution of the code and start an interactive terminal session. If you are running a rails server on your local machine, you can simply interact with the terminal window that you started the server from.

However, with a Docker image things are a little different. When you use `binding.pry` the server will still halt execution, but you will not be able to interact with it in anyway. So you need to attach to that image in order to run commands and see what is happening. 

First, we need to find the image that is running the webserver. To do that we need to list the running Docker images.

```
docker ps
```

Again, we get a list of running images.

```
CONTAINER ID   IMAGE                     COMMAND                  CREATED        STATUS          PORTS                                       NAMES
697b8685d509   openfoodnetwork_web       "bash -c 'wait-for-i…"   12 hours ago   Up 10 seconds   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   openfoodnetwork_web_1
8ec13ea014c2   openfoodnetwork_worker    "bash -c 'wait-for-i…"   12 hours ago   Up 11 seconds                                               openfoodnetwork_worker_1
9171e4c62f72   postgres:10.19            "docker-entrypoint.s…"   12 hours ago   Up 31 minutes   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   openfoodnetwork_db_1
5015b1895607   openfoodnetwork_webpack   "./bin/webpack-dev-s…"   12 hours ago   Up 11 seconds   0.0.0.0:3035->3035/tcp, :::3035->3035/tcp   openfoodnetwork_webpack_1
9067a38ec683   redis                     "docker-entrypoint.s…"   12 hours ago   Up 11 seconds   6379/tcp                                    openfoodnetwork_redis_1
```

This time we want to attach to the running webserver. In my case, that is `openfoodnetwork_web`

```
docker attach 697b8685d509
```

From there, you can query local variables and pull records to see what is happening and troubleshoot the issue. I should mention that if you are running specs using either of the two methods I mentioned above, the interactive terminal will start normally in the terminal window you used to run the Rspec command.

## Conclusion

Those are some of the basic tips I learned while trying to troubleshoot a Rails application running in Docker. Of course, there are numerous ways to setup and troubleshoot an app like this, but these are the ways I found the most useful.

Do you have any other tips for using Docker? Let me know in the comments below.