Apply Docker to Ruby on Rails app

Tram Ho

In this article, we will build a complete Rails application using docker. Applications will include Postgresql, Redis and Sidekiq.

Also, we will install Unicorn and Nginx for production.

After reading this article: Knowledge to use includes:

  • Basic knowledge of Docker
  • How Docker assists the development process
  • How you use CI / CD to build and test

What is Docker?

Docker allows us to package an application or service with all its dependent libraries or tools into one standard unit. This is called a Docker image .

The Docker image will contain all the code, runtime libraries, or system libraries to keep the server running.

Docker is different from Virtual Machine

We have tools like Vagrant, VirtualBox or VMWare which are all virtual machines _ virtualization technology, allowing you to isolate services, but there are many disadvantages.

That is, you need an entire operating system for each application you want to isolate. This takes quite a while to start up a virtual machine, and each virtual machine needs several GB of memory.

The Docker container takes a different approach, kernel sharing, and isolating is done through the linux kernel libraries and cgroups. Thanks to this, Docker is very light, and it only takes a few seconds for a container to start and the running process does not take up much space.

So how can you develop Rails apps in an isolated environment without using RVM or make it easier to change the Ruby version?

Or suppose you are a freelancer with 10 projects, you want to install or switch between projects without wasting disk space?

Or do you want to share your project on Github and other developers can download and run everything in a matter of minutes?

Benefits of Docker

If you want to improve productivity and make for a better programming experience, Docker fits those requirements, with benefits like:

1. Keep environmental parameters intact

Docker allows you to package applications and easily switch environments. It works effectively for all environments and on all devices that run Docker.

2. Expanding rapidly developing team

In the past, you might need up to 30 pages of documentation for new developers to show how to install locally. This can take a long time, and with new developers it is entirely possible that mistakes.

With Docker, all developers on the team can install applications or services that run automatically and efficiently, with just a few commands and a few minutes.

3. Use whatever technology is appropriate

If you only speak one language, you put yourself at a disadvantage and your programming skills lag. But by isolating the application in the Docker container, we can extend our programming knowledge vertically by experimenting with new languages ​​and frameworks.

You don’t have to worry about how other developers install technology. You can package them all into a Docker image and they just have to run the Docker container and that’s it.

4. Create an image once and use it many times

Because your application resides in a built-in Docker image, it can be run in seconds, making it very easy to scale.

Time for additional library work just need to rebuild. Once the image has been built, you can use it on multiple hosts.

This not only helps the scaling process quickly, but also makes deploying predictable and consistent.

5. Developers and operations managers can work together

Docker tools allow developers and operations managers to work together towards the common goal of deploying an application.

Docker acts as an abstract class. You can distribute the application to other members, and they do not need to know the detailed configuration of the environment.

Install Docker

How to install based on the operating system:

Linux: https://docs.docker.com/get-started/

Windows and Mac: https://www.docker.com/products/docker-desktop

Create Rails app

We will create a Rails project without having Ruby installed on the machine using the official Ruby Docker image version.

Create Rails Image

To create a Rails app in a Docker container, you need a Dockerfile . Dockerfile contains all the commands you need to create programs and libraries.

Create the file Dockerfile.rails :

The basic Dockerfile commands are:

  • FROM : specifies the image to start with. We’ll be using the official version of the Ruby image.
  • ARG : specifies parameter variables during build time. If you run in Linux, then the user and group id should be the same between host and docker container.
  • RUN : run commands in the container. For example, you use it to create a user and group and install Rails gems.
  • ENV : definition of environment variables
  • WORKDIR : specifies the current directory in the container.
  • USER : change the active user in the container.
  • CMD : run the program when the container starts

To build the image, we run the command:

Create Project

We will use the Rails image to create the project:

Docker runs a new container and runs the command rails new where:

  • -it : assigns your terminal process to the container.
  • -v $PWD:/opt/app : assigns the current directory of the host on your machine to the container, to map the files created in the corresponding copy container to your local machine.
  • rails new --skip-bundle rails_demo : This command is passed into the Rails image, to create a new project, rails_demo

After running the above command, you will see a new Rails folder.

Install a few main libraries

Edit Gemfile

Edit Database configuration

We edit the file config/database.yml :

We use environment variables to configure the app.

Add some config in the config/application.rb file:

Create Unicorn Config

Add file config/unicorn.rb :

Create installation file Sidekiq

We add the file config/initializers/sidekiq.rb :

Whitelist Docker Host

Rails has a security feature that is blocking access from undefined sources. I want other docker containers to communicate with each other, so need to add rails_demo containter to the whitelist.

We modify the file config/environment/development.rb :

Create an Environment variable file

Create an env file containing environment variables on par with the Dockerfile.rails file

The content of the environment variable file can be:

Copy the file to .env and need to remove .env from the git control:

Dockerizing Rails Application

Create a Dockerfile file:

This file creates a Docker image with:

  • NodeJS and Yarn
  • Rails
  • Gems in Gemfile

The last line of Dockerfile specified the user, added permissions for the file, and started the unicorn HTTP server.

Configure Ngnix

While unicorn is sufficient to support the application, for better performance and security goals, you should put an HTTP server first. An HTTP server is configured as a reverse proxy to protect the application from slow requests and speed up connection through cache.

We will use Nginx, and make the configuration file _ reverse-proxy.conf _ on par with Dockerfiles:

Create a new file called Dockerfile.nginx to create a custom Nginx image:

Create file dockerignore

Create a .dockerignore file with the following content:

This file is similar to .gitignore, the purpose is to ignore files or folders from the Docker image build process

What is Docker Compose?

Docker Compose allows you to run 1 or more Docker containers easily. You can define anything in the YAML file and the other developers just run the docker-compose up command and everything will run concurrently.

Create Docker Compose Configuration File

We create the file docker-compose.yml :

From the file above, we have:

  • Postgres and Redis use Docker volumes to save data for later.
  • Postgres, Redis and rails_demo both expose the same port
  • RailsDemo and Sidekiq both use volumes to mount the app code for direct editing
  • RailsDemo and Sidekiq both linked to Postgres and Redis and read the environment variables together from .env
  • Sidekiq overrides the default CMD command to run Sidekiq instead of Unicorn

Create Volumes

In the file docker-compose.yml, we use the same volumes that do not exist yet, we can create them with the following commands:

Once the data is stored in PostgreSQL or Redis, it will be stored in volumes on your local machine. This way, you don’t need to worry about data being lost when restarting service, because Docker container is stateless.

Run everything

Let’s run everything with the command:

The above command will take a long time to run for the first time because it needs to load all the Docker images that the application requests.

This process is fast and slow depending on the network speed

Then the terminal will show:

However, the rails_demo_1 container reported an error that the database doesn’t exist. That’s because we haven’t initialized the database when we ran the Rails app.

Database initialization

Press CTRL + C in terminal to stop up command and run the following commands to create database.

We run the up command again to initialize all:

Test the service

Let’s check again in the link: http: // localhost: 8020

Works with Rails app

Currently the source code is on my machine, and the source code has been mounted in the Docker container directly through the volume. That means every time you edit a file, the changes will be reflected immediately.

For example:

Create a Controller

Run the following command to create the Page controller:

Recompile Assets

To recompile CSS and JavaScript code or use webpack for optimization, we use the command:

In this article, we have built a fairly complete Rails application with technology stacks using Docker

Everyone can see the code on Github: https://github.com/sonlh-0262/docker-rails

In the next section, we will learn how to use Docker with CI / CD

Share the news now

Source : Viblo