環境
- ruby 2.4.1
- Rails 5.1.0(+Puma)
- MySQL 5.7
- Wercker CI
- RSpec + FactoryGirl + Faker
- Rubocop
- Brakeman
Dockerfile
FROM ruby:2.4.1
ENV APP_ROOT /usr/src/app
ENV ENTRYKIT_VERSION 0.4.0
WORKDIR $APP_ROOT
EXPOSE 3000
## SSLのレポジトリをインストールできるようにします
RUN apt-get update && apt-get install -y apt-transport-https
## yarnのレポジトリをインストールします
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
## Nodejsのレポジトリをインストールします
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
# 依存ライブラリをインストールします
RUN apt-get update && apt-get install -y \
      nodejs \
      mysql-client \
      postgresql-client \
      sqlite3 \
      yarn \
      --no-install-recommends && rm -rf /var/lib/apt/lists/*
# EntryKitのインストール
RUN apt-get install openssl \
  && rm -rf /var/cache/apk/* \
  && 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
# Rubyのライブラリをインストール
COPY Gemfile $APP_ROOT
COPY Gemfile.lock $APP_ROOT
RUN bundle install --jobs=4
# レポジトリの内容をコピーしておきます
COPY . $APP_ROOT
# サーバー起動前の処理を定義します
ENTRYPOINT [ \
  # 起動前準備スクリプトです。実行権限をつけます。
  "prehook", "chmod +x boot.sh", "--", \
  # 起動前準備スクリプトを実行します。
  "prehook", "bash ./boot.sh", "--"]
解説
アプリのルートディレクトリは/usr/src/appにしていますがこれは特に理由はありません。好みでOKです。yarnのレポジトリがSSLになっているのですが、使っているイメージruby-2.4.1では下記のエラーが出てインストールできませんでした。
E: The method driver /usr/lib/apt/methods/https could not be found.apt-transport-httpsを入れて解決してあります。
## SSLのレポジトリをインストールできるようにします
RUN apt-get update && apt-get install -y apt-transport-https
boot.sh
# Rubyのバージョンを表示します。
ruby -v
# Rubyのライブラリをインストールします。
bundle install -j4
# フロントのライブラリをインストールします。
yarn install --no-optional
# 特定のサーバー・ポートが起動するまで待つスクリプトです。実行権限をつけます。
chmod +x wait-for-it.sh
# MySQL起動を待ちます
./wait-for-it.sh mysql:3306
# DBを更新します。
rake db:create
rake db:migrate
# railsサーバーが起動済だったら殺します
kill -s 9 `pgrep -f 'rails s' `
# pidファイルを消します
rm -f app/tmp/pids/server.pid
- 依存ライブラリの解決
- MySQLの起動待ち
- DBの更新
- rails sの二重起動防止(killspidファイルも消し、)
MySQLの起動待ちにはwait-for-itを使っています。(rootに配置)
docker-compose.yml
version: '3'
services:
  # Railsサーバー
  app:
    build: . # Dockerfileを元にビルドします
    environment:
      RAILS_ENV: development
      DATABASE_URL: mysql2://root:pass@mysql:3306
      PORT: 3000
    ports:
      - 3000:3000
    volumes:
      - .:/usr/src/app
      - bundle:/usr/local/bundle
    depends_on:
      - mysql
    command: ["rails", "s", "-b", "0.0.0.0"]
  # MySQL
  mysql:
    image: mysql:5.7.10
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
    ports:
      - 7207:3306
    volumes:
      - mysql-data:/var/lib/mysql
# グローバルにvolumesを書くとホストボリュームになり、ファイルを永続化できます。
volumes:
  mysql-data:
    driver: local
  bundle:
    driver: local
これによりbundle installにやり直しが発生しません。MySQLのデータも永続化している為、開発環境のデータが毎回クリアされることもありません。
また、rails5.1からPORT:3000と指定しないとデフォルトの9292ポートでpumaが起動してしまいます。(バグかは追っていません)
config/application.rb
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module App
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.1
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
    config.generators do |g|
      g.stylesheets false
      g.javascripts false
      g.helper false
      g.test_framework :rspec, view_specs: false, helper_specs: false, fixture: true
      g.template_engine = :slim
    end
  end
end
rails g(enerate) のコマンドの設定を書いています。
- スタイルシート・JS・ヘルパーの生成を無効に(必要なファイルだけ後で生成します)
- テストフレームワークはrspecに
- テンプレートエンジンはslimに
Gemfile
source 'https://rubygems.org'
git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.1.0'
# Use mysql2 as the database for Active Record
gem 'mysql2'
# Use Puma as the app server
gem 'puma', '~> 3.7'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
# テンプレートエンジンにslimを使います
gem 'slim-rails'
# Use Capistrano for deployment
gem 'capistrano-rails', group: :development
group :development, :test do
  # セキュリティチェックのBrakemanを導入
  gem 'brakeman', :require => false
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  # Fixtureの代替となるFactoryGirlを導入
  gem 'factory_girl_rails'
  # テストデータ生成のFakerを導入
  gem 'faker'
  # Adds Support for RSpec unit testing
  gem 'rspec-rails', '~> 3.5'
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '~> 2.13.0'
  gem 'selenium-webdriver'
  # CSチェック
  gem 'rubocop', require: false
end
group :development do
  # HTML/ERBからslimに変換します
  gem 'html2slim'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
  gem 'web-console', '>= 3.3.0'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
Gemfileは日本語注釈がついたものを追加したのと、redis, bcryptあたりは後々使いそうだったのでコメントを外しています。
開発運用
docker-compose up -d(初回のみ)docker-compose logs(うまく動かない時のログを見る)
docker-compose restart(gem等がうまくrailsサーバーに伝わらない時実行)
docker-compose down(コンテナを落とす)
docker-compose rm(イメージを消す)
docker-compose exec app bash (擬似的にシェルログインできます。アプリサーバーでコマンド実行 ※これで普通にrailsコマンドが実行できるようになります)
wercker.yml
# 下記を参考に作成しています
# http://qiita.com/masashi-sutou/items/d0fcec3a14c1c89ae702
# This references the default Ruby container from
# the Docker Hub.
# https://registry.hub.docker.com/_/ruby/
# If you want to use a specific version you would use a tag:
# ruby:2.2.2
box: ruby:2.4.1
# You can also use services such as databases. Read more on our dev center:
# http://devcenter.wercker.com/docs/services/index.html
# services:
    # - postgres
    # http://devcenter.wercker.com/docs/services/postgresql.html
    # - mongo
    # http://devcenter.wercker.com/docs/services/mongodb.html
services:
  - id: mysql
    env:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_USER: test_user
      MYSQL_PASSWORD: test_password
      MYSQL_DATABASE: test_database
# This is the build pipeline. Pipelines are the core of wercker
# Read more about pipelines on our dev center
# http://devcenter.wercker.com/docs/pipelines/index.html
build:
    # Steps make up the actions in your pipeline
    # Read more about steps on our dev center:
    # http://devcenter.wercker.com/docs/steps/index.html
    steps:
        - install-packages:
            name: Install mysql client
            packages: mysql-client
        - rails-database-yml:
            service: mysql-docker
        - bundle-install:
            jobs: 4
        - script:
            name: Run RSpec
            code: bundle exec rspec
        - script:
            name: Run Brakeman
            code: bundle exec brakeman -qz
mysql clientをインストールする前にbundle installすると、bundle install時にリンクに失敗しているのか、libmysqlclientが見つからないエラーが出ます。
bundle installの結果は永続化されている為、2回目以降のビルドが高速です。
開発が進んだ後で、アプリのビルドイメージを作ってレポジトリに上げたものを使うようにwerckerの設定を修正する予定です。
参考記事・サイト
- Dockerで起動したMySQLのデータを永続化する - ログってなんぼ http://okisanjp.hatenablog.jp/entry/docker_data_volume_container
- 開発しやすいRails on Docker環境の作り方 - Qiita http://qiita.com/joker1007/items/9f54e763ae640f757cfb
- Debian に Docker をインストールしたときのメモ - Qiita http://qiita.com/deep_tkkn/items/38c90cc7ae8ae749a6ae
- Entrykit のすすめ - Qiita http://qiita.com/spesnova/items/bae6406bf69d2dc6f88b
- アプリのサーバーサイドをRailsで構築する - Qiita http://qiita.com/masashi-sutou/items/d0fcec3a14c1c89ae702
- rspecを実行した時にcannot load such file -- spec_helper (LoadError)と言われる解決方法 - Qiita http://qiita.com/pugiemonn/items/55dd0a07c262c2010e2c
