[Ruby] Rails 6 (API mode) + MySQL Docker environment creation by docker-compose (for Mac)

7 minute read

Introduction

There was talk of making the environment docker in order to proceed with the complete renovation at the part-time job.
I decided to make it with the configuration of front end Nuxt.js and back end Rails 6, and I will be in charge of the back end part, so let’s write a Dockerfile a lot! So I will introduce the completed configuration by implementing it for studying as well.
How to make a Rails container is briefly written on Docker official page , but this time the Docker file considering Rails 6 I will also introduce how to write and how to create a MySQL container.

Own skills

It was about a year and a half ago that I started touching rails as an individual, and my practical development experience as a web engineer is just over a year, which is not a long period of time.
However, I am growing rapidly by taking advantage of the wide range of prerequisite knowledge I gained at university and the attitude of taking on various challenges.
Even in the previous project, I was touching around docker, changing the database container (MarinaDB-> MySQL), creating a shell script for initial setting, etc.
I didn’t have a chance to make docker from scratch by myself, so I tried this time.

docker environment creation

From here on, we will actually create an environment using docker.

file organization

First of all, I will briefly introduce the file structure.
Assuming that the name of the application to be created is sample, the files related this time have the following file structure.

sample 
|- backend --- app
|           |- bin
|           |- config --- ...
|           |          |- database.yml
|           |          |- ...
|           |- ...
|           |- Dockerfile
|           |- Gemfile
|           |- Gemfile.lock
|           |- ...
|- db --- data --- ...
|      |- my.cnf
|- docker-compose.yml

Actually, there will be more files (created), but these are the only files to be manipulated this time.

Creating required files

Next, I will describe the files related to docker.
backend/Dockerfile
This will be a file with instructions for building a Rails container. The contents are listed below, and the comments explain what each process is doing.

backend/Dockerfile


#Image and version to use
FROM ruby:2.7.1

#Install the required libraries
RUN apt-get update -qq && \
    apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs

#The following is rails 6 or later(Excluding API mode)Needed in
RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
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

#Create a folder called app in the container
#* The folder is not created on the local PC.
RUN mkdir /app
#Change root to app directory
ENV APP_ROOT /app
WORKDIR $APP_ROOT

#Gemfile in local PC(.lock)Into the container
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock

#Execute bundle install to copy the files on the local PC into the container
RUN bundle install
ADD . $APP_ROOT

#The port number that the container listens on
EXPOSE 3000

#Command to be executed
CMD ["rails", "server", "-b", "0.0.0.0"]

Since rails6, Webpacker is the default, so if yarn is not installed, an error will occur when doing rails new.
However, you do not need to install yarn when creating in API mode described later.

backend/Gemfile
Write Gemfile in advance to install Rails.
This file will be rewritten later when you do rails new.
Here, rails 6 or later version is specified.

backend/Gemfile


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

backend/Gemfile.lock
When you do bundle install, it will create something like a library blueprint based on the dependencies.
Create an empty one. Later I got an error if the file did not exist.

backend/Gemfile.lock


db/data/
Let’s prepare only the directory

db/my.cnf
This is a file related to MySQL settings.

my.cnf


[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
sql_mode=''

[client]
default-character-set=utf8mb4

The character code is set and the sql_mode is set.
Especially, I think it is better to set sql_mode.
This is because the default sql_mode has changed from MySQL 5.7, and especially in modes such as ʻonly_full_group_by, it often throws an error, so it is explicit which sql_mode` to use. Let’s write it down. This time, no setting (default for MySQL 5.6.5 or earlier) is explicitly specified.
(I want to write more articles around here)

docker-compose.yml
Finally write docker-compose.
A brief explanation is given in the comments.

docker-compose.yml


version: "3"
services:
  # MySQL
  db:
    #Image to build
    image: mysql:5.7
    #Specifying environment variables
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: spportunity
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      TZ: 'Asia/Tokyo'
    #Set the character code to utf8mb4
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      # db/Mount the data directory on the container's mysql directory
      - ./db/data/:/var/lib/mysql
      # /db/my.cnf file my in container.Mount on cnf config file
      - ./db/my.cnf:/etc/mysql/conf.d/my.cnf
    ports:
      - 3306:3306

  #Rails  
  backend:
    #Specify build source
    build:
      context: ./backend
      dockerfile: Dockerfile
    #Specifying the container name
    container_name: "sample-backend"
    #Command specification at startup Rails s is done after terminating the previous process
    command: bash -c "rm -f tmp/pids/server.pid && rails s -p 3000 -b '0.0.0.0'"
    #Mount the files in the backend folder to the app directory inside the container
    volumes:
      - ./backend/:/app
    ports:
      - "3000:3000"
    #Start after db container
    depends_on:
      - db

Now that the file is ready, let’s create a rails application.

Creating a rails application

Create a rails application using the docker-compose command.
Make sure the current directory is sample.

Create rails in normal mode (need to install yarn in dockerfile)

% docker-compose run backend rails new . --force --no-deps --database=mysql --skip-bundle

–Rewrite --force Gemfile
-- database = mysql … Specify MySQL for the database
–Skip --skip-bundle bundle (Gemfile.lock is not changed yet)

Create rails in API mode

% docker-compose run backend rails new . --force --no-deps --database=mysql --skip-bundle --api

-- api … Creation options in API mode

When completed, you will have a large number of rails related folders and files in the backend / folder.
I will write about the difference between API mode and normal mode and the difference between files.

Build container

% docker-compose build

Running this command will create a MySQL container and bundle install in the rails container.
If you look at the console, you can see that the contents of the Dockerfile are being executed in order.

Rails connection settings to db

backend/config/database.yml


default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: root
  host: db

development:
  <<: *default
  database: sample


test:
  <<: *default
  database: sample_test

production:
  <<: *default
  database: sample_production
  username: <%= ENV['APP_DATABASE_USER'] %>
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>

Change the connection information to the image of the MySQL container you created earlier for host, and the environment variables for the container you created earlier for your username and password.

Install Webpacker (unless in API mode)

% docker-compose run backend rails webpacker:install

Creating a database

% docker-compose run backend rails db:create

Start docker

If you come to this point, the setting is complete.
All you have to do is start docker!

% docker-compose up

Make sure Rails is up in your browser

When I access http: // localhost: 3000 / with a browser, Rails is launched successfully.
スクリーンショット 2020-07-15 21.24.05.png

Scalability

I didn’t mention it this time, but by adding a frontend container etc., it will be possible to create an environment that combines a frontend application and an API server in one shot.
In that case, you will have to create a Dockerfile and add a container to docker-compose in the same procedure.
I’m still a front-end beginner, so I’d like to eventually make a front container as well.

Impressions

After all docker is convenient.
I didn’t use docker in my personal development, but I’m thinking of using it positively from now on.
In that case, I would like to write an article.

It was my first time to write an article about qiita, and when I was wondering how much I should write, it became quite long.
However, there are many people who write a lot of very rich articles, and I feel that I still have a lot to do.
I may not be able to write something that still has content often, but I would like to publish my knowledge little by little.

Referenced

I referred to the following qiita article.
I also imitated the writing style, which was very helpful.
Thank you very much.

https://qiita.com/azul915/items/5b7063cbc80192343fc0
https://qiita.com/kodai_0122/items/795438d738386c2c1966

In addition to the above article, it also includes API mode, MySQL container mount and settings, etc., so please forgive the similar writing style.