How to use Docker with Ruby on Rails applications.
Tags: ruby, rails, docker
Published: 2023-02-18 05:15:00

## What is docker? and how to use it with ruby on rails applications? and benefits of using docker.

Docker is a platform for building, shipping, and running applications in containers. A container is a lightweight, standalone, and executable package of software that includes everything needed to run an application, including code, runtime, libraries, system tools, and settings. Docker makes it easy to package an application and all its dependencies into a single container, which can then be deployed to any environment that supports Docker.

Docker provides a way to package and distribute your application as a container, which makes it easier to manage dependencies, ensure consistent environments across different servers, and simplify deployment.

**Here are some of the benefits of using Docker with Ruby on Rails applications:

**Consistent development environments**: By using Docker to create a container that contains all the necessary dependencies and tools for your application, you can ensure that all developers are working in the same environment. This can help prevent issues caused by differences in operating systems or installed software.

**Easier deployment**: Docker allows you to package your application and its dependencies into a single container, which can then be deployed to any server that supports Docker. This makes it easier to move your application between development, staging, and production environments.

**Improved scalability**: Docker containers can be easily replicated and scaled horizontally, allowing you to handle more traffic by spinning up additional containers as needed. This can help improve the performance and reliability of your application.

**Simplified maintenance**: With Docker, you can isolate your application and its dependencies from the host system, which makes it easier to maintain and update your application without affecting other applications running on the same server.

Overall, using Docker with Ruby on Rails applications can help simplify development, deployment, and maintenance, while improving the performance and scalability of your application.

## Here's a step-by-step example of how to use Docker with a Ruby on Rails application, Sidekiq, Redis, and PostgreSQL:

Step 1: Install Docker
Before you can use Docker, you need to install it on your system. You can download and install Docker from the official website.

Step 2: Create a new Rails application
Assuming you already have Ruby installed on your system, you can create a new Rails application with the following command:
`$ rails new myapp`

Step 3: Add Sidekiq to your application
To use Sidekiq with your Rails application, you need to add the sidekiq gem to your Gemfile and run bundle install. You should also generate a config/sidekiq.yml file with the following command: 
`$ bundle exec sidekiq --config config/sidekiq.yml`

Step 4: Add Redis to your application
To use Redis with Sidekiq, you need to add the redis gem to your Gemfile and run bundle install. You should also configure Redis in your `config/sidekiq.yml` file.

Step 5: Add PostgreSQL to your application
To use PostgreSQL with your Rails application, you need to add the pg gem to your Gemfile and run bundle install. You should also update your `config/database.yml` file to use PostgreSQL.

Step 6: Create a Dockerfile
Create a new file called Dockerfile in the root of your Rails application directory. This file will define the Docker image for your application. Here's an example Dockerfile for a Rails application with Sidekiq, Redis, and PostgreSQL:

```ruby
# Use an official Ruby runtime as a parent image
FROM ruby:3.0.3

# Set the working directory
WORKDIR /app

# Install dependencies
RUN apt-get update && \
    apt-get install -y \
    build-essential \
    nodejs \
    postgresql-client && \
    rm -rf /var/lib/apt/lists/*

# Install gems
COPY Gemfile Gemfile.lock ./
RUN gem install bundler && \
    bundle install --jobs 4

# Copy the application code
COPY . .

# Expose ports
EXPOSE 3000

# Set the entrypoint command
CMD ["rails", "server", "-b", "0.0.0.0"]
```

Step 7: Create a `docker-compose.yml` file
Create a new file called `docker-compose.yml` in the root of your Rails application directory. This file will define the Docker services for your application. Here's an example `docker-compose.yml` file for a Rails application with Sidekiq, Redis, and PostgreSQL:

```ruby
version: "3"
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis
  db:
    image: postgres:12
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: myapp_development
  redis:
    image: redis:6.0
```

Step 8: Build and start the Docker containers
To build and start the Docker containers for your application, run the following command in the root of your Rails application directory:
`$ docker-compose up --build`

This will build the Docker images and start the containers for your application, Sidekiq, Redis, and PostgreSQL.

Step 9: Access your application
Once the Docker containers are up and running, you should be able to access your Rails application in your web browser at `http://localhost:3000`. You should also be able to access the Sidekiq web interface at` http://localhost:3000/sidekiq`.

Step 10: Stop and remove the Docker containers
When you're finished working with your application, you can stop and remove the Docker containers with the following command in the root of your Rails application directory:
`$ docker-compose stop`

This will stop and remove the Docker containers for your application, Sidekiq, Redis, and PostgreSQL.

That's it! You've now used Docker to run a Ruby on Rails application with Sidekiq, Redis, and PostgreSQL. With Docker, you can easily package and run your application in any environment, making it easy to deploy and scale your application as needed.

## How to do it with production?

**Here's an example of how to deploy your Ruby on Rails application to a production environment using Docker and Docker Compose:**

