カタカタブログ

SIerで働くITエンジニアがカタカタした記録を残す技術ブログ。Java, Oracle Database, Linuxが中心です。たまに数学やデータ分析なども。

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
f:id:osn_th:20191110214035p:plain
Railsサーバのトップ画面が見れることが確認できた。

続いて、DB機能をテストしてみる。以下のURLにアクセスしScaffoldで実装されたCRUD機能を動かしてみる。
http://localhost:3000/users
f:id:osn_th:20191110214031p:plain
New userでのデータ登録や一覧表示等のDB操作が正常にできることが確認できた!
コンテナ上でRailsアプリが正しくコンテナ上のPostgreSQLと連携し、機能していることが確認できた。

まとめ

RailsアプリをWebサーバ・DBサーバともにDockerによりコンテナ化し正常に動作するところまで確認できた。
これでローカル開発するときもRailsやPostgresのインストールをせずともアプリ開発ができるし、コンテナをAWSのECSなどにデプロイすれば本番環境としても利用できる。
コンテナ化によりアプリ開発や本番運用がますます簡単になってきているので、いろいろ検証して利用を進めていきたい。
(もちろんこれはごく簡単な例なので、本格運用する場合はもっといろいろと検証ポイントはあるが)

以上!