3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ローカルRails6アプリのDocker環境への移行(ついでにMysql導入)

Last updated at Posted at 2021-01-19

#はじめに
ローカル環境でrailsを使用し開発を進めていましたが、今後のデプロイを考慮し、環境をDockerによるコンテナで管理することとしました。
初めてでかなり時間がかかってしまったため、備忘録として残します。
同様の環境構築が必要な方の参考になれば幸いです。

#環境構築にあたっての目標

  • ローカルの環境をコンテナ化し、本番環境構築時に容易にしたい。
  • Dockerのイメージは、効率化を考慮し、できるだけ軽量化したい。
  • bundleやyarnのモジュールを永続化することにより、起動にかかる時間を減らしておきたい。
  • DBはsqliteを使用していたので、ついでにMysqlにしたい。

#環境
###コンテナの構成

  • db
  • web
  • webpacker←webpack_dev_server実行用

###バージョン

  • ruby 2.7.2
  • Rails 6.0.3
  • Mysql 8.0.22

##一覧
今回変更した箇所のみ記載しています。
ルートディレクトリはrailsアプリのルートディレクトリとしています。

.
├── config
│   ├── database.yml    #更新
│   └── webpacker.yml   #更新
├── docker
│   └── rails
│       └── Dockerfile  #新規作成
├── docker-compose.yml  #新規作成
├── .env                #新規作成
└── Gemfile             #更新

##Dockerfile

docker/rails/Dockerfile
#軽量化のため、alpineを使用。
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

#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", "--"]

###イメージの軽量化

今後の作業の効率化のため、イメージの軽量化するために、alpineを使用しています。
約1.6GB→約400MBまで容量が減りました。

マルチステージビルドを使用し、nodejsのインストールを別にすることで、さらにイメージの軽量化ができそうです。
ある程度軽量化できたので、今回はここまでとしました。

###ENTRY KITの導入

ENTRY KITを使用し、コンテナ起動時にyarn installbundle installを実行するようにしています。
調べた記事では、Dockerfile内で実行しているものが多かったですが、以下の問題があるため今回は見送りました。

  • gem等の追加が必要となった時は、コンテナのbuildからやり直す必要がある。
  • コンテナをdownすると、installしたgem等が保持されない。

そのためコンテナ起動時の実行かつ、モジュールを永続化することで、上記の問題を解決する構成としました。

##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:/app/vendor/bundle
      - node_modules:/app/node_modules
    tty: true            #binding.pry実行用
    stdin_open: true     #binding.pry実行用
    environment:
      WEBPACKER_DEV_SERVER_HOST: webpacker    #webpack_dev_server実行用のコンテナを指定
      BUNDLE_APP_CONFIG: ./.bundle
      NODE_ENV: development
      RAILS_ENV: development

  webpacker:             #webpack_dev_server実行用のコンテナ
    <<: *app_base
    command: bash -c "bundle exec bin/webpack-dev-server"
    depends_on:
      - web
    ports:
      - '3035:3035'
    tty: false           #binding.pry不要なのでfalseへ変更
    stdin_open: false    #binding.pry不要なのでfalseへ変更
    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:
  • DBのユーザ情報は別ファイルとしておきたかったので、変数化し.envに記載しています。
  • コンテナをdownさせても、DB、モジュールのデータが失われないよう、永続化しています。

##config/database.yml

database.yml
 default: &default
-  adapter: sqlite3
+  adapter: mysql2
+  username: app
+  password: password
+  host: db    #サービス名を指定

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

##config/webpacker.yml

webpacker.yml
 default: &default
   dev_server:
-    host: localhost
+    host: webpack    #サービス名を指定

##Gemfile

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

##.env

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

##疑問点・解消できなかったこと

###コンテナ初回起動時エラー(stack Error: getaddrinfo EAI_AGAIN nodejs.org)
コンテナ初回起動時のyarn install実行中に、エラーが発生することがあります。
調べた結果、原因はDNSで名前解決できていないことだそう。

解決方法と思われるホスト側のDNS変更や、docker-compose.ymlでのDNSの指定等試しましたが、解決しませんでした。
2回目起動時はエラーが発生せず、コンテナの再起動を解決方法としている記事もあったため、このままとしておきます。

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 node-gyp@3.8.0
web_1        | gyp info using node@12.20.1 | 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 

###マルチステージビルドでのイメージの軽量化
時間短縮等、更なる効率化が必要となった時に試してみようと思います。

#最後に
新規のRailsアプリをDockerで環境構築する記事はあったのですが、既存のRailsアプリをコンテナ化する記事はあまりなかったので苦労しました。
開発環境として一旦構築したので、テスト環境や本番環境の分け方・構築も検討して取り組んでいきます。

他にも以下の内容も取り組んでいきたいので、実施できれば記事にしようかと思います。

  • webサーバとしてnginxの導入
  • CI/CDの導入
  • AWS上での環境構築

###1/26追記
このままではRspec×Capybara×ChromeDriverが正常に動かなかったので別の記事を書きました。。。
Docker環境でRspec×Capybara×ChromeDriverを動作させる - Qiita

#参考にさせて頂いた記事
開発しやすいRails on Docker環境の作り方 - Qiita
Rails newからproductionモードで動くようになるまで - Qiita
Rails 6.0 × MySQL8でDocker環境構築(Alpineベース) - Qiita
Docker Composeのvolumesを使ってもっと効率的に - Qiita
【Dockerfile全解説】Rails本番環境のための一番シンプルなDockerイメージを作る - Qiita
【Docker】Rails開発で知っておきたい!gemの永続化による作業効率アップの話 | Enjoy IT Life
docker-composeでの環境構築で留意しておきたいところ - Qiita
Rails + webpacker on Dockerの環境をdocker-composeで構築する - RoadMovie

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?