Create And Dockerize Rails Application With PostgreSQL And Sidekiq (Docker + Docker Compose)
Tags: webdev, ruby, docker, sidekiq
Published: 2023-03-06 06:38:20

For this setup, I will use the ruby version 3.1.2 which will generate the rails app of rails version 7.0.4.

```
rails new ecs_rails_app -d postgresql
```

![rails new setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ucfos6w7g1c2ah0teyt.png)


Our application is created. Let’s create Dockerfile.
```
cd ecs_rails_app
```

```
# Creating Dockfile
touch Dockerfile
```

```
# Creating development directory and docker-compose file
mkdir development && touch development/docker-compose.yml
```

```
# Creating entrypoint.sh file
touch entrypoint.sh
```




#Dockerfile

Paste the following content into Dockerfile

```
FROM ruby:3.1.3

# install rails dependencies
RUN apt-get clean all && apt-get update -qq && apt-get install -y build-essential libpq-dev \
    curl gnupg2 apt-utils  postgresql-client postgresql-server-dev-all git libcurl3-dev cmake \
    libssl-dev pkg-config openssl imagemagick file nodejs npm yarn


RUN mkdir /rails-app
WORKDIR /rails-app

# Adding gems
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install

COPY . /rails-app

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
```


Entrypoint.sh

paste the following code into entrypoint.sh file

```
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /rails-app/tmp/pids/server.pid

exec "$@"
```

Now build the docker image.
```
docker build .
```

![Build Docker Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5oh4skabuz3vaboelhc.png)


#Docker Compose


I'll add Postgresql, Redis and web (our rails project) services in our docker compose file.
Firstly, we need some adjustment, database.yml file should look like this:

```
default: &default
  adapter: postgresql
  encoding: unicode
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  port: <%= ENV['DB_PORT'] %>
  host: <%= ENV['DB_HOST'] %>
  database: <%= ENV['DB_NAME'] %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default
```

Open the docker-compose.yml file located in development folder and paste the following code:

```
version: "3.8"
services:
  db:
    image: postgres
    restart: always
    environment:
     - POSTGRES_HOST_AUTH_METHOD=trust
    volumes:
      - db:/var/lib/postgresql/data'
    logging:
            driver: none
    ports:
      - 5432:5432
  redis:
    image: redis:4.0-alpine
    command: redis-server
    volumes:
      - redis:/data
    ports:
      - 6379
    logging:
            driver: none
  web:
    build: ../
    command: bundle exec rails s -p 3000 -e development -b '0.0.0.0'
    environment:
     DB_USERNAME: postgres
     DB_PASSWORD: password
     DB_NAME: ecs_application_db
     DB_PORT: 5432
     DB_HOST: db
     RAILS_ENV: development
     RAILS_MAX_THREADS: 5
     REDIS_HOST: redis
     REDIS_PORT: 6379
     BUNDLE_PATH: /bundle
    volumes:
      - ../:/rails-app
      - bundle:/bundle
    ports:
      - "3000:3000"
    depends_on:
      - "db"
      - "redis"
volumes:
  db:
  bundle:
  redis:
```

I have created 3 services (db, redis and web)

Our rails application requires postgresql database and redis (in the future for sidekiq). Docker compose is creating postgres and redis service for our rails application inside docker-compose.yml file.

- db service is using postgres docker image from docker hub
- redis service is using redis docker image from docker hub
- web service is our rails application project containing our own Dockerfile 

```
cd development/
docker-compose run web bundle install
docker-compose run web rails db:migrate
docker-compose run web rails db:setup
docker-compose build
```

![Build Docker Compose](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bxc1hsb5j14eb7upj6hm.png)

Then run the final command to instantiate rails server

```
docker-compose up
```

![Docker Compose Up](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/217yku24tfuvngnk3qn5.png)


![Server started](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/akxhoqt8zazzd6xm9nst.png)

![Run Locally](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jaimlt80yg224bf8oe3a.png)



#Configure sidekiq


Add gems into Gemfile:

```
gem 'sidekiq', '< 7'
gem 'redis-rails'
```

Create following files:

```
touch config/initializers/sidekiq.rb
```


Paste following code into sidekiq.rb file


```
# frozen_string_literal: true
sidekiq_config = { url: "redis://#{ENV['REDIS_HOST']}:#{ENV['REDIS_PORT']}/12" }
Sidekiq.configure_server do |config|
  config.redis = sidekiq_config
end
Sidekiq.configure_client do |config|
  config.redis = sidekiq_config
end
```

Go to development folder and install the new gems

```
docker-compose run web bundle install
```

We need to add a new service to the docker-compose.yml file

```
  sidekiq:
    build: ../
    command: bundle exec sidekiq
    volumes:
      - ../:/rails-app
    environment:
      RAILS_ENV: development
      REDIS_HOST: redis
      REDIS_PORT: 6379
    depends_on:
      - "redis"
```

then run

```
docker-compose up
```

![Docker compose up](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1k02xyfov8s0227rpf3.png)

![Docker container](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rd5vr3ac6dkm5xmcrk7e.png)



Then we will create a Controller, ActiveJob and some changes to the routes.


Create a controller and Active Job


```
docker-compose run web rails g controller home
docker-compose run web rails g job home
```

home_controller.rb

```
class HomeController < ApplicationController
    def index
        render json: {"message": "Welcome"}
        HomeJob.perform_later
      end
end
```

home_job.rb

```
class HomeJob < ApplicationJob
  queue_as :default
  def perform(*args)
    puts 'Job Executed'
  end
end
```

routes.rb

```
Rails.application.routes.draw do
  get '/home', to: 'home#index'  
end
```

then run

```
docker-compose build
docker-compose up
```

Open http://localhost:3000/home in your web browser,

![Localhost](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xj7fr52w4plch4nriogd.png)

in the console you should be able to see that the HomeJob has been performed.

![Job Executed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3t0pytryxs2s73sqjh1z.png)


![Yes.](https://blogger.googleusercontent.com/img/a/AVvXsEhvLybsL98FhjH9HbOLBKdJa68m4IduB4UOSKBG5PzK-yasJyZ4Z5pcuokCJg01EWrfoQbm2LNwQrI3CaI9wXPIQdRzkC3I4IaoKc3EEbt57WX_mUjedzyyc7K-XaCScAeZ-eVQRQ29CTvb7LMwRqHMrMr_NyHS5tQYk-b4tHXOV2GhTDa_oG4FJvyA=s320)