Step 1: Build your Docker image

First, you need to build your Docker image for your Rails application. In the root of your Rails application directory, run the following command:
`$ docker build -t myapp .`

This will build a Docker image named myapp based on the Dockerfile in your Rails application directory.

Step 2: Push your Docker image to a registry

Next, you need to push your Docker image to a registry so that it can be deployed to your production environment. You can use a public registry like Docker Hub or a private registry like Amazon ECR or Google Container Registry.

To push your Docker image to Docker Hub, first create an account if you don't have one already. Then, tag your Docker image with your Docker Hub username and the name of your image repository:

`$ docker tag myapp your-dockerhub-username/myapp:latest`

Finally, push your Docker image to Docker Hub:
`$ docker push your-dockerhub-username/myapp:latest`

Step 3: Create a production Docker Compose file

Create a new file called `docker-compose.prod.yml` in the root of your Rails application directory. This file will define the Docker services for your production environment. Here's an example `docker-compose.prod.yml` file for a Rails application with Sidekiq, Redis, and PostgreSQL:

```ruby
version: "3"
services:
  web:
    image: your-dockerhub-username/myapp:latest
    environment:
      RAILS_ENV: production
      DATABASE_URL: "postgres://postgres:password@db/myapp_production"
      REDIS_URL: "redis://redis:6379/0"
    ports:
      - "80:3000"
    depends_on:
      - db
      - redis
    restart: always
  db:
    image: postgres:12
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp_production
    volumes:
      - db_data:/var/lib/postgresql/data
    restart: always
  redis:
    image: redis:6.0
    restart: always
volumes:
  db_data:
```
Note that the image property for the web service is set to the name of your Docker image on Docker Hub. The environment properties set environment variables that your Rails application will use to connect to PostgreSQL and Redis. The ports property maps port 80 on the host to port 3000 in the container. The depends_on property specifies that the web service depends on the db and redis services. The restart property specifies that the services should be restarted if they fail.

Step 4: Deploy your application to a server

To deploy your Rails application to a server, you'll need to install Docker and Docker Compose on the server.

Once Docker and Docker Compose are installed, copy your `docker-compose.prod.yml` file to the server and run the following command in the directory where the file is located:

`$ docker-compose -f docker-compose.prod.yml up -d`
This will start the Docker containers for your Rails application, Sidekiq, Redis, and PostgreSQL in the background.

Step 5: Access your application

Once the Docker containers are up and running, you should be able to access your Rails application in your web browser at http://your-server-ip-address. You should also be able to access the Sidekiq web interface at `http://your-server-ip-address/sidekiq`

Step 6: Update your application

To update your application, you'll need to build a new Docker image for your updated code and push it to your Docker registry. Then, on the server, you can pull the new image and start a new container using the following commands:

`$ docker pull your-dockerhub-username/myapp:latest`
`$ docker-compose -f docker-compose.prod.yml up -d`

This will pull the new Docker image and start a new container for your application, while leaving your database and Redis data intact.

Step 7: Monitor your application

To monitor your Rails application in production, you can use a tool like New Relic or Scout. These tools provide real-time monitoring and alerting for your application, so you can quickly identify and fix any issues that arise.

Step 8: Scale your application

To scale your Rails application in production, you can use Docker Compose to run multiple containers of your Rails application behind a load balancer. Here's an example `docker-compose.prod.yml` file for running multiple containers of your Rails application:

```ruby
version: "3"
services:
  web:
    image: your-dockerhub-username/myapp:latest
    environment:
      RAILS_ENV: production
      DATABASE_URL: "postgres://postgres:password@db/myapp_production"
      REDIS_URL: "redis://redis:6379/0"
    ports:
      - "80:3000"
    depends_on:
      - db
      - redis
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 2
        delay: 10s
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M
  db:
    image: postgres:12
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp_production
    volumes:
      - db_data:/var/lib/postgresql/data
  redis:
    image: redis:6.0
volumes:
  db_data:
```

Note that the web service has a deploy property that specifies that it should be run with 3 replicas. The update_config property specifies that updates should be rolled out with a maximum parallelism of 2 and a delay of 10 seconds between updates. The resources property sets resource limits and reservations for the containers.

With this configuration, you can use a load balancer like Nginx or HAProxy to distribute traffic across the multiple containers of your Rails application.

Configure a reverse proxy like Nginx or Apache to route incoming HTTP requests to the Docker container running your Rails application. You can configure the reverse proxy to listen on port 80 or 443 and forward requests to port 3000, which is the default port for Rails applications. You can also configure SSL/TLS encryption for secure connections. Here is an example of an Nginx configuration file for a Rails application:

```ruby
upstream myapp {
  server localhost:3000;
}

server {
  listen 80;
  server_name example.com;

  location / {
    proxy_pass http://myapp;
    proxy_set_header Host $host
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}
```

Thanks,
Harsh