How to run a Rails development environment using docker

Mateo mojica
5 min readJun 9, 2023
Photo by Pat Whelen on Unsplash

Developing an application is a very daunting task on its own. Still, transitioning from just developing an application in your local environment into deploying said application in a production environment can be very frustrating because the setup of the application is very different between a dev and a prod environment. Add to this the number of packages and drivers you have installed into your computer that helps your application work correctly without you even noticing. To make this transition easier the idea is to take your local environment as close as it can be to the production one. The best way to accomplish this goal is to run your development environment using containers so they can be configured and even used in the production deployment. In this article, you are going to learn how to set up a dockerized development environment to make a ruby on rails application.

Let’s start with the concept of a container. A container is an isolated system that has everything you need to run an application inside it without any of the other overhead that physical machines have. In other words, is a little custom world where your application can live and run freely. If you want to learn more about containers and docker you can check out my article on the subject.

The advantage of having your development environment running on a container is that you eliminate the dreaded problem that every developer has at some point in their career, where you have to say “it works on my computer” to explain why the code is not working in production. Creating a container that is close to the production environment or even using the same image that is used to deploy the application (in case you use containers for the deployment) is the best way to shield yourself from any discrepancies in environments and you can almost guarantee that when the code is deployed it is going to work as intended. Another advantage of this approach is that it prevents any OS level or package update from breaking your environment.

Before we start you will need to install docker for the system you are using, you can check the documentation and follow the step by step to install it. Now let’s move on to setting up your development environment, the first thing you will need is to create a Docker file to create the image that the container is going to be based on. The template for the docker file is in the following code.

Dockerfile for a ruby development image

If you need a specific version of ruby you can check Dockerhub which base image you will need and change it in the “from” statement. Remember that all the ruby images are based on Linux so that is why all the commands in the Dockerfile are for a Linux-based system. After that, you just have to run the command docker image build <path to docker file>from your terminal, if you are using Docker Desktop the process is going to be different.

After you build the image for your container you can start developing with it, but probably you are not going to be developing with just Rails, you will also need other services like a database, and those services can also be run from containers without any effort from your side. To configure all those containers (app and extra services) you can use any orchestration tool but docker comes with one out-of-the-box called Docker compose. The template for your docker-compose file is the following code.

Docker-compose file

In that file, you have all the services that the application is going to need. For each service, you specify the image that it is going to be pulled from and the configuration options that you can find on the DockerHub page for that image. You also configure the app container where you tell it which command it is going to run when started, environment variables that it will have, and the volume (directory) that is going to be mapped to the app folder in the container, in this case, the docker file is stored in a folder within the project so the full project files are one level above, that is why it has a “..” as the local folder. Finally, you set any dependencies for the start of your app, in our case the app depends on the database to be running first. Finally, to run the application with all its containers you just have to run the command docker-compose -f <path to compose file> up on your terminal, this command will lock your terminal to show you all the requests that the app is handling as you would on a normal development environment, but if you want to run it and free up your terminal you have to add a -d at the end to run it in daemon mode.

Since you are developing you probably are going to need to run commands for your application to work properly and up to date. You can do this using the run option of docker-compose, followed by the name of the container and the command that you want to run. So for example, if you just generated a migration and want it to be reflected in your environment you just have to run docker-compose -f <path to compose file> run app rails db:migrate this will run that command on your container and update your database, same goes in case you need to access the rails console or if you installed a new gem and have to run the bundle install again.

This method is a great way to streamline and bring your development closer to the production state, but as with everything in software development, it comes with its trade-offs. The first one is a very annoying one, I develop on a Linux machine and it asks me for superuser permissions every time I want to save a file, and to create a file I have to do a touch using sudo otherwise I can’t create any new files, I’m pretty sure that there is a fix for it but I haven’t looked for it yet but it shouldn’t be that way. The other big tradeoff that this type of development comes with is that is harder to perform debugging with it. I rely a lot on the pry gem to debug my applications and with this type of development you can’t use it because it is locked inside the container and you can’t access it, to solve this you probably can use the interactive console option when you run the application but I haven’t tested it yet. These are the most important things that annoy me when developing with docker but I’m sure that there are solutions for both of them.

Besides the two downsides of developing with docker that I listed, I really think that using this type of development is very beneficial for the whole process and will reduce problems down the line since everybody is using basically the same environment in all stages. Thank you for reading this article, I hope it helped you and got you excited about developing using docker and if you liked it give it a clap and consider reading my other articles on different topics also consider following me to get notified when I publish something new.

References

--

--