Max Rukomoynikov

I love to create. Developer and designer. Looking forward to make cool things.

Rails on Docker

Why Docker?

It has always been easier to supply the necessary tools locally. If you need to have multiple versions, then rvm or nvm solve the problem. Then came Docker. Until this year, I had successfully managed to avoid it. On projects where the guys worked with Docker, I instead installed everything locally. But, I thought that enough fighting and it's time to try to live with the idea of "docker for everything". It's simply time to admit either i work using Docker or i don't work at all.

Generating Ruby on Rails application

Well I don't have ruby installed locally. And I need to generate a new Rails application or experiment in IRB.

The first thing I did was look at the official Rails image. It turned out to be deprecated, and the authors suggested Ruby as a replacement.Using Ruby image, I was unable to generate a Rails application, so Imade my own Docker image.

FROM debian:bullseye

WORKDIR /app

ARG ruby_version=2.7.1
ARG PG_MAJOR=13
ARG NODE_MAJOR=14

# Installing general packages
RUN apt update \
  && apt upgrade -y \
  && apt install libpq-dev postgresql-client-$PG_MAJOR gnupg2 git wget curl vim build-essential libssl-dev zlib1g-dev libyaml-dev libffi-dev -y

# Installing rbenv and ruby
RUN apt install rbenv -y \
  && echo 'eval "$(rbenv init -)"' >> ~/.bashrc \
  && rbenv install $ruby_version \
    && rbenv global $ruby_version \
  && eval "$(rbenv init -)" \
  && gem install rails

#Installing node and yarn
RUN curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR.x | bash - \
  && apt install nodejs \
  && npm i -g yarn

ENV PATH /root/.rbenv/versions/$ruby_version/bin/:/root/.rbenv/shims:$PATH

Using the image

The following command will generate a new Rails application in the current folder and install required gems in the gems folder. As you know, a container cannot change its content after it has been built.Therefore, all application files and gems will be stored on the host machine.

docker run --rm -v /$(pwd):/app rukomoynikov/rails rails new .

Launching the application is not much more difficult. But, in a simple form, it will only work if you use the sqlite database.

docker run --rm -it -p 3000:3000 -v /$(pwd):/app rukomoynikov/rails rails s -b 0.0.0.0

Running IRB. Or you can enter console and run ruby files from local machine.

docker run --rm -it -p 3000:3000 -v /$(pwd):/app rukomoynikov/rails bash

What's next?

Above you saw an example of basic Rails application used SQLite. In order to use Postgresql and Webpacker you need something more complicated than simple Dockerfile. You need docker-compose. There you will be able to separate application into a ruby service, and the client service.

Here is example of docker-compose.yml

services:
  web:
    image: rukomoynikov/rails:2.7.1
    volumes:
      - ./:/app
      - rails_cache:/app/tmp/cache
      - bundle:/usr/local/bundle
    ports:
      - 3000:3000
    tmpfs:
      - /tmp
      - /app/tmp/pids
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    command: bundle exec rails server -b 0.0.0.0
  client:
    image: rukomoynikov/rails:2.7.1
    command: yarn run build -w
    ports:
      - '3035:3035'
    volumes:
      - ./:/app:cached
      - bundle:/usr/local/bundle
      - node_modules:/app/node_modules
      - packs:/app/public/packs
    environment:
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
  postgres:
    image: postgres:13
    volumes:
      - postgres:/var/lib/postgresql/data
    environment:
      PSQL_HISTFILE: /root/log/.psql_history
      POSTGRES_PASSWORD: postgres
    ports:
      - 5432
    healthcheck:
      test: pg_isready -U postgres -h 127.0.0.1
      interval: 5s
  redis:
    image: redis:3.2-alpine
    volumes:
      - redis:/data
    ports:
      - 6379
    healthcheck:
      test: redis-cli ping
      interval: 1s
      timeout: 3s
      retries: 30

volumes:
  postgres:
  redis:
  bundle:
  rails_cache:
  node_modules:
  packs: