動機
私はRubyOn Railsのエンジニアです。
わたしのPCでは、rvm
, macports
をつかって開発していて、rubyのバージョン管理やその他周辺ライブラリのインストールではまったりすることが多かったことから、Dockerによる開発環境の仮想化を検討しました。
Dockerについての理解
Dockerはアプリケーション(プロセス)単位で実行環境を仮想化します(アプリケーションの実行に必要なファイルやディレクトリをまとめた「コンテナ」という単位での管理)。
ウェブアプリケーションであれば、webサーバ、DBをコンテナをそれぞれ作成し、それらを連携させることで機能させることができます。
ウェブアプリでは必須の「データ」の永続化に関しては、記憶領域をコンテナにして、DBと連携させることでホストから切り離すことができます。(postgresのインストールでハマりまくったので、非常に感動しました)
Docker でデータのポータビリティをあげ永続化しよう
これを使うことで、ローカルでの開発環境の手間を省けるだけでなく、環境をイメージとして、公開し、再配布できるというメリットもあります。
ホスト環境
- Mac OS X Yosemite (10.10.5)
- メモリ 4G
構築する環境
- Ruby On Rails (5.0.0)
- Ruby (2.3.1)
- PostgreSQL (9.5)
Docker for Macのインストール
-
https://docs.docker.com/engine/installation/mac/
こちらに従ってインストールします。macOS 10.10.3 Yosemite or newer
ではDocker for Mac を、それ以外ではDocker Toolboxをインストールします。今回はDocker for Macがインストールされたものとして進めます。
コマンド
細かいコマンドの説明は省きます。以下のステップで必要なものだけ説明します
参考ページ
以下のページを参考にさせていただきました。ありがとうございました。
-Docker で Rails5 の開発環境を「rails new」から構築する
-Railsアプリケーション開発を完全にDocker化する
手順1:プロジェクトルートディレクトリの作成
まずはプロジェクトルートを作成します。今回のプロジェクト名はthinklog
です。
作成したらプロジェクトルートに移動しておきます
mkdir thinklog
cd thinklog
手順2:railsをインストールするためのファイル作成
railsをinstallするためにGemfile, Gemfile.lockを作成します
touch Gemfile
touch Gemfile.lock
Gemfileは以下の内容を書きます
source 'https://rubygems.org'
gem 'rails', '5.0.0'
手順3:rails(webサーバコンテナ)作成用のDockerfileを作成
railsのコンテナは、docker-compose.ymlからDockerfileを参照しイメージを作成することにします。
touch Dockerfile.development
FROM ruby:2.3.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
# ARG命令でdocker-compose.ymlから渡されたAPP_HOMEという引数を参照できるようにします
ARG APP_HOME
# dockerの環境側へプロジェクトルートを作成
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
# ADD命令でホストにあるファイルをdockerの環境内にコピーします。
ADD Gemfile $APP_HOME/
ADD Gemfile.lock $APP_HOME/
RUN bundle install -j4
ADD . $APP_HOME
手順4:railsアプリケーションを構成するすべてのコンテナの定義と連携をdocker-compese.ymlにかく
ポイントは以下になります
- webコンテナを作成するときにargsとしてカレントディレクトリを渡しており、プロジェクト名に依存しない作り
- dataコンテナを作り、データ永続化用のコンテナをつくり、ホストの依存を断ち切っていること
- Ctrl C でkillすると tmp/pids/server.pid が削除されず、サーバを再起動できない問題があったので以下commandの箇所を修正しました
version: '2'
services:
web: &app_base
build:
context: .
dockerfile: "Dockerfile.development"
args:
- APP_HOME=${PWD}
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
environment:
- "DATABASE_HOST=db"
- "DATABASE_PORT=5432"
- "DATABASE_USER=postgres"
- "DATABASE_PASSWORD=mysecretpassword1234"
volumes:
- .:${PWD}
ports:
- "3000:3000"
links:
- db
tty: true
stdin_open: true
spring:
<<: *app_base
command: "bundle exec spring server"
ports: []
tty: false
stdin_open: false
db:
image: "postgres:9.5"
environment:
- "POSTGRES_USER=postgres"
- "POSTGRES_PASSWORD=mysecretpassword1234"
volumes_from:
- data
data:
image: "busybox"
volumes:
- "/var/lib/postgresql/data"
手順5:rails newを実行して、イメージを作成する
以下のコマンドを実行すると、プロジェクトが新規作成され、それをもとにイメージが作成されます。
この段階ではまだコンテナの雛形である「イメージ」の段階です
docker-compose run --rm web rails new . --force --database=postgresql --skip-bundle
手順6:bunldle installし、Gemfile.lockを更新
rails newを実行するとGemfileがRails5のベースのGemfileに差し代わっています。
このタイミングでbundle installを実行し、Gemfile.lockを更新します.
ここではイメージ側のGemfile.lockが書き換わっただけです。
docker-compose run --rm web bundle install
手順7: 再buildし、Gemfileの更新結果をイメージに反映
これをして初めて、イメージ側にgemが反映されます。
ホスト側とイメージ側で2回bunlde installが走るのがいけてないです。
(しかもフルで走る)
docker-compose build
手順8: データベース設定
docker-compose.ymlで環境変数が渡されているのでそれを読み取るようにします。
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch('DATABASE_USER') { 'root' } %>
password: <%= ENV.fetch('DATABASE_PASSWORD') { 'password' } %>
host: <%= ENV.fetch('DATABASE_HOST') { 'localhost' } %>
port: <%= ENV.fetch('DATABASE_PORT') { 5432 } %>
development:
<<: *default
database: thinklog_development
test:
<<: *default
database: thinklog_test
production:
<<: *default
database: thinklog_production
手順9: データベース作成
docker-compose run --rm web rails db:create
手順10: 起動
docker-compose up
確認
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e87c36fb1fa8 postgres:9.5 "/docker-entrypoint.s" 30 seconds ago Up 12 seconds 5432/tcp thinklog_db_1
0e7b50b979b8 thinklog_web "bundle exec rails s " 3 minutes ago Up 11 seconds 0.0.0.0:3000->3000/tcp thinklog_web_1
2ab3e48b66d2 thinklog_spring "bundle exec spring s" 3 minutes ago Up 11 seconds thinklog_spring_1
コンテナが起動しました。しかし、データボリュームコンテナは常駐していない模様...(必要な時しか起動しないのか)
ちなみに
docker-compose run --rm web rails s
まとめ
- ホストに依存しない環境は構築できました。しかし、docker-composeコマンドをたたかないといけなかったり bundle installを何回もしないといけないなど、デメリットもあります。
- あと気になったのが、データボリュームコンテナは、アクセスされたタイミングで起動と終了していて、これはいいのかどうか.....
- しかしながら一回作った環境をファイルだけで使いまわせる(ほかのメンバとシェアできる)のは大きな魅力です!今後はワーカージョブを起動したりする設定を追加していきたいと思います!!!!!