Migrate existing Rails 6 apps to Docker environment

Introduction

We were developing using rails in the local environment, but in consideration of future deployment, we decided to manage the environment in a container with Docker. It took a long time for the first time, so I will leave it as a memorandum. I hope it will be helpful for those who need to build a similar environment.

Goals for building an environment

Built environment

Container configuration

version

List

Only the parts changed this time are listed. The root directory is the root directory of the rails app.

.
├── config
│   ├── database.yml    #update
│   └── webpacker.yml   #update
├── docker
│   └── rails
│       └── Dockerfile  #Create New
├── docker-compose.yml  #Create New
├── .env                #Create New
└── Gemfile             #update

Dockerfile

Dockerfile


#Alpine is used for weight reduction.
FROM ruby:2.7.2-alpine3.12

ENV TZ="Asia/Tokyo" \
    LANG="C.UTF-8" \
    APP_ROOT="/app" \
    ENTRYKIT_VERSION="0.4.0"

WORKDIR $APP_ROOT

#Introduction of ENTRY KIT
RUN wget https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
    && tar -xvzf entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
    && rm entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \
    && mv entrykit /bin/entrykit \
    && chmod +x /bin/entrykit \
    && entrykit --symlink

RUN apk update \
&&  apk add --no-cache \
    alpine-sdk \
    bash \
    build-base \
	mysql-client \
    mysql-dev \
    nodejs \
    tzdata \
    yarn

COPY . $APP_ROOT

ENTRYPOINT [ \
  "prehook", "bundle install -j4 --quiet", "--", \
  "prehook", "yarn install --check-files --ignore-optional", "--"]

Image weight reduction

Alpine is used to reduce the weight of the image for the efficiency of future work. The capacity has been reduced from about 1.6GB to about 400MB.

By using a multi-stage build and installing nodejs separately, it seems that the image can be further reduced in weight. I was able to reduce the weight to some extent, so this time I decided to stop.

Introduction of ENTRY KIT

I am using ENTRY KIT to execute yarn install and bundle install when the container is started. In the articles I examined, most of them were executed in the Dockerfile, but due to the following problems, I forgot this time.

Therefore, it is configured to solve the above problem by executing it when the container is started and making the module persistent.

docker-compose.yml

docker-compose.yml


version: '3'

services:
  db:
    image: mysql:8.0.22
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports: 
      - '3306:3306'
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_DATABASE: ${DATABASE}
      MYSQL_ROOT_PASSWORD: ${ROOTPASS}
      MYSQL_USER: ${USERNAME}
      MYSQL_PASSWORD: ${USERPASS}

  web: &app_base
    build:
      context: .
      dockerfile: ./docker/rails/Dockerfile
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b 0.0.0.0"
    depends_on:
      - db
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - gem_modules:/vendor/bundle
      - node_modules:/node_modules
    tty: true            #binding.For pry execution
    stdin_open: true     #binding.For pry execution
    environment:
      WEBPACKER_DEV_SERVER_HOST: webpacker    #webpack_dev_Specify the container for server execution
      BUNDLE_APP_CONFIG: ./.bundle
      NODE_ENV: development
      RAILS_ENV: development

  webpacker:             #webpack_dev_container for server execution
    <<: *app_base
    command: bash -c "bundle exec bin/webpack-dev-server"
    depends_on:
      - web
    ports:
      - '3035:3035'
    tty: false           #binding.Change to false because pry is unnecessary
    stdin_open: false    #binding.Change to false because pry is unnecessary
    environment:
      BUNDLE_APP_CONFIG: ./.bundle
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
      NODE_ENV: development
      RAILS_ENV: development

volumes:
  db_data:
  gem_modules:
  node_modules:

database.yml

database.yml


 default: &default
-  adapter: sqlite3
+  adapter: mysql2
+  username: app
+  password: password
+  host: db    #Specify the service name

 development:
   <<: *default
-  database: db/development.sqlite3
+  database: mysql_development

webpacker.yml

webpacker.yml


 default: &default
   dev_server:
-    host: localhost
+    host: webpack    #Specify the service name

Gemfile

Gemfile


-gem 'sqlite3', '~> 1.4'
+gem 'mysql2', '0.5.3'

.env

.env


