[RUBY] "Rails 6 x MySQL 8" Docker environment construction procedure for sharing with teams

This time, I will introduce the procedure to build a Docker environment for a web application that combines Rails 6 and MySQL 8.

Webpacker is installed as standard from Rails 6, and the user authentication method has changed from MySQL 8, so there were various parts that were clogged with environment construction, so I hope it will be helpful.

In order to enable smooth development by multiple people, the goal is to create an environment where ** if you clone from a remote repository, the application will start up just by docker-compose up **.

The various versions are as follows.

The execution environment uses Docker Desktop for Mac (version 2.3.0.4).

Rails application preparation

Create / move directories. The Rails application name created this time is sample_app.

$ mkdir sample_app && cd $_

Create a Gemfile in the local environment using the ruby image. -v is an option for bind mount (synchronization of host and container directories).

By synchronizing the current directory of the host and the working directory of the container, the files created on the container are placed on the host.

$ docker run --rm -v `pwd`:/sample_app -w /sample_app ruby:2.7.1 bundle init

Uncomment the gem" rails " part of the created Gemfile and specify the rails version.

Gemfile


# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
- # gem "rails"
+ gem "rails", '~> 6.0.3.2'

Create a Dockerfile to build a Docker environment that runs rails new.

Rails 6 also runs rails webpacker: install when you create your application, so don't forget to install ** yarn. ** ** This time, use npm to install yarn.

Dockerfile


FROM ruby:2.7.1

RUN apt-get update -qq && \
    apt-get install -y nodejs \
                       npm && \
    npm install -g yarn

#Working directory/sample_Specified in app
WORKDIR /sample_app

#Copy local Gemfile to Dokcer
COPY Gemfile /sample_app/Gemfile

# /sample_bundle install on the app directory
RUN bundle install

Start the container using the image created by building the Dockerfile, and do rails new on the container.

$ docker build -t sample_app .

$ docker run --rm -v `pwd`:/sample_app sample_app rails new . –skip-bundle --database=mysql

Create docker-compose.yml.

This time, for the sake of brevity, I am connecting to MySQL as the root user. When connecting as a general user, it is necessary to set the following environment variables for the MySQL image.

Environment variable Contents
MYSQL_USER username
MYSQL_PASSWORD User password

--Reference: [Docker] An environment for connecting to multiple MySQL databases as a general user, understood by Rails Construction procedure

Database information is persisted by creating a named volume named mysql_data.

docker-compose.yml



version: '3'
services:
  web: #Container launched by Ruby on Rails
    build: .
    ports:
      - '3000:3000' #Make it accessible on localhost port 3000
    volumes:
      - .:/sample_app #Application file synchronization
    depends_on:
      - db
    command: ["rails", "server", "-b", "0.0.0.0"]
  db: #Container that MySQL starts
    image: mysql:8.0.21
    volumes:
      - mysql_data:/var/lib/mysql #Data persistence
    command: --default-authentication-plugin=mysql_native_password #Set the authentication method to 8 series or earlier.
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
      MYSQL_DATABASE: 'sample_app_development'
volumes:
  mysql_data: #Data volume registration

--Reference: Docker data is persisted! Introduction to environment construction starting from understanding Data Volume

I will give a supplementary explanation of the above docker-compose.yml.

The MySQL Docker image will create a database with the name set in MYSQL_DATABASE. Since the development environment of Ruby on Rails uses the database [application name] _development, sample_app_development is registered in MYSQL_DATABASE. Now you can have a database for your development environment without running rails db: create.

Starting with MySQL 8, the authentication method has changed from mysql_native_password to caching_sha2_password. With the MySQL 8 standard caching_sha2_password authentication method, it is not possible to connect to the database, and the following error message is displayed when starting the Rails application.


Mysql2::Error::ConnectionError

Plugin caching_sha2_password could not be loaded: /usr/lib/x86_64-linux-gnu/mariadb19/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory

スクリーンショット 2020-09-15 9.15.45.png

