Rails 5.2 + PostgreSQLアプリをDockerで起動してみる
はじめに
かなり久しぶりのブログ記事。最近はDockerなどコンテナを触り始めており、いろいろ検証している。
今回はRails 5.2(6.0もすでに出ているが、、手順はさほど変わりないはず)とPostgres DBをつないだアプリをRailsもDBも両方ともDockerコンテナ上で起動させてみる。
なお環境はWindows 10上のDocker for Windowsを入れて、WSL(Ubuntu)からコマンドラインで操作している。
そのあたりもVSCodeのRemote WSL機能でコードもターミナルもかなり快適に使えるようになったきた(が、このあたりは本題ではないので割愛する)。
またRubyやRails環境も構築済みとする。
環境情報は以下。
$ docker -v Docker version 19.03.4, build 9013bf5 $ docker-compose -v docker-compose version 1.24.1, build 4667896b $ ruby -v ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux] $ rails -v Rails 5.2.3
Railsのサンプルアプリ作成
まずはRailsのサンプルアプリを作成する。今回はコンテナ上で動くRailsアプリがコンテナ上で動くPostgresqlに接続し、DBアプリとして正常に動作確認ができればよいので、
簡単にscaffoldで構築することにする。
何はともあれrails new
する。--database=postgresql
オプションも明示する。
$ rails new rails-sample-app --database=postgresql
DB処理を持つ画面機能をscaffoldで実装する。
$ rails generate scaffold User name:string email:string
さて、ここまででアプリはできているが、コンテナで扱う上でDB情報などは環境変数から渡せるようにしておくと便利。
なのでdatabase.ymlを修正し環境変数で各種パラメータ値を取得するように修正する。
default: &default adapter: postgresql encoding: unicode pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> host: <%= ENV['DB_HOST'] %> port: <%= ENV['DB_PORT'] %> database: <%= ENV['DB_NAME'] %> username: <%= ENV['DB_USER'] %> password: <%= ENV['DB_PASSWORD'] %> development: <<: *default test: <<: *default database: rails-sample-app_test production: <<: *default database: rails-sample-app_production username: rails-sample-app password: <%= ENV['RAILS-SAMPLE-APP_DATABASE_PASSWORD'] %>
ここまででRailsアプリとしては完成とする(簡単!)
Dockerコンテナイメージ作成
続いてアプリ部分ができたのでインフラとしてのコンテナ部分を作る。
Dockerfileとdocker-compose.ymlの二つのファイルを作成する必要があるが、いずれもRailsアプリプロジェクトのトップに直接配置する。
まずDockerfileを作成する。
RailsサーバやPostgresSQL(pgのgem)を導入するのに必要なパッケージのインストールをappフォルダをコンテナ内に配置してbundle install
するのみ。
これだけだとDBマイグレーションとかはできないのが、そのあたりはコンテナでRailsとDBの両方が起動した後に別途実行する必要がある。
Dockerfile
FROM ruby:2.6.5 RUN apt-get update -qq && apt-get install -y \ build-essential \ libpq-dev \ nodejs \ yarn \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* RUN mkdir /app WORKDIR /app COPY . /app RUN bundle install CMD ["rails", "server", "-b", "0.0.0.0"]
Dockerfileができたので、さっそくビルドしてみる。tag名をrails-app:0.1
と明示的に指定しておく。
--no-cache
はコンテナイメージのキャッシュによりファイルを変更しても反映されない場合などに付与するとよい。
$ docker build --no-cache -t rails-app:0.1 . Sending build context to Docker daemon24.37MB Step 1/7 : FROM ruby:2.6.5 ---> d98e4013532b (・・・略) Removing intermediate container 2e7649a0d45a ---> 6bc8d871d10d Step 7/7 : CMD ["rails", "server", "-b", "0.0.0.0"] ---> Running in 7c3be452473b Removing intermediate container 7c3be452473b ---> ba7f6c2f08eb Successfully built ba7f6c2f08eb Successfully tagged rails-app:0.1 SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
途中でaptやgemのインストールなどが正常に行われていることがログから確認できる。エラーなく終了すればコンテナビルドはOK。
docker-compose.yml作成
さて、先ほど作ったRailsアプリのコンテナイメージとPostgresSQLのコンテナイメージを両方起動するdocker-compose.ymlを作成する。
RailsのDB接続情報もPostgresの各種DB情報も環境変数で渡せるようになっているので、以下のようにそれぞれに同じ値を設定する。
version: '3' services: db: image: postgres:11.5 environment: - POSTGRES_PORT=5432 - POSTGRES_DB=sample - POSTGRES_USER=sample-user - POSTGRES_PASSWORD=password ports: - 5432:5432 web: image: rails-app:0.1 ports: - 3000:3000 depends_on: - db links: - db environment: - DB_HOST=db - DB_PORT=5432 - DB_NAME=sample - DB_USER=sample-user - DB_PASSWORD=password
コンテナ起動
コンテナの定義ができたので、さっそく起動してみる。
$ docker-compose up -d Creating network "rails-sample-app_default" with the default driver Creating rails-sample-app_db_1 ... done Creating rails-sample-app_web_1 ... done
正常に起動できたよう。コンテナの状態も確認しておく。
$ docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------- rails-sample-app_db_1 docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp rails-sample-app_web_1 rails server -b 0.0.0.0 Up 0.0.0.0:3000->3000/tcp
ちゃんとDBとWebの二つのコンテナが起動していることが分かる。
ここで後回しにしていたDBマイグレーションを忘れずに実行しておく。
$ docker-compose run web rails db:migrate Starting rails-sample-app_db_1 ... done == 20191110115438 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0123s == 20191110115438 CreateUsers: migrated (0.0127s) =============================
テーブルも問題なく作成できたよう。これでアプリとDBの両方の作成が完了した。
動作確認
最後に動作確認をしておく。
まずRailsのトップページにアクセスする。
http://localhost:3000
Railsサーバのトップ画面が見れることが確認できた。
続いて、DB機能をテストしてみる。以下のURLにアクセスしScaffoldで実装されたCRUD機能を動かしてみる。
http://localhost:3000/users
New userでのデータ登録や一覧表示等のDB操作が正常にできることが確認できた!
コンテナ上でRailsアプリが正しくコンテナ上のPostgreSQLと連携し、機能していることが確認できた。
まとめ
RailsアプリをWebサーバ・DBサーバともにDockerによりコンテナ化し正常に動作するところまで確認できた。
これでローカル開発するときもRailsやPostgresのインストールをせずともアプリ開発ができるし、コンテナをAWSのECSなどにデプロイすれば本番環境としても利用できる。
コンテナ化によりアプリ開発や本番運用がますます簡単になってきているので、いろいろ検証して利用を進めていきたい。
(もちろんこれはごく簡単な例なので、本格運用する場合はもっといろいろと検証ポイントはあるが)
以上!