We are living as nomad in Cyprus !!
docker

Build Docker + Ruby on Rails + MySQL development environment

How to build Docker + Ruby on Rails + MySQL development environment. Docker compose is a tool for defining and running multi-container Docker applications such as Ruby on Rails + MySQL.

Contents

Install Docker

Access to the Docker Docs page to install Docker.

Install Docker for Mac Install Docker for Windows Install Docker for Linux

noknow also wrote a blog how to install Docker.

Docker

Mac OSにDockerをインストールする

Create a new project path

Create a new project path as "noknow".

Terminal

$ mkdir noknow
$ cd noknow

The final directory structure would be as follows:

The final directory structure

noknow
  /docker-compose.yml
  /mysql
    /Dockerfile
    /my.cnf
  /rails
    /.browserslistrc
    /.git
    /.gitignore
    /.ruby-version
    /Dockerfile
    /Gemfile
    /Gemfile.lock
    /README.md
    /Rakefile
    /app
    /babel.config.js
    /bin
    /config
    /config.ru
    /db
    /lib
    /log
    /node_modules
    /package.json
    /postcss.config.js
    /public
    /storage
    /test
    /tmp
    /vendor
    /yarn.lock

Create docker-compose.yml

docker-compose.yml

version: "3.7"
services:
  db:
    build: mysql
    image: noknow_db
    container_name: noknow_db
    ports:
      - 3306:3306
  app:
    build: rails
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    image: noknow_app
    container_name: noknow_app
    ports:
      - 3000:3000
    volumes:
      - ./rails:/noknowApp
    depends_on:
      - db

In services key, defines db and app.

- db: for MySQL

- app: for Ruby on Rails

About services: db:

- build: Would be read noknow/mysql/Dockerfile then build.

- image: When build is specified, the specified image from repository or local won't be build. Then the IMAGE of Docker would be "noknow_db".

- container_name: The NAMES of Docker would be "noknow_db".

- ports: Mapping by port 3306 in host side and port 3306 in the container side.

About services: app:

- build: Would be read noknow/rails/Dockerfile then build.

- command: Override a default command.

- image: When build is specified, the specified image from repository or local won't be build. Then the IMAGE of Docker would be "noknow_app".

- container_name: The NAMES of Docker would be "noknow_app".

- ports: Mapping by port 3000 in host side and port 3000 in the container side.

- volumes: Mount between noknow/rails in the host side and /noknowApp in the container side.

- depends_on: Start up service "app" after starting up service "db".

Create Dockerfile and my.cnf for MySQL

We set up build: mysql in docker-compose.yml so create a mysql directory and then move to there.

Terminal

$ cd noknow
$ mkdir mysql
$ cd mysql

Firstly, create a Dockerfile.

Dockerfile

FROM mysql:8.0.18

ENV MYSQL_ROOT_PASSWORD root_pass

COPY ./my.cnf /etc/mysql/conf.d/my.cnf
RUN mkdir /var/log/mysql
RUN chown mysql:mysql /var/log/mysql
RUN mkdir /var/run/mysql
RUN chown mysql:mysql /var/run/mysql

FROM: The target varsion of MySQL is 8.0.18.

MYSQL_ROOT_PASSWORD: Specifies root password for mysql login.

COPY: Copy my.cnf from host to container. When you copy it to container, the destination path should be "/etc/mysql/my.cnf", "/etc/mysql/conf.d/my.cnf" or "/etc/mysql/mysql.conf.d/my.cnf".

Create paths "/var/log/mysql" and "/var/log/mysql" in the container side to store MySQL log file and process file. And then change the permissions.

Next, create a my.cnf which is MySQL setting file.

my.cnf

[mysql]
default-character-set=utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin
datadir=/var/lib/mysql
socket=/var/run/mysql/mysql.sock
log-error=/var/log/mysql/mysqld.log
pid-file=/var/run/mysql/mysqld.pid
port=3306
default_authentication_plugin= mysql_native_password
[client]
default-character-set=utf8mb4