Therefore, --default-authentication-plugin = mysql_native_password is used to use the previous authentication method of mysql_native_password.

Next, set up the database connection for Ruby on Rails.

config/database.yml



default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: pass # (This time it's root)MYSQL_ROOT_Match with PASSWORD
  host: db #Set the database container name

Confirmation of launching Rails application

Now that you have a Docker environment that combines Ruby on Rails 6 and MySQL 8, let's start it.


$ docker-compose up

It is OK if you access localhost: 3000 and the following screen is displayed.

スクリーンショット 2020-09-15 9.23.43.png

Let's also check the persistence of data in the database. As an example, create a function related to ʻevent with scaffold`.


$ docker-compose exec web rails g scaffold event title:string
$ docker-compose exec web rails db:migrate

Access localhost: 3000 / events / new and register a record called" sample event "as an example.

It is OK if the data remains even if the container is deleted and started.

$ docker-compose down
$ docker-compose up

$ docker-compose exec web rails c
> Event.last.title
=> "Sample event"

Creating a database for the test environment

By creating a database of development environment using MYSQL_DATABASE, Rails application can be started without executing db: create.

However, ** this alone is not enough as a development environment ** because the database ([application name] _test) of the test environment used in the test code has not been created.

In MySQL Docker image, if you place scripts (.sql, .sh, .sql.gz) in /docker-entrypoint-initdb.d, it will be executed when the container starts. there is. [^ docker-entrypoint-initdb] Take advantage of this feature to create a database for the test environment.

** Scripts are executed in alphabetical order **, so if there is a dependency between scripts, be aware of the file name as well.

$ mkdir docker-entrypoint-initdb.d && cd $_
$ vim 00_create.sql

00_create.sql


--Create a database for the test environment
CREATE DATABASE sample_app_test;

In addition, the database access right of general users is only the database set to MYSQL_DATABASE. Therefore, ** When connecting to a database as a general user, it is necessary not only to create the database but also to grant the following access rights. ** **

01_grant.sql


--When using a general user named webapp
GRANT ALL ON `sample_app_test`.* TO webapp@'%';

--Reference: [Docker] An environment for connecting to multiple MySQL databases as a general user, understood by Rails Construction procedure

Add a bind mount so that the script you created can be read on the container.

docker-compose.yml


version: '3'
services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/sample_app
    depends_on:
      - db
    command: ["rails", "server", "-b", "0.0.0.0"]
  db:
    image: mysql:8.0.21
    volumes:
      - mysql_data:/var/lib/mysql
+     - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
      MYSQL_DATABASE: 'sample_app_development'
volumes:
  mysql_data:

Confirm that the database is created automatically

Delete and start the db container and check if the database is created automatically. It is OK if the databases of [application name] _development and [application name] _test exist.

#Create a database from scratch, also deleting database persistence information
$ docker-compose down --volumes

$ docker-compose up

$ docker-compose exec db mysql -uroot -ppass -D sample_app_development

mysql> show databases;
+------------------------+
| Database               |
+------------------------+
| information_schema     |
| mysql                  |
| performance_schema     |
| sample_app_development |
| sample_app_test        |← db for test has been created
| sys                    |
+------------------------+
6 rows in set (0.00 sec)

You can also connect successfully from a Rails application.

$ docker-compose exec web rails c

> ENV['RAILS_ENV']
=> "development

$ docker-compose exec web rails c -e test

> ENV['RAILS_ENV']
=> "test"

Make the environment start up just by "clone → docker-compose up"

The following patterns are often seen as a way to build a Rails development environment with Docker.

#Launch the container
$ docker-compose up

#Creating a database
$ docker-compose exec web rails db:create

#Table migration
$ docker-compose exec web rails db:migrate

The Rails application and the database are linked by docker-compose, and the database used by the application is built on the container.

There is no problem with the above method, but in this case ** It takes time to manually create the database and table on the container at the first startup. ** **

