Consistency and scalability are essential in modern development.
Docker simplifies the deployment process by packaging applications into containers that can run reliably across different environments. While most guides focus on PostgreSQL with Rails, MongoDB is a powerful non-relational alternative that integrates seamlessly with Docker.
In this guide, weâll walk you through the steps to dockerize a Rails app with MongoDB. Whether youâre already familiar with Docker or just getting started, this article will help you efficiently set up and run your app.
Ready to streamline your development process? Contact us for expert Dockerization services!
Dockerizing Rails and MongoDB
A few weeks ago, we took on the challenge of dockerizing a Rails app that uses MongoDB. While there are plenty of guides available for setting up Rails with Postgres, we found it surprisingly hard to find resources for non-relational databases like MongoDB.
This gap in available documentation inspired us to create this guide, so you donât have to face the same obstacles.
Before we dive into the technical steps, letâs quickly review what Docker is and why itâs the ideal tool for this kind of project.
What is Docker?
Docker is an open-source platform that automates the deployment, scaling, and management of applications. It uses containerization technology to encapsulate apps and their dependencies into self-contained units that can run consistently across any system with Docker installed. For both local and remote deployments, Docker makes everything behave the same way.
Tired of setup issues? Discover how Dev Containers create a consistent environment for your Dockerized Rails app in our next article.
Advantages of Docker
- Consistency Across Multiple Environments: Docker containers enable apps to behave the same way everywhere, from a developerâs personal computer to a test environment to a production server.
- Isolation: Docker containers run separately from each other. This boosts security and lets you run multiple containers on one machine without them interfering with each other.
- Portability: Since Docker containers encapsulate everything an application needs to run (including the operating system). They can run on any machine that has Docker installed, rno matter the underlying operating system.
- Efficiency: Docker containers are lightweight and start quickly, making them much more efficient than virtual machines in terms of system resources.
- Version control and component reuse: Docker has features for version control and component reuse, enabling you to track changes, understand differences, or revert to previous versions of a container. You can also reuse components from existing Docker images, saving time and reducing complexity.
- Developer Productivity: Docker simplifies many aspects of software development, like setting up a development environment and managing dependencies. This can significantly boost developer productivity.
7 Steps to Containerizing Your Ruby on Rails App with MongoDB
Letâs dive into the details to get your Rails app containerized and running smoothly.
- Install Docker Desktop and prepare Ruby environment
- Create and configure the Dockerfile for your Rails app
- Define services (database and web app) in a compose.yml file.
- Build Docker images to containerize your app.
- Update the mongoid.yml file for MongoDB configuration.
- Start your containers with docker-compose up
- Access your app at localhost:3000.
Now, letâs break down each of these steps in detail to ensure a smooth process.
Step 1: Install Docker Desktop and prepare Ruby environment
- Install Docker Desktop: Start by downloading and installing Docker Desktop from Dockerâs official page. This will install several tools that you could install separately, but for the purpose of this post, we recommend using the installer.
- Fetch the Ruby image: Use the Ruby image from Docker Hub. In this case, weâll be using ruby:3.2-bullseye.
- Install dependencies: Install required dependencies for running a Rails project like Node.js as for compiling JavaScript assets in the asset pipeline.
- Create project directory: Make a working directory within the Docker file system for the project.
- Copy Gemfile and code: Copy the Gemfile and Gemfile.lock files into the Docker directory
- Install necessary gems: Run âbundle installâ to install the required gems.
â ď¸ Tip: When using a Ruby image from Docker Hub, make sure the Ruby version in your Gemfile matches exactly with the one in the Docker container. Or, you can just remove the Ruby version from the Gemfile to avoid any version mismatch errors.
Step 2: Create and configure the Dockerfile for your Rails app
Now that youâve set up Ruby, create a Dockerfile in the root directory of your project and create a file named Dockerfile without any extension.
Add the following application code to it, in order to configuring the environment:
FROM ruby:3.2-bullseye as base
RUN apt-get update -qq && apt-get install -y build-essential apt-utils libpq-dev nodejs
WORKDIR /docker/app
COPY Gemfile* ./
RUN bundle install
ADD . /docker/app
Letâs break this configuration down line by line:
- FROM ruby:3.2-bullseye as base: Specifies the base image for subsequent instructions, which is Ruby 3.2 on the Debian âbullseyeâ release.
- RUN apt-get update -qq && apt-get install -y build-essential apt-utils libpq-dev nodejs: Updates the package lists for upgrades and new installations, then installs essential packages for the Rails application. While not strictly necessary, itâs beneficial to start with the latest versions.
- WORKDIR /docker/app: Sets the working directory of the project to /docker/app in the Docker container. All subsequent commands will be run from this directory.
- COPY Gemfile ./*: Copies the Gemfile and Gemfile.lock from your project to the current directory in the Docker container.
- RUN bundle install: Installs the Ruby dependencies specified in the Gemfile.
- ADD . /docker/app: Copies the entire current directory (your Rails application) into the /docker/app directory in the Docker container.
By following these steps, you now have a Docker container configured to run your Rails app with Ruby and all required dependencies.
Step 3: Define services in a compose.yml file
Now, we need to set up the MongoDB database to get it fully operational. According to the documentation, to have MongoDB working, you need to create another container and connect it to the Rails container via a Docker Network.
In order to avoid manual setup, we will create a second configuration file.
A Dockerfile sets up the environment for a single Docker container, but it doesnât handle the orchestration of multiple containers. In a typical app, you might have several services running in separate containers that need to talk to each other. This is where Docker Compose comes in.
- Create a new file named compose.yml at the root of your project, just like the Dockerfile. This file describes the services that make up your appâin this case, a MongoDB database and a Rails web app.
The compose.yml file specifies how to get each serviceâs Docker image: the database uses a pre-made MongoDB image, and the web app is built from the current directory. It also outlines the configuration needed to link these services together.
With Docker Compose, each service joins a default network, making them reachable and discoverable by other services on it. This means your Rails and MongoDB services can interact without you having to manually create a network.
Your new file will look like this:
services:
db:
container_name: my_database_container
image: mongo:6.0
restart: always
ports:
- "27017:27017"
web:
container_name: my_web_container
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db # This responds to the service name, not the container's name.
Note: When using depends_on: db, Docker enables the service named db to start before the web service. However, note that these services start asynchronously; one does not wait for the other to fully start before launching.
â ď¸ Make sure the Rails server is accessible externally by using the -b â0.00.0â flag in the start command. Without this, you might run into âaddress not foundâ errors.
Step 4: Build Docker images to containerize your app
To build your project using the configuration specified in the compose.yml file, run:
./my_project: $ docker compose build
This command builds all the services defined in your compose.yml file that have a build context specified (if you use the -f
flag you can specify another file, but we wonât focus on this topic today).
For each of these services, Docker performs the following steps:
- Use the specified Dockerfile to build each image. In our case, Docker will use the Dockerfile we created previously to build the web service.
- Build a new image according to the instructions in the Dockerfile.
- Tag the new image with the name specified in the compose.yml file, if one is provided.
The result is a Docker image for each service that you can then start with the command docker compose up
. If the images were already built and no changes were made to the Dockerfile
or the build context, the existing images will be used.
Step 5: Update the mongoid.yml file for MongoDB configuration
If we were to run the web app in its current state, it would break immediately because the database configuration would be incorrectâit needs to point to the MongoDB container.
To access our database, you must establish a new host for all Rails environments in the mongoid.yml
file.
Below, we share the code snippet where we set up the host for the development environment by specifying the name of the database service defined in the Docker Compose file:
development:
clients:
default:
database: app_development
hosts:
- db:27017 # "db" is the name of MongoDB service in `compose.yml` we created in the previous section.
options:
server_selection_timeout: 1
â ď¸ Note: While you can configure this file before containers are built, it has been intentionally placed after for demo purposes.
Step 6: Start containers with docker-compose up
We have successfully configured our Ruby on Rails and MongoDB services within Docker containers and corrected the MongoDB configuration inside the Rails app.
Now, itâs time to start your containers. To do so:
-
First, rebuild the containers using the
build
command mentioned earlier. -
Next, to start the web service and its associated database service, execute the following command in your terminal:
./my_project: $ docker compose up
This will start both the web and database services.
Step 7: Access your app
After configuring MongoDB, you can access your application at localhost:3000
in your browser.
â ď¸ Note: Keep in mind that the current MongoDB database is different from your initial one. After starting your app, youâll need to reinitialize the database if you had any data stored before. You can do this with a seed task or through your appâs interface.
Taking advantage of the Docker client
Thereâs a better and much more powerful way to see logs and use specific terminal prompts from a desired container. Just go to your Docker client and pick the container that holds our web and database services.
There, you can choose each one and head over to the exec tab to get a respective command prompt.
The Docker Client
Inside the Docker client, we can see our compose container running, holding our web and database containers.
The compose container logs
If we click the compose container (in this case, the my_project container), we can see the logs output from both web and database services.
The web service console
Then, we can also click on a specific container service and use its own isolated console.
â ď¸ Note: If you push your image to Docker Hub, you can tell the web service to use the name_of_your_image_in_dockerhub and not build it locally but fetch it from the Hub instead. Just like we did with the âdbâ service using the mongo:6 image.
All in all⌠Docker for Rails
Dockerizing a Rails app with MongoDB can significantly streamline your development and deployment processes. By following the steps in this guide, you can create a Dockerfile and a compose.yml file to define and manage your appâs services. This approach boosts consistency across different environments and simplifies the setup process for new team members.
With Docker, you can build, ship, and run your app anywhere, making your workflow more efficient and reliable. Dockerization makes it easier to scale, move, and manage dependencies for your Rails and MongoDB apps.
Partnering for your growth
At Seta Workshop, weâre here to help you unlock the full potential of Docker.
As a nearshore software development company, we offer a unique blend of proximity and expertise to meet your needs. Our team of experts is ready to support your growth and streamline your development and deployment processes. Letâs work together to make your projects more efficient and scalable.
Ready to Dockerize your Rails app with MongoDB? Contact us for guidance and support!