About default_authentication_plugin, When the version is more than 8, the default password authentication would be caching_sha2_password. You can change mysql_native_password if you want.

Create Dockerfile, Gemfile and Gemfile.lock for Ruby on Rails

We set up build: rails in docker-compose.yml so create a rails directory and then move to there.

Terminal

$ cd noknow
$ mkdir rails
$ cd rails

Firstly, create a Dockerfile.

Dockerfile

FROM ruby:2.6.5

ENV LANG C.UTF-8
ENV APP_HOME /noknowApp

RUN apt-get update -qq && apt-get install -y build-essential nodejs

# This is a error handling when to be occurred yarn error.
RUN apt-get update -qq && apt-get install -y curl && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && apt-get update && apt-get install -y yarn

RUN rm -rf /var/lib/apt/lists/*

RUN mkdir $APP_HOME
WORKDIR $APP_HOME
COPY ./Gemfile $APP_HOME/Gemfile
COPY ./Gemfile.lock $APP_HOME/Gemfile.lock
RUN bundle install
COPY . $APP_HOME

EXPOSE  3000

FROM: The target varsion of Ruby is 2.6.5.

ENV LANG C.UTF-8: Set to be able to use Japanese in Rails application.

ENV APP_HOME /noknowApp: This is the application source storage location on the container side.

RUN rm -rf /var/lib/apt/lists/*: In addition, when you clean up the apt cache by removing /var/lib/apt/lists, it reduces the image size.

Next, create a Gemfile.

Gemfile

source 'https://rubygems.org'
gem 'rails', '~> 6.0.0'

Lastly, create a Gemfile.lock.

This fils should be empty.

Terminal

$ touch Gemfile.lock

Create a new Rails application

Create a new rails application by rails new command.

Terminal

$ docker-compose run app rails new . --force --no-deps --database=mysql

// Created the rails application under noknow/rails directory.
ls rails
Dockerfile		Rakefile		config			log			public			vendor
Gemfile			app			config.ru		node_modules		storage			yarn.lock
Gemfile.lock		babel.config.js		db			package.json		test
README.md		bin			lib			postcss.config.js	tmp

Edit a database.yml

noknow/rails/config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: root_pass  // root user's password.
  host: db  // The services key defined in docker-compose.yml.

development:
  <<: *default
  database: noknowApp_development

test:
  <<: *default
  database: noknowApp_test

production:
  <<: *default
  database: noknowApp_production
  username: noknowApp
  password: <%= ENV['NOKNOWAPP_DATABASE_PASSWORD'] %>

Build a Docker image

Created all needed files so build a image.

Terminal

$ docker-compose build
...
Successfully built b43c6f4d3343
Successfully tagged noknow_app:latest

Boot an application by docker-compose

Terminal

$ docker-compose up -d  // -d: Start in background.
Creating network "noknow_default" with the default driver
Creating noknow_db ... done
Creating noknow_app ... done

// Create database which is model.
$ docker-compose run app rails db:create
Starting noknow_db ... done
Created database 'noknowApp_development'
Created database 'noknowApp_test'

// Check the container process.
$ docker-compose ps
   Name                 Command               State                 Ports              
---------------------------------------------------------------------------------------
noknow_app   bash -c rm -f tmp/pids/ser ...   Up      0.0.0.0:3000->3000/tcp           
noknow_db    docker-entrypoint.sh mysqld      Up      0.0.0.0:3306->3306/tcp, 33060/tcp

$ curl http://127.0.0.1:3000
// Output HMTL.

Error handling

ArgumentError: Malformed version number string 0.32+git

Webpacker would be used by default since rails6 so need to install yarn the newer version.

Added the line below in Dockerfile.

Dockerfile

...
RUN apt-get update -qq && apt-get install -y curl && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && apt-get update && apt-get install -y yarn
...

Plugin caching_sha2_password could not be loaded: caching_sha2_password.so: cannot open shared object file: No such file or directory

Here is the one way to solve it. Added the line below in my.cnf

my.cnf

[mysqld]
default_authentication_plugin= mysql_native_password
Search by keywords

Select Language

/

Follow us by