passenger-dockerでRailsアプリをコンテナ化する（1. 開発モードでコンテナ化する）

<img width="962" alt="passenger-rails.png" src="https://qiita-image-store.s3.amazonaws.com/0/141934/0c5b68a4-9d55-3172-1f58-1d95ae6cb67f.png">

## 参考

[phusion/passenger\-docker: Docker base images for Ruby, Python, Node\.js and Meteor web apps](https://github.com/phusion/passenger-docker)

# 全体の流れ

1. 開発モードでコンテナ化する　←今回の投稿
2. [コンテナからDBに接続できるようにする](https://qiita.com/NaokiIshimura/items/dd76d67ca023bc9351ce)
3. [本番モードでコンテナ化する](https://qiita.com/NaokiIshimura/items/bfaeb07fc14a1e05102f)

# 今回やること

- 開発モード(development)でRailsアプリをコンテナ化する

# 次回以降にやること

- RailsアプリのコンテナからDBに接続できるようにする
- 本番モード(production)でRailsアプリをコンテナ化する

# もくじ

1. Railsアプリを作成
2. Dockerfileの作成
3. nginxコンフィグを作成
4. コンテナをビルド
5. コンテナをローカルで起動

# ソース一式

今回の投稿のために用意したソースは下記で公開しております。
[qiita\-rails\-passenger\-docker/1 at master · NaokiIshimura/qiita\-rails\-passenger\-docker](https://github.com/NaokiIshimura/qiita-rails-passenger-docker/tree/master/1)

# ディレクトリ構成

今回の投稿のために用意した作業ディレクトリは以下の構成です。

| ディレクトリ | 内容 |
| :--- | :--- |
| / | Dockerfile |
| /nginx | nginxコンフィグ一式 |
| /rails-app | railsのソース一式 |

![passenger-rails-102.png](https://qiita-image-store.s3.amazonaws.com/0/141934/df43de4c-6dff-b7a4-7adc-339ee41b8f8b.png)


# 1. Railsアプリを作成

まずはコンテナ化するRailsアプリを用意します。
今回はアクセスした時に静的ページを表示するだけのアプリを用意しました。

![passenger-rails-101.png](https://qiita-image-store.s3.amazonaws.com/0/141934/326acedc-678d-a52f-c8e0-ff3056efe8e6.png)

# 2. Dockerfileの作成

Dockerfileについては[phusion/passenger\-docker](https://github.com/phusion/passenger-docker)リポジトリのREADMEを参考にRuby2.5を利用する設定としました。
今回は環境変数`RAILS_ENV`に`development`を指定してます。
今回は本番モード(production)で必要になる設定は省略してます。

```dockerfile:Dockerfile
##
# phusion/passenger-docker
# https://github.com/phusion/passenger-docker

##
# Getting started

# Ruby images
FROM phusion/passenger-ruby25:latest

# ...put your own build instructions here...

##
# Nginx

# Using Nginx and Passenger
RUN rm -f /etc/service/nginx/down

# Using Nginx and Passenger
RUN rm /etc/nginx/sites-enabled/default
ADD nginx/webapp.conf /etc/nginx/sites-enabled/webapp.conf

# Configuring Nginx
ADD nginx/secret_key.conf /etc/nginx/main.d/secret_key.conf
ADD nginx/gzip_max.conf /etc/nginx/conf.d/gzip_max.conf

##
# Rails application

# Set correct environment variables.
ENV RAILS_ENV development

# Your application should be placed inside /home/app.
COPY --chown=app:app rails-app /home/app/webapp

# bundlerのインストール
# 実行しなかった場合、Railsアプリにアクセスした時に以下のエラーが発生する
# cannot load such file -- bundler/dep_proxy (LoadError)
RUN gem install bundler

# tzdataのインストール
# 実行しなかった場合、Railsアプリにアクセスした時に以下のエラーが発生する
# tzinfo-data is not present.
# Please add gem 'tzinfo-data' to your Gemfile
# and run bundle install (TZInfo::DataSourceNotFound)
RUN apt-get update && apt-get install -y \
  tzdata

# タイムゾーンをJSTに設定
ENV TZ=Asia/Tokyo

# bundle install
WORKDIR /home/app/webapp
RUN bundle install

# Clean up APT when done.
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Use baseimage-docker's init process.
CMD ["/sbin/my_init"]
```

#3. nginxコンフィグを作成
 
Dockerfileと同様に[phusion/passenger\-docker](https://github.com/phusion/passenger-docker)リポジトリのREADMEを参考にRuby2.5を利用する設定としました。
今回はパラメータ`passenger_app_env`に`development`を指定してます。
今回は本番モード(production)で必要になる設定は省略してます。

```nginx:nginx/webapp.conf
server {
  listen 80;
  server_name www.webapp.com;
  root /home/app/webapp/public;

  # The following deploys your Ruby/Python/Node.js/Meteor app on Passenger.

  # Not familiar with Passenger, and used (G)Unicorn/Thin/Puma/pure Node before?
  # Yes, this is all you need to deploy on Passenger! All the reverse proxying,
  # socket setup, process management, etc are all taken care automatically for
  # you! Learn more at https://www.phusionpassenger.com/.
  passenger_enabled on;
  passenger_user app;

  # If this is a Ruby app, specify a Ruby version:
  passenger_ruby /usr/bin/ruby2.5;

  # Ensures that RAILS_ENV, NODE_ENV, etc are set to "staging"
  # when your application is started.
  passenger_app_env development;

}
```

```nginx:nginx/secret_key.conf
env SECRET_KEY=123456;
```

```nginx:nginx/gzip_max.conf
gzip_comp_level 9;
```

# 4. コンテナをビルド

```shell-session
$ docker build -t rails-image .

...
Successfully built f1dc75a6cd5b
Successfully tagged rails-image:latest
```

# 5. コンテナをローカルで起動

```shell-session
$ docker run -p 3000:80  rails-image
```

ブラウザで`http://localhost:3000`にアクセスしてRailsアプリが表示されることを確認

![passenger-rails-101.png](https://qiita-image-store.s3.amazonaws.com/0/141934/326acedc-678d-a52f-c8e0-ff3056efe8e6.png)


# 補足

コンテナのビルドに成功してもRailsアプリへアクセスする際にエラーが発生することがあったので、エラー回避のために追加した設定について記録として残しておきます。

## エラー回避１

以下は`cannot load such file -- bundler/dep_proxy (LoadError)`を回避するために追加した記述です。

```dockerfile:Dockerfile
RUN gem install bundler
```

指定がなかった時には以下のエラーが発生してました。

```shell-session
cannot load such file -- bundler/dep_proxy (LoadError)
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:135:in `require'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:135:in `rescue in require'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:39:in `require'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:888:in `block (2 levels) in expand_dependencies'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:887:in `each'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:887:in `block in expand_dependencies'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:874:in `each'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:874:in `expand_dependencies'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:806:in `converge_locked_specs'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:247:in `resolve'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:170:in `specs'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:237:in `specs_for'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/definition.rb:226:in `requested_specs'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/runtime.rb:108:in `block in definition_method'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/runtime.rb:20:in `setup'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler.rb:107:in `setup'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/bundler-1.16.1/lib/bundler/setup.rb:20:in `<top (required)>'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
  /usr/lib/ruby/vendor_ruby/phusion_passenger/loader_shared_helpers.rb:456:in `activate_gem'
  /usr/lib/ruby/vendor_ruby/phusion_passenger/loader_shared_helpers.rb:323:in `block in run_load_path_setup_code'
  /usr/lib/ruby/vendor_ruby/phusion_passenger/loader_shared_helpers.rb:461:in `running_bundler'
  /usr/lib/ruby/vendor_ruby/phusion_passenger/loader_shared_helpers.rb:322:in `run_load_path_setup_code'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:100:in `preload_app'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:156:in `<module:App>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:30:in `<module:PhusionPassenger>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:29:in `<main>'
```

参考：[Getting "bundler: failed to load command: rake" after upgrading to ruby 2\.5\.0 · Issue \#8978 · travis\-ci/travis\-ci](https://github.com/travis-ci/travis-ci/issues/8978)

## エラー回避２

以下は`cannot load such file -- bundler/dep_proxy (LoadError)`を回避するために追加した記述です。
Gemfileを修正しても回避できますが、毎回Gemfileを書き換えるのは手間なので`tzdata`をインストールして回避することにしました。

```dockerfile:Dockerfile
RUN apt-get update && apt-get install -y \
  tzdata
```

指定がなかった時には以下のエラーが発生してました。

```shell-session
tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install (TZInfo::DataSourceNotFound)
  /usr/local/rvm/gems/ruby-2.5.0/gems/activesupport-5.1.5/lib/active_support/railtie.rb:22:in `rescue in block in <class:Railtie>'
  /usr/local/rvm/gems/ruby-2.5.0/gems/activesupport-5.1.5/lib/active_support/railtie.rb:19:in `block in <class:Railtie>'
  /usr/local/rvm/gems/ruby-2.5.0/gems/railties-5.1.5/lib/rails/initializable.rb:30:in `instance_exec'
  /usr/local/rvm/gems/ruby-2.5.0/gems/railties-5.1.5/lib/rails/initializable.rb:30:in `run'
  /usr/local/rvm/gems/ruby-2.5.0/gems/railties-5.1.5/lib/rails/initializable.rb:59:in `block in run_initializers'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:228:in `block in tsort_each'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:431:in `each_strongly_connected_component_from'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:349:in `block in each_strongly_connected_component'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:347:in `each'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:347:in `call'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:347:in `each_strongly_connected_component'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:226:in `tsort_each'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/2.5.0/tsort.rb:205:in `tsort_each'
  /usr/local/rvm/gems/ruby-2.5.0/gems/railties-5.1.5/lib/rails/initializable.rb:58:in `run_initializers'
  /usr/local/rvm/gems/ruby-2.5.0/gems/railties-5.1.5/lib/rails/application.rb:353:in `initialize!'
  /home/app/webapp/config/environment.rb:5:in `<top (required)>'
  config.ru:3:in `require_relative'
  config.ru:3:in `block in <main>'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/rack-2.0.4/lib/rack/builder.rb:55:in `instance_eval'
  /usr/local/rvm/rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/rack-2.0.4/lib/rack/builder.rb:55:in `initialize'
  config.ru:1:in `new'
  config.ru:1:in `<main>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:110:in `eval'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:110:in `preload_app'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:156:in `<module:App>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:30:in `<module:PhusionPassenger>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:29:in `<main>'
```