RailsのDocker環境にEntrykitを導入し、bundle installを自動実行させる方法

インフラ

こんにちは。Enjoy IT Life管理人の仁科(@nishina555)です。

前回、『環境構築からデータ作成まで!Rails x MySQLのDocker Compose環境構築手順』でRuby on RailsのDocker環境構築方法について紹介をしました。

環境構築からデータ作成まで!Rails x MySQLのDocker Compose環境構築手順

上記の記事で紹介したDocker環境でRuby on Railsの開発はできますが、実は少しだけ問題点があります。

それは、新しくgemを追加した場合、Dockerイメージを再度ビルドしないとコンテナが起動できないという点です。

DockerイメージをビルドすることでDockerファイルで定義されているbundle installが実行されるのでコンテナは問題なく起動できます。

しかし、gemの追加後、もしDockerイメージのビルドせずにコンテナを起動すると、『Bundler::GemNotFound』というgemが見つからないことを意味するエラーが発生し、コンテナが起動できません↓

$ docker-compose up

Starting rails_app_db_1 ... done
Starting rails_app_web_1 ... done
Attaching to rails_app_db_1, rails_app_web_1
(中略)
web_1  | /usr/local/lib/ruby/2.6.0/bundler/resolver.rb:287:in `block in verify_gemfile_dependencies_are_found!': Could not find gem 'ransack' in any of the gem sources listed in your Gemfile. (Bundler::GemNotFound)

Ruby on Railsの場合、サーバーを起動する前にはRailsアプリで必要になるgemが全てインストールされている必要があります。
そのため、bundle installを忘れるとRailsアプリが起動できないというケースが発生します。

Railsアプリのbundle installのように、Dockerコンテナ起動時に確実に実行しておきたいコマンドが存在するケースがあります。
そのような時に利用すると便利なのが、今回紹介するEntrykitと呼ばれるツールです。

今回はRailsアプリを具体例にとり、Entrykitの活用方法について紹介したいと思います。

Entrykitについて

まずはEntrykitについて紹介をしたいと思います。

EntrykitとはDockerコンテナ起動時の実行タスクを処理するためのツールです。

Dockerコンテナを起動する際、メインプロセスを実行する前の事前準備としてスクリプトの実行や設定ファイルの配置などが必要になるケースがあります。

EntrykitではDockerコンテナ起動時に実行されるタスクを簡単に記述できる機能が用意されています。

そのため、Entrykitを活用することで、簡単な処理であればシェルスクリプトなどを用意することなくコンテナ起動時の実行タスクを処理することができます。

Entrykitでは4つのコマンドが用意されています。コマンドとその機能の対応は以下のようになっております。

コマンド 機能
prehook コンテナ起動時にコマンドを実行する
render テンプレート化したファイルに記載されている変数部分を動的に変更する
switch コンテナ起動時に実行できるコマンドを複数用意し切り替えられるようにする
codep 複数のプロセスを並列実行する

サンプルアプリの作成

Entrykitの具体的な活用事例を紹介するにあたり、まずはサンプルとなるDocker環境を構築していきます。

今回はサンプルアプリとして前回紹介したRuby on RailsのDocker環境を利用します。

環境構築からデータ作成まで!Rails x MySQLのDocker Compose環境構築手順

構築方法は上記の記事で紹介した手順と同じですので、前回の記事をご覧になられている方はこちらの項目は飛ばしていただいて問題ありません。

まずは作業ディレクトリの作成・移動をします。

$ mkdir rails_app && cd rails_app

Docker環境のrubyを利用してローカル環境にGemfileを用意します。

$ docker run --rm -v `pwd`:/rails_app -w /rails_app ruby:2.6 bundle init

作成されたGemfileの『gem “rails”』の部分のコメントアウトを外します。

Gemfile

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

- # gem "rails"
+ gem 'rails', '~> 5.0.2'

次にDockerfileを用意します。

Dockerfile

FROM ruby:2.6
WORKDIR /rails_app
COPY Gemfile* /rails_app/
RUN bundle install

上記のDockerfileをビルドしてDockerイメージを作成します。

$ docker build -t rails_app .

これでrailsが実行できるDockerイメージが作成できたので、rails newでRailsアプリの雛形を作成します。

$ docker run --rm -v `pwd`:/rails_app rails_app rails new . --database=mysql

Ruby on Rails側のデータベース接続設定を行います。

config/database.yml

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

次にdocker-compose.ymlを作成します。

docker-compose.yml

version: '3'
services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/rails_app
    depends_on:
      - db
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'

Dockerファイルを以下のように編集し、Ruby on Railsが起動するDockerイメージの準備をしておきましょう。

Dockerfile

FROM ruby:2.6
+ RUN apt-get update -qq && apt-get install -y nodejs
WORKDIR /rails_app
COPY Gemfile* /rails_app/
RUN bundle install

+ CMD ["rails", "server", "-b", "0.0.0.0"]

Dockerファイルを修正したので、イメージをビルドしなおします。

$ docker-compose build

Railsアプリで利用するデータベースを作成します。

$ docker-compose run web rake db:create

以上でサンプルとなるRailsアプリの雛形の作成が完了しました。

EntrykitをDocker環境に導入する方法

Entrykitには様々な機能がありますが、その中でも今回は『prehook』を利用し、Dockerコンテナ起動時にbundle installを自動実行できるようにしたいと思います。

Entrykitは2019年8月現在の最新版であるv0.4.0を利用します。1

先ほど作成したDockerファイルを以下のように編集します。

Dockerfile

  FROM ruby:2.6
- RUN apt-get update -qq && apt-get install -y nodejs
+ RUN apt-get update -qq && apt-get install -y nodejs wget

+ ENV ENTRYKIT_VERSION 0.4.0
+ 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

  WORKDIR /rails_app
  COPY Gemfile* /rails_app/
  RUN bundle install

+ ENTRYPOINT ["prehook", "bundle install", "--"]

  CMD ["rails", "server", "-b", "0.0.0.0"]

Entrykitの処理はENTRYPOINTと呼ばれるコンテナ起動時に実行される命令に記述します。

ここで、Entrykitのインストールを行う際のコマンドを&&で連結している理由について軽く触れておきます。

DockerイメージはDockerファイルで実行された命令単位でレイヤーを作成します。レイヤーの増加は最終的に出来上がるDockerイメージのサイズの肥大化の原因にもなります。

&&で実行コマンドを連結することでRUNの実行命令回数を減らすことができます。その結果、レイヤーも減ることになるため、Dockerイメージの軽量化が図れます。これが&&で実行命令を連結している理由です。

また、コマンドが連結しているとコードの可読性が下がるため、\を利用して適宜Dockerファイルに改行をいれています。

また、ENTRYPOINTに記述した--ですが、これはコマンドのつなぎ目を表現するものです。シェルでいう&&に近いような働きをします。
--をつけることでprehookの対象がbundle installのみであることを表現しています。

Entrykitの導入方法についてまとめると以下のようになります。

Entrykitの導入方法
  1. Entrykitをwget等でダウンロード
  2. entrykitコマンドを実行できるようにする
  3. ENTRYPOINTに実行命令を記述

サンプルアプリの起動確認

実際にEntrykitを導入したDocker環境でRailsアプリを実行していきましょう。

まずはDockerイメージをビルドします。

$ docker-compose build

ビルド後、gemを追加します。今回は例としてransackというgemを追加してみます。

Gemfile

+ gem 'ransack'

もしEntrykitが導入されていない場合、Dockerコンテナを起動すると以下のようなエラーが発生します。↓

$ docker-compose up

Starting rails_app_db_1 ... done
Starting rails_app_web_1 ... done
Attaching to rails_app_db_1, rails_app_web_1
(中略)
web_1  | /usr/local/lib/ruby/2.6.0/bundler/resolver.rb:287:in `block in verify_gemfile_dependencies_are_found!': Could not find gem 'ransack' in any of the gem sources listed in your Gemfile. (Bundler::GemNotFound)

