I just started volunteering with the Open Food Network 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, 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 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.
Top comments (0)