DATABASE=mysql_development
USERNAME=app
USERPASS=password
ROOTPASS=password

Questions / things that could not be resolved

First container startup error (stack Error: getaddrinfo EAI_AGAIN nodejs.org)

An error may occur during yarn install when the container is started for the first time. As a result of investigation, it seems that the cause is that the name cannot be resolved by DNS.

I tried changing the DNS on the host side, which seems to be the solution, and specifying the DNS in docker-compose.yml, but it did not solve. The error did not occur at the second startup, and there was an article that the solution was to restart the container, so leave it as it is.

error /app/node_modules/node-sass: Command failed.
web_1        | Exit code: 1
web_1        | Command: node scripts/build.js
web_1        | Arguments: 
web_1        | Directory: /app/node_modules/node-sass
web_1        | Output:
web_1        | Building: /usr/bin/node /app/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library=
web_1        | gyp info it worked if it ends with ok
web_1        | gyp verb cli [
web_1        | gyp verb cli   '/usr/bin/node',
web_1        | gyp verb cli   '/app/node_modules/node-gyp/bin/node-gyp.js',
web_1        | gyp verb cli   'rebuild',
web_1        | gyp verb cli   '--verbose',
web_1        | gyp verb cli   '--libsass_ext=',
web_1        | gyp verb cli   '--libsass_cflags=',
web_1        | gyp verb cli   '--libsass_ldflags=',
web_1        | gyp verb cli   '--libsass_library='
web_1        | gyp verb cli ]
web_1        | gyp info using [email protected]
web_1        | gyp info using [email protected] | linux | x64
web_1        | gyp verb command rebuild []
web_1        | gyp verb command clean []
web_1        | gyp verb clean removing "build" directory
web_1        | gyp verb command configure []
web_1        | gyp verb check python checking for Python executable "python2" in the PATH
web_1        | gyp verb `which` succeeded python2 /usr/bin/python2
web_1        | gyp verb check python version `/usr/bin/python2 -c "import sys; print "2.7.18
web_1        | gyp verb check python version .%s.%s" % sys.version_info[:3];"` returned: %j
web_1        | gyp verb get node dir no --target version specified, falling back to host node version: 12.20.1
web_1        | gyp verb command install [ '12.20.1' ]
web_1        | gyp verb install input version string "12.20.1"
web_1        | gyp verb install installing version: 12.20.1
web_1        | gyp verb install --ensure was passed, so won't reinstall if already installed
web_1        | gyp verb install version not already installed, continuing with install 12.20.1
web_1        | gyp verb ensuring nodedir is created /root/.node-gyp/12.20.1
web_1        | gyp verb created nodedir /root/.node-gyp
web_1        | gyp http GET https://nodejs.org/download/release/v12.20.1/node-v12.20.1-headers.tar.gz
web_1        | gyp WARN install got an error, rolling back install
web_1        | gyp verb command remove [ '12.20.1' ]
web_1        | gyp verb remove using node-gyp dir: /root/.node-gyp
web_1        | gyp verb remove removing target version: 12.20.1
web_1        | gyp verb remove removing development files for version: 12.20.1
web_1        | gyp ERR! configure error 
web_1        | gyp ERR! stack Error: getaddrinfo EAI_AGAIN nodejs.org
web_1        | gyp ERR! stack     at GetAddrInfoReqWrap.onlookup [as oncomplete](dns.js:66:26)
web_1        | gyp ERR! System Linux 4.19.121-linuxkit
web_1        | gyp ERR! command "/usr/bin/node" "/app/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
web_1        | gyp ERR! cwd /app/node_modules/node-sass
web_1        | gyp ERR! node -v v12.20.1
web_1        | gyp ERR! node-gyp -v v3.8.0
web_1        | gyp ERR! not ok 

Image weight reduction in multi-stage builds

I will try it when further efficiency is needed, such as shortening the time.

Finally

There was an article about building a new Rails app with Docker, but I had a hard time because there weren't many articles about containerizing existing Rails apps. Since it was built once as a development environment, we will consider and work on how to divide and build the test environment and production environment.

In addition, I would like to work on the following contents, so I will write an article if possible.

Articles that I used as a reference