一方、Entrykitを導入後はコンテナ起動時にbundle installが実行されます。
その証拠に、コンテナのログを確認するとコンテナ起動前には存在していなかったransackをインストールしていることがわかります。↓

$ docker-compose up

Starting rails_app_db_1 ... done
Starting rails_app_web_1 ... done
Attaching to rails_app_db_1, rails_app_web_1
(中略)
web_1  | Fetching ransack 2.3.0
web_1  | Installing ransack 2.3.0

bundle installがEntrykitのprehookにより実行されたため、コンテナ起動時にはRailsアプリで必要なgemが全てインストールされた状態になります。そのため、Railsアプリも正常に起動できます。

まとめ: コンテナ起動前の環境準備にはEntrykitを活用しよう

以上でEntrykitの紹介と、Entrykitのprehookを利用したRailsアプリのDocker環境構築手順について紹介をしました。

今回は紹介しませんでしたが、Entrykitに加えてgemのインストール先のディレクトリに対してデータボリュームを作成すれば、Entrykitによって自動でインストールされたgemを永続化することができます。

gemの永続化の方法については『【Docker】Rails開発で知っておきたい!gemの永続化による作業効率アップの話』で紹介していますので、こちらもあわせてご覧になっていただければと思います。

【Docker】Rails開発で知っておきたい!gemの永続化による作業効率アップの話

今回のまとめ
  • Entrykitにはprehook、render、switch、codepの計4つのコマンドが用意されている
  • Dockerファイルにインストール手順を追記することでentrykitが利用できるようになる
  • EntrykitのコマンドはENTRYPOINT命令に記載する

Entrykitはリリースのヒストリーを見ればわかる通り開発はそこまで活発に行われていない印象です。しかし非常に便利ですし、書籍などでも紹介されるほど知名度もあるツールです。

『Docker/Kubernetes実践コンテナ開発入門』でもEntrykitについて紹介されているので、さらにEntrykitについて学習されたいという方はご覧になってみてはいかがでしょうか。

この記事がいいなと思いましたらツイッター(@nishina555)のフォローもよろしくお願いします!