Considering the case of sharing the Docker environment with multiple people, it is ideal that the environment can be started by just doing docker-compose up after cloning the application file from the remote repository.

If possible, I would like to avoid the situation where I have to bother to tell the shared members "Create the database on the container at the first startup".

From here, if you clone from a remote repository, just do docker-compose up to configure the settings so that the Rails application can be started.

Run yarn install at container startup

In the development environment, source code synchronization using bind mout (synchronization of host and container directories) is often used.

The application file cloned from the remote repository has a package.json but no node_modules directory. Therefore, if you do docker-compose up after cloning, the directory without node_modules will be bind-mounted. As a result, an error prompting you to execute yarn install occurs and the application cannot be started.


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================

To disable this check, please change `check_yarn_integrity`
to `false` in your webpacker config file (config/webpacker.yml).

yarn check v1.22.5
info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.

To prevent this, you need to run yarn install when starting the container. For example, you can run yarn install at container startup by doing the following:

docker-compose.yml


version: '3'
services:
  web:
    build: .
+   command: ["./start.sh"]
-   command: ["rails", "server", "-b", "0.0.0.0"]
    ports:
      - '3000:3000'
    volumes:
      - .:/sample_app
    depends_on:
      - db
  db:
    image: mysql:8.0.21
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
      MYSQL_DATABASE: 'sample_app_development'

start.sh


#!/bin/bash -eu
yarn
rails server -b '0.0.0.0'

Change shell permissions.

$ chmod 755 start.sh

I call the shell with the command when starting the container, and execute yarn install in the shell. After executing yarn install, the Rails application will start on rails server, so the previous error will be resolved.

Allow migration to run automatically

As with yarn install, table migration should be executed by a shell script that is called when the container is started.

start.sh


#!/bin/bash -eu
yarn
+ rails db:migrate
rails server -b '0.0.0.0'

However, although you can control the container startup order by using depends_on of docker-compose.yml, you cannot wait for the container to start [^ startup-order], so prepare to start the db container. If db: migrate is executed before the end of, the migration will not be successful.

[^ startup-order]: Docker Doc "Control of startup order in Compose"

To automate the migration, you need to wait for the db container to start before db: migrate is executed.

There are several ways to wait for the database to be ready, but this time wait-for-it Here's how to use>.

If you place wait-for-it.sh in the current directory and make docker-compose.yml as follows, the script will be executed after waiting for the database to start.

docker-compose.yml


version: '3'
services:
  web:
    build: .