** ・ How to create a Rails on Docker environment that is easy to develop --Qiita ** ** ・ From Rails new until it works in production mode --Qiita ** ** ・ Building Docker environment with Rails 6.0 x MySQL8 (Alpine base) --Qiita ** ** · More efficient with Docker Compose volumes-Qiita ** ** ・ [Dockerfile full explanation] Create the simplest Docker image for Rails production environment --Qiita ** ** ・ [Docker] I want to know about Rails development! Talk about improving work efficiency by making gem persistent | Enjoy IT Life ** ** ・ Points to keep in mind when building an environment with docker-compose --Qiita ** ** ・ Build Rails + webpacker on Docker environment with docker-compose --RoadMovie **

Recommended Posts

Migrate existing Rails 6 apps to Docker environment
[Rails 6] Dockerize existing Rails apps [Docker]
How to build Rails 6 environment with Docker
Rails Docker environment construction
[Rails] How to build an environment with Docker
Introduce dotenv to Docker + Rails to manage environment variables
[Docker] How to create a virtual environment for Rails and Nuxt.js apps
Introduce Docker to the development environment and test environment of existing Rails and MySQL applications
[Docker] Rails 5.2 environment construction with docker
Rails6 I tried to introduce Docker to an existing application
How to install Docker in the local environment of an existing Rails application [Rails 6 / MySQL 8]
How to build Rails, Postgres, ElasticSearch development environment with Docker
Migrate Docker image to another server
Build environment with vue.js + rails + docker
Build Rails environment with Docker Compose
Rails on Docker environment construction procedure
[Environment construction with Docker] Rails 6 & MySQL 8
Deploy Rails on Docker to heroku
Pass environment variables to docker container
Deploy Rails apps to Azure App Service using Docker & Continuous Deployment
Super beginner builds Rails6 + Postgresql environment with Docker to the end
How to install Pry after building Rails development environment with Docker
How to build Rails + Vue + MySQL environment with Docker [2020/09 latest version]
Rails environment construction with Docker (personal apocalypse)
Building Rails 6 and PostgreSQL environment with Docker
Create Rails 6 + MySQL environment with Docker compose
[Rails] How to use rails console with docker
[Docker] Building an environment to use Hugo
Deploy to heroku with Docker (Rails 6, MySQL)
Introduced Vue.js to an existing Rails app
Knowledge required to bring Rails apps to AWS
[Docker] Development environment construction Rails6 / Ruby2.7 / MySQL8
Show Better Errors in Rails + Docker environment
Introduced Vuetify to an existing Rails app
How to build a Ruby on Rails environment using Docker (for Docker beginners)
How to build a Ruby on Rails development environment with Docker (Rails 6.x)
How to migrate a web application created in a local docker environment to AWS
How to build a Ruby on Rails development environment with Docker (Rails 5.x)
Ruby on Rails ✕ Docker ✕ MySQL Introducing Docker and docker-compose to apps under development
How to apply Rails environment variables to Docker container (aws :: Sigv4 :: Errors solution)
Complete roadmap for building environment up to Docker + rails6 + MySQL + bootstrap, jquery
Build a development environment for Docker + Rails6 + Postgresql
Downgrade an existing app created with rails 5.2.4 to 5.1.6
[First environment construction] I tried to create a Rails 6 + MySQL 8.0 + Docker environment on Windows 10.
How to link Rails6 Vue (from environment construction)
(Basic authentication) environment variables in rails and Docker
Rails6 [API mode] + MySQL5.7 environment construction with Docker
Introducing New Relic to Rails apps on Heroku
Procedure for introducing Docker into the development environment of existing Rails applications [Rails, MySQL, Docker]
Rails6.0 ~ How to create an eco-friendly development environment
Rails Docker ~ Part 1 ~
Rails Docker ~ Part 2 ~
Build a development environment to create Ruby on Jets + React apps with Docker
Docker environment construction
About the case where "Docker" freeter tried to put Docker in the existing Rails application
[Rails] How to use PostgreSQL in Vagrant environment
Easy to display hello world with Rails + Docker
Temporarily move Docker environment from Mac to AWS
[Rails] [Docker] Copy and paste is OK! How to build a Rails development environment with Docker
Docker command to create Rails project with a single blow in environment without Ruby
Migration error after Activerecord association in Rails5 + Docker environment (2)