-   command: [""./start.sh"]
+   command: ["./wait-for-it.sh", "db:3306", "--", "./start.sh"]
    ports:
      - '3000:3000'
    volumes:
      - .:/sample_app
    depends_on:
      - db
  db:
    image: mysql:8.0.21
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
      MYSQL_DATABASE: 'sample_app_development'

Summary

This concludes the introduction of the procedure for building a Docker environment for Rails 6 + MySQL 8.

By executing the shell when the container is started, the development environment can be built smoothly even when multiple people use the Docker environment. This time, by calling the shell when the container is started, yarn install and db: migration are surely executed, but the command control when the container is started is <a href="https: //". You can also do it with a tool called github.com/progrium/entrykit "target="_blank"> Entrykit .

About Entrykit How to install Entrykit in Rails Docker environment and execute bundle install automatically </ strong> It is introduced in a>, so please have a look if you are interested.

--Summary of this time --From Rails 6, you need to install yarn in advance. --If a MySQL 8 authentication error occurs, resolve it by reverting to standard authentication. --By executing the shell when the container is started, it is possible to automate table creation etc.

at the end

I'm doing Twitter ( @ nishina555 ). I hope you will follow me!

Reference article

-Recommendation of Entrykit -Too polite Docker-compose rails5 + MySQL on Docker environment construction (Docker for Mac) -Steps for building a Ruby on Rails environment with Docker [Rails 6 compatible] -Detailed explanation of Ruby on Rails environment construction with Docker -I was addicted to building a Rails 6 development environment with Docker

Recommended Posts

"Rails 6 x MySQL 8" Docker environment construction procedure for sharing with teams
Rails + MySQL environment construction with Docker
[Environment construction with Docker] Rails 6 & MySQL 8
Procedure for building a Rails application development environment with Docker [Rails, MySQL, Docker]
[Docker] Rails 5.2 environment construction with docker
Build Rails (API) x MySQL x Nuxt.js environment with Docker
Environment construction with Docker for beginners
Rails on Docker environment construction procedure
Rails application development environment construction with Docker [Docker, Rails, Puma, Nginx, MySQL]
Rails environment construction with Docker (personal apocalypse)
Create Rails 6 + MySQL environment with Docker compose
Laravel + MySQL + phpMyadmin environment construction with Docker
Environment construction procedure for using PowerMock with JUnit
Wordpress local environment construction & development procedure with Docker
[Rails API x Docker] Easy environment construction with shell & operation check with Flutter
virtulbox + vagrant + Docker + nginx + puma + MySQL Rails environment construction
Stable development environment construction manual for "Rails6" with "Docker-compose"
Procedure for introducing Docker into the development environment of existing Rails applications [Rails, MySQL, Docker]
Environment construction of Rails5 + MySQL8.0 + top-level volumes with docker-compose
[Java] Environment construction procedure for developing struts 1.3 with Eclipse
[Rails / MySQL] Mac environment construction
React environment construction with Docker
Easy environment construction of MySQL and Redis with Docker and Alfred
Node.js environment construction with Docker Compose
Build Rails environment with Docker Compose
Ruby on Rails development environment construction with Docker + VSCode (Remote Container)
Rails 6 (API mode) + MySQL Docker environment creation by docker-compose (for Mac)
How to build Rails + Vue + MySQL environment with Docker [2020/09 latest version]
Build a development environment for Django + MySQL + nginx with Docker Compose
GPU environment construction with Docker [October 2020 version]
Building Rails 6 and PostgreSQL environment with Docker
Laravel development environment construction with Docker (Mac)
Deploy to heroku with Docker (Rails 6, MySQL)
Environment construction with Docker (Ubuntu20.04) + Laravel + nginx
Edit Mysql with commands in Docker environment
Create a MySQL environment with Docker from 0-> 1
Rails & React & Webpacker & MySQL Environment Construction Manual
CentOS8.2 (x86_64) + ruby2.5 + Rails5.2 + MariaDB (10.3.17) environment construction
How to build Rails 6 environment with Docker
Build debug environment on container --Build local development environment for Rails tutorial with Docker-
I built a rails environment with docker and mysql, but I got stuck
[Environment construction] Rails + MySQL + Docker (Beginners can also use it in 30 minutes!)
[Rails & Docker & MySQL environment construction] I started the container, but I can't find MySQL ...?
How to build a Ruby on Rails development environment with Docker (Rails 6.x)
Build a local development environment for Rails tutorials with Docker (Rails 6 + PostgreSQL + Webpack)
How to build a Ruby on Rails development environment with Docker (Rails 5.x)
Complete roadmap for building environment up to Docker + rails6 + MySQL + bootstrap, jquery
Docker environment construction
Spring Boot environment construction with Docker (January 2021 version)
Build a development environment for Docker + Rails6 + Postgresql
Introducing Rspec with Ruby on Rails x Docker
Environment construction command memo with Docker on AWS
[Ubuntu 18.04] Environment construction for using PyTorch with RTX3090
[Rails] Procedure for linking databases with Ruby On Rails
[Rails] How to build an environment with Docker
[First environment construction] I tried to create a Rails 6 + MySQL 8.0 + Docker environment on Windows 10.
Building an environment for WordPress, MySQL and phpMyAdmin with Docker Compose on EC2
A memorandum when building an environment with Ruby3.0 x Rails6.1 x Docker x CentOS Stream
How to build docker environment with Gradle for intelliJ
Docker x Rails 6 (memo)
Rails deploy with Docker