DockerComposeを使用した開発のためのRubyonRailsアプリケーションのコンテナー化

提供:Dev Guides
移動先:案内検索

序章

アプリケーションを積極的に開発している場合は、 Docker を使用すると、ワークフローとアプリケーションを本番環境にデプロイするプロセスを簡素化できます。 開発中のコンテナを使用すると、次の利点があります。

  • 環境は一貫しています。つまり、システムの競合を心配することなく、プロジェクトに必要な言語と依存関係を選択できます。
  • 環境が分離されているため、問題のトラブルシューティングや新しいチームメンバーの参加が容易になります。
  • 環境は移植可能であり、コードをパッケージ化して他の人と共有することができます。

このチュートリアルでは、Dockerを使用して Ruby onRailsアプリケーションの開発環境をセットアップする方法を説明します。 Docker Compose を使用して、アプリケーション自体、 PostgreSQL データベース、 Redis 、およびSidekiqサービス用に複数のコンテナーを作成します。 セットアップは次のことを行います。

  • ホスト上のアプリケーションコードをコンテナ内のコードと同期して、開発中の変更を容易にします。
  • コンテナの再起動間でアプリケーションデータを保持します。
  • 期待どおりにジョブを処理するようにSidekiqワーカーを構成します。

このチュートリアルの最後に、Dockerコンテナで実行されている動作するサメ情報アプリケーションがあります。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • Ubuntu 18.04を実行しているローカル開発マシンまたはサーバー、およびsudo特権とアクティブなファイアウォールを持つ非rootユーザー。 これらの設定方法のガイダンスについては、この初期サーバー設定ガイドを参照してください。
  • Ubuntu18.04にDockerをインストールして使用する方法の手順1と2に従ってローカルマシンまたはサーバーにDockerをインストールします。
  • Ubuntu 18.04にDockerComposeをインストールする方法のステップ1に従って、ローカルマシンまたはサーバーにDockerComposeをインストールします。

ステップ1—プロジェクトのクローンを作成して依存関係を追加する

最初のステップは、 DigitalOceanCommunityGitHubアカウントからrails-sidekiqリポジトリのクローンを作成することです。 このリポジトリには、既存のRails5プロジェクトにSidekiqを追加する方法を説明するRubyonRailsアプリケーションにSidekiqとRedisを追加する方法で説明されているセットアップのコードが含まれています。

リポジトリをrails-dockerというディレクトリに複製します。

git clone https://github.com/do-community/rails-sidekiq.git rails-docker

rails-dockerディレクトリに移動します。

cd rails-docker

このチュートリアルでは、PostgreSQLをデータベースとして使用します。 SQLite 3の代わりにPostgreSQLを使用するには、Gemfileにリストされているプロジェクトの依存関係に pggemを追加する必要があります。 そのファイルを開いて、nanoまたはお気に入りのエディターを使用して編集します。

nano Gemfile

メインプロジェクトの依存関係(開発の依存関係の上)の任意の場所にgemを追加します。

〜/ rails-docker / Gemfile

. . . 
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false
gem 'sidekiq', '~>6.0.0'
gem 'pg', '~>1.1.3'

group :development, :test do
. . .

sqlite gem はもう使用しないため、コメントアウトすることもできます。

〜/ rails-docker / Gemfile

. . . 
# Use sqlite3 as the database for Active Record
# gem 'sqlite3'
. . .

最後に、developmentの下にあるspring-watcher-listengemをコメントアウトします。

〜/ rails-docker / Gemfile

. . . 
gem 'spring'
# gem 'spring-watcher-listen', '~> 2.0.0'
. . .

このgemを無効にしないと、Railsコンソールにアクセスするときに永続的なエラーメッセージが表示されます。 これらのエラーメッセージは、このgemがファイルシステムの変更をポーリングするのではなく、Railsがlistenを使用して開発の変更を監視しているという事実に由来しています。 このgemは、node_modulesディレクトリを含むプロジェクトのルートを監視するため、監視されているディレクトリに関するエラーメッセージをスローし、コンソールを乱雑にします。 ただし、CPUリソースの節約が心配な場合は、このgemを無効にしてもうまくいかない可能性があります。 この場合、RailsアプリケーションをRails6にアップグレードすることをお勧めします。

編集が終了したら、ファイルを保存して閉じます。

プロジェクトリポジトリを配置し、pg gemをGemfileに追加し、spring-watcher-listen gemをコメントアウトすると、PostgreSQLで動作するようにアプリケーションを構成する準備が整います。

ステップ2—PostgreSQLおよびRedisで動作するようにアプリケーションを構成する

開発中のPostgreSQLとRedisを使用するには、次のことを行います。

  • PostgreSQLをデフォルトのアダプターとして使用するようにアプリケーションを構成します。
  • .envファイルを、データベースのユーザー名とパスワード、およびRedisホストを使用してプロジェクトに追加します。
  • init.sqlスクリプトを作成して、データベースのsammyユーザーを作成します。
  • Sidekiq用のinitializerを追加して、コンテナ化されたredisサービスで動作できるようにします。
  • .envファイルおよびその他の関連ファイルをプロジェクトのgitignoreおよびdockerignoreファイルに追加します。
  • データベースシードを作成して、アプリケーションの起動時に使用できるレコードがアプリケーションに含まれるようにします。

まず、config/database.ymlにあるデータベース構成ファイルを開きます。

nano config/database.yml

現在、このファイルには次のdefault設定が含まれています。これらの設定は、他の設定がない場合に適用されます。

〜/ rails-docker / config / database.yml

default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

postgresqlアダプターを使用するという事実を反映するために、これらを変更する必要があります。これは、Docker Composeを使用してPostgreSQLサービスを作成し、アプリケーションデータを永続化するためです。

SQLiteをアダプターとして設定するコードを削除し、次の設定に置き換えます。これにより、アダプターと接続に必要なその他の変数が適切に設定されます。

〜/ rails-docker / config / database.yml

default: &default
  adapter: postgresql
  encoding: unicode
  database: <%= ENV['DATABASE_NAME'] %>
  username: <%= ENV['DATABASE_USER'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  port: <%= ENV['DATABASE_PORT'] || '5432' %>
  host: <%= ENV['DATABASE_HOST'] %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
. . .

次に、development環境の設定を変更します。これは、このセットアップで使用している環境だからです。

セクションが次のようになるように、既存のSQLiteデータベース構成を削除します。

〜/ rails-docker / config / database.yml

. . . 
development:
  <<: *default
. . .

最後に、productionおよびtest環境のdatabase設定も削除します。

〜/ rails-docker / config / database.yml

. . . 
test:
  <<: *default
  
production:
  <<: *default
. . . 

デフォルトのデータベース設定に対するこれらの変更により、バージョン管理にコミットされない.envファイルで定義された環境変数を使用してデータベース情報を動的に設定できるようになります。

編集が終了したら、ファイルを保存して閉じます。

Railsプロジェクトを最初から作成する場合は、 How To Use PostgreSQL with Your Ruby onのステップ3で説明されているように、rails newコマンドを使用してアダプターを設定できます。 Ubuntu18.04上のRailsアプリケーション。 これにより、アダプターがconfig/database.ymlに設定され、pggemがプロジェクトに自動的に追加されます。

環境変数を参照したので、好みの設定でそれらのファイルを作成できます。 この方法で構成設定を抽出することは、アプリケーション開発への 12ファクターアプローチの一部であり、分散環境でのアプリケーションの復元力のベストプラクティスを定義します。 現在、本番環境とテスト環境を将来セットアップする場合、データベース設定を構成するには、追加の.envファイルを作成し、DockerComposeファイルで適切なファイルを参照する必要があります。

.envファイルを開きます。

nano .env

次の値をファイルに追加します。

〜/ rails-docker / .env

DATABASE_NAME=rails_development
DATABASE_USER=sammy
DATABASE_PASSWORD=shark
DATABASE_HOST=database
REDIS_HOST=redis

データベース名、ユーザー、パスワードの設定に加えて、DATABASE_HOSTの値も設定しました。 値databaseは、DockerComposeを使用して作成するdatabasePostgreSQLサービスを指します。 また、REDIS_HOSTを設定して、redisサービスを指定します。

編集が終了したら、ファイルを保存して閉じます。

sammyデータベースユーザーを作成するには、init.sqlスクリプトを記述して、起動時にデータベースコンテナーにマウントできます。

スクリプトファイルを開きます。

nano init.sql

次のコードを追加して、管理者権限を持つsammyユーザーを作成します。

〜/ rails-docker / init.sql

CREATE USER sammy;
ALTER USER sammy WITH SUPERUSER;

このスクリプトは、データベース上に適切なユーザーを作成し、このユーザーに管理者権限を付与します。

スクリプトに適切な権限を設定します。

chmod +x init.sql

次に、コンテナ化されたredisサービスと連携するようにSidekiqを構成します。 イニシャライザーをconfig/initializersディレクトリーに追加できます。ここで、Railsは、フレームワークとプラグインがロードされると構成設定を検索し、Redisホストの値を設定します。

sidekiq.rbファイルを開いて、次の設定を指定します。

nano config/initializers/sidekiq.rb

次のコードをファイルに追加して、REDIS_HOSTおよびREDIS_PORTの値を指定します。

〜/ rails-docker / config / initializers / sidekiq.rb

Sidekiq.configure_server do |config|
  config.redis = {
    host: ENV['REDIS_HOST'],
    port: ENV['REDIS_PORT'] || '6379'
  }
end

Sidekiq.configure_client do |config|
  config.redis = {
    host: ENV['REDIS_HOST'],
    port: ENV['REDIS_PORT'] || '6379'
  }
end

データベース構成設定と同様に、これらの設定により、ホストとポートのパラメーターを動的に設定できるため、アプリケーションコード自体を変更することなく、実行時に適切な値に置き換えることができます。 REDIS_HOSTに加えて、他に設定されていない場合に備えて、REDIS_PORTのデフォルト値が設定されています。

編集が終了したら、ファイルを保存して閉じます。

次に、アプリケーションの機密データがバージョン管理にコピーされないようにするために、プロジェクトの.gitignoreファイルに.envを追加して、プロジェクトで無視するファイルをGitに指示します。 編集用にファイルを開きます。

nano .gitignore

ファイルの最後に、.envのエントリを追加します。

〜/ rails-docker / .gitignore

yarn-debug.log*
.yarn-integrity
.env

編集が終了したら、ファイルを保存して閉じます。

次に、.dockerignoreファイルを作成して、コンテナーにコピーしないものを設定します。 編集用にファイルを開きます。

.dockerignore

次のコードをファイルに追加します。これにより、Dockerは、コンテナーにコピーする必要のないものの一部を無視するようになります。

〜/ rails-docker / .dockerignore

.DS_Store
.bin
.git
.gitignore
.bundleignore
.bundle
.byebug_history
.rspec
tmp
log
test
config/deploy
public/packs
public/packs-test
node_modules
yarn-error.log
coverage/

このファイルの最後にも.envを追加します。

〜/ rails-docker / .dockerignore

. . .
yarn-error.log
coverage/
.env

編集が終了したら、ファイルを保存して閉じます。

最後のステップとして、アプリケーションを起動したときにいくつかのレコードが含まれるように、いくつかのシードデータを作成します。

dbディレクトリにあるシードデータのファイルを開きます。

nano db/seeds.rb

次のコードをファイルに追加して、4つのデモサメと1つのサンプル投稿を作成します。

〜/ rails-docker / db / seeds.rb

# Adding demo sharks
sharks = Shark.create([{ name: 'Great White', facts: 'Scary' }, { name: 'Megalodon', facts: 'Ancient' }, { name: 'Hammerhead', facts: 'Hammer-like' }, { name: 'Speartooth', facts: 'Endangered' }])
Post.create(body: 'These sharks are misunderstood', shark: sharks.first)

このシードデータは、最初のサメに関連付けられた4つのサメと1つの投稿を作成します。

編集が終了したら、ファイルを保存して閉じます。

アプリケーションがPostgreSQLで動作するように構成され、環境変数が作成されたら、アプリケーションDockerfileを作成する準備が整います。

ステップ3—Dockerfileおよびエントリポイントスクリプトの記述

Dockerfileは、作成時にアプリケーションコンテナに含まれるものを指定します。 Dockerfileを使用すると、コンテナー環境を定義し、依存関係またはランタイムバージョンとの不一致を回避できます。

最適化されたコンテナの構築に関するこれらのガイドラインに従い、アルパインベースを使用し、画像レイヤーを一般的に最小化することで、画像を可能な限り効率的にします。

現在のディレクトリでDockerfileを開きます。

nano Dockerfile

Dockerイメージは、相互に構築される一連のレイヤードイメージを使用して作成されます。 最初のステップは、アプリケーションのベースイメージを追加することです。これにより、アプリケーションビルドの開始点が形成されます。

次のコードをファイルに追加して、 Ruby alpineimageをベースとして追加します。

〜/ rails-docker / Dockerfile

FROM ruby:2.5.1-alpine

alpineイメージは、Alpine Linuxプロジェクトから派生したものであり、イメージサイズを小さく抑えるのに役立ちます。 alpineイメージがプロジェクトに適しているかどうかの詳細については、 DockerHubRubyイメージページのImageVariantsセクションの詳細な説明を参照してください[ X210X]。

開発でalpineを使用する際に考慮すべきいくつかの要因:

  • 画像サイズを小さくすると、特にボリュームを最小限に抑える場合は、ページとリソースの読み込み時間が短縮されます。 これにより、開発におけるユーザーエクスペリエンスを迅速に保ち、コンテナ化されていない環境でローカルで作業している場合のエクスペリエンスに近づけることができます。
  • 開発イメージと本番イメージの間に同等性があると、展開の成功が容易になります。 チームはスピードのメリットのために本番環境でアルパインイメージを使用することを選択することが多いため、アルパインベースで開発すると、本番環境に移行する際の問題を相殺するのに役立ちます。

次に、環境変数を設定して、Bundlerバージョンを指定します。

〜/ rails-docker / Dockerfile

. . .
ENV BUNDLER_VERSION=2.0.2

これは、環境で使用可能なデフォルトのbundlerバージョンと、Bundler2.0.2を必要とするアプリケーションコードとの間のバージョンの競合を回避するために実行する手順の1つです。

次に、アプリケーションでの作業に必要なパッケージをDockerfileに追加します。

〜/ rails-docker / Dockerfile

. . . 
RUN apk add --update --no-cache \
      binutils-gold \
      build-base \
      curl \
      file \
      g++ \
      gcc \
      git \
      less \
      libstdc++ \
      libffi-dev \
      libc-dev \ 
      linux-headers \
      libxml2-dev \
      libxslt-dev \
      libgcrypt-dev \
      make \
      netcat-openbsd \
      nodejs \
      openssl \
      pkgconfig \
      postgresql-dev \
      python \
      tzdata \
      yarn 

これらのパッケージには、nodejsおよびyarnなどが含まれます。 アプリケーションはwebpackでアセットを提供するため、アプリケーションが期待どおりに機能するには、Node.jsYarnを含める必要があります。

alpineイメージは非常に最小限であることに注意してください。ここにリストされているパッケージは、独自のアプリケーションをコンテナー化するときに開発で必要になる可能性のあるものを網羅しているわけではありません。

次に、適切なbundlerバージョンをインストールします。

〜/ rails-docker / Dockerfile

. . . 
RUN gem install bundler -v 2.0.2

この手順により、コンテナー化された環境と、このプロジェクトのGemfile.lockファイルの仕様との間の同等性が保証されます。

次に、コンテナにアプリケーションの作業ディレクトリを設定します。

〜/ rails-docker / Dockerfile

. . .
WORKDIR /app

GemfileGemfile.lockをコピーします。

〜/ rails-docker / Dockerfile

. . .
COPY Gemfile Gemfile.lock ./

これらのファイルを独立した手順としてコピーし、その後にbundle installを実行すると、アプリケーションコードに変更を加えるたびにプロジェクトgemを再構築する必要がなくなります。 これは、Composeファイルに含めるgemボリュームと連携して機能します。このボリュームは、サービスが再作成されてもプロジェクトgemが同じである場合に、アプリケーションコンテナーにgemをマウントします。

次に、nokogirigemビルドの構成オプションを設定します。

〜/ rails-docker / Dockerfile

. . . 
RUN bundle config build.nokogiri --use-system-libraries
. . .

このステップでは、上記のRUN apk add…ステップでアプリケーションコンテナに追加したlibxml2およびlibxsltライブラリバージョンを使用してnokigiriをビルドします。

次に、プロジェクトgemをインストールします。

〜/ rails-docker / Dockerfile

. . . 
RUN bundle check || bundle install

この手順では、gemをインストールする前に、gemがまだインストールされていないことを確認します。

次に、JavaScriptパッケージと依存関係を使用してgemで使用したのと同じ手順を繰り返します。 最初にパッケージメタデータをコピーし、次に依存関係をインストールし、最後にアプリケーションコードをコンテナイメージにコピーします。

DockerfileのJavascriptセクションを開始するには、package.jsonyarn.lockをホスト上の現在のプロジェクトディレクトリからコンテナにコピーします。

〜/ rails-docker / Dockerfile

. . . 
COPY package.json yarn.lock ./

次に、yarn installを使用して必要なパッケージをインストールします。

〜/ rails-docker / Dockerfile

. . . 
RUN yarn install --check-files

この命令には、yarnコマンドを伴う--check-filesフラグが含まれています。これは、以前にインストールされたファイルが削除されていないことを確認する機能です。 gemの場合と同様に、Composeファイルを作成するときに、ボリュームを使用してnode_modulesディレクトリ内のパッケージの永続性を管理します。

最後に、残りのアプリケーションコードをコピーして、エントリポイントスクリプトを使用してアプリケーションを起動します。

〜/ rails-docker / Dockerfile

. . . 
COPY . ./ 

ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]

エントリポイントスクリプトを使用すると、コンテナを実行可能ファイルとして実行できます。

最終的なDockerfileは次のようになります。

〜/ rails-docker / Dockerfile

FROM ruby:2.5.1-alpine

ENV BUNDLER_VERSION=2.0.2

RUN apk add --update --no-cache \
      binutils-gold \
      build-base \
      curl \
      file \
      g++ \
      gcc \
      git \
      less \
      libstdc++ \
      libffi-dev \
      libc-dev \ 
      linux-headers \
      libxml2-dev \
      libxslt-dev \
      libgcrypt-dev \
      make \
      netcat-openbsd \
      nodejs \
      openssl \
      pkgconfig \
      postgresql-dev \
      python \
      tzdata \
      yarn 

RUN gem install bundler -v 2.0.2

WORKDIR /app

COPY Gemfile Gemfile.lock ./

RUN bundle config build.nokogiri --use-system-libraries

RUN bundle check || bundle install 

COPY package.json yarn.lock ./

RUN yarn install --check-files

COPY . ./ 

ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]

編集が終了したら、ファイルを保存して閉じます。

次に、エントリポイントスクリプト用にentrypointsというディレクトリを作成します。

mkdir entrypoints

このディレクトリには、メインのエントリポイントスクリプトとSidekiqサービスのスクリプトが含まれます。

アプリケーションエントリポイントスクリプトのファイルを開きます。

nano entrypoints/docker-entrypoint.sh

次のコードをファイルに追加します。

rails-docker / entrypoints / docker-entrypoint.sh

#!/bin/sh

set -e

if [ -f tmp/pids/server.pid ]; then
  rm tmp/pids/server.pid
fi

bundle exec rails s -b 0.0.0.0

最初の重要な行はset -eです。これは、スクリプトを実行する/bin/shシェルに、スクリプトの後半で問題が発生した場合に高速で失敗するように指示します。 次に、スクリプトはtmp/pids/server.pidが存在しないことを確認して、アプリケーションの起動時にサーバーの競合が発生しないようにします。 最後に、スクリプトはbundle exec rails sコマンドを使用してRailsサーバーを起動します。 このコマンドで-bオプションを使用して、サーバーをデフォルトのlocalhostではなく、すべてのIPアドレスにバインドします。 この呼び出しにより、Railsサーバーは着信要求をデフォルトのlocalhostではなくコンテナIPにルーティングします。

編集が終了したら、ファイルを保存して閉じます。

スクリプトを実行可能にします。

chmod +x entrypoints/docker-entrypoint.sh

次に、Sidekiqジョブを処理するsidekiqサービスを開始するスクリプトを作成します。 このアプリケーションがSidekiqを使用する方法の詳細については、SidekiqとRedisをRubyonRailsアプリケーションに追加する方法を参照してください。

Sidekiqエントリポイントスクリプトのファイルを開きます。

nano entrypoints/sidekiq-entrypoint.sh

Sidekiqを起動するには、ファイルに次のコードを追加します。

〜/ rails-docker / entrypoints / sidekiq-entrypoint.sh

#!/bin/sh

set -e

if [ -f tmp/pids/server.pid ]; then
  rm tmp/pids/server.pid
fi
 
bundle exec sidekiq

このスクリプトは、アプリケーションバンドルのコンテキストでSidekiqを起動します。

編集が終了したら、ファイルを保存して閉じます。 実行可能にする:

chmod +x entrypoints/sidekiq-entrypoint.sh

エントリポイントスクリプトとDockerfileを配置すると、Composeファイルでサービスを定義する準備が整います。

ステップ4—DockerComposeを使用したサービスの定義

Docker Composeを使用すると、セットアップに必要な複数のコンテナーを実行できるようになります。 メインのdocker-compose.ymlファイルでComposeservicesを定義します。 Composeのサービスは実行中のコンテナーであり、サービス定義(docker-compose.ymlファイルに含める)には、各コンテナーイメージの実行方法に関する情報が含まれています。 作成ツールを使用すると、複数のサービスを定義して、マルチコンテナーアプリケーションを構築できます。

アプリケーションのセットアップには、次のサービスが含まれます。

  • アプリケーション自体
  • PostgreSQLデータベース
  • Redis
  • Sidekiq

また、セットアップの一部としてバインドマウントを含めるため、開発中に行ったコードの変更は、このコードにアクセスする必要のあるコンテナーとすぐに同期されます。

テストはこのチュートリアルとシリーズの範囲外であるため、ではなく testサービスを定義していることに注意してください。ただし、前例に従うことでそうすることができます。ここではsidekiqサービスに使用しています。

docker-compose.ymlファイルを開きます。

nano docker-compose.yml

まず、アプリケーションサービス定義を追加します。

〜/ rails-docker / docker-compose.yml

version: '3.4'

services:
  app: 
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - database
      - redis
    ports: 
      - "3000:3000"
    volumes:
      - .:/app
      - gem_cache:/usr/local/bundle/gems
      - node_modules:/app/node_modules
    env_file: .env
    environment:
      RAILS_ENV: development

appサービス定義には、次のオプションが含まれています。

  • build:これは、contextdockerfileなど、Composeがアプリケーションイメージをビルドするときに適用される構成オプションを定義します。 Docker Hub などのレジストリの既存のイメージを使用する場合は、代わりに image命令を使用して、ユーザー名、リポジトリ、イメージタグに関する情報を使用できます。
  • context:これは、イメージビルドのビルドコンテキスト(この場合は現在のプロジェクトディレクトリ)を定義します。
  • dockerfile:これは、Composeがアプリケーションイメージのビルドに使用するファイルとして、現在のプロジェクトディレクトリのDockerfileを指定します。
  • depends_on:これにより、databaseおよびredisコンテナーが最初にセットアップされ、appより前に稼働します。
  • ports:これは、ホストのポート3000をコンテナーのポート3000にマップします。
  • volumes :ここには2種類のマウントが含まれています: 1つ目は、ホスト上のアプリケーションコードをコンテナの/appディレクトリにマウントするバインドマウントです。 これにより、ホストコードに加えた変更がすぐにコンテナに入力されるため、迅速な開発が容易になります。 2つ目は、名前付きボリュームgem_cacheです。 バンドルインストール命令がコンテナで実行されると、プロジェクトgemがインストールされます。 このボリュームを追加すると、コンテナを再作成すると、gemが新しいコンテナにマウントされます。 このマウントは、プロジェクトに変更がないことを前提としているため、開発中にプロジェクトgemに変更を加える場合は、アプリケーションサービスを再作成する前に、このボリュームを削除することを忘れないでください。 3番目のボリュームは、node_modulesディレクトリーの名前付きボリュームです。 node_modulesをホストにマウントして、開発中にパッケージの不一致や権限の競合を引き起こす可能性があるのではなく、このボリュームは、このディレクトリ内のパッケージが永続化され、プロジェクトの現在の状態を反映することを保証します。 この場合も、プロジェクトのノードの依存関係を変更する場合は、このボリュームを削除して再作成する必要があります。
  • env_file:これは、ビルドコンテキストにある.envというファイルから環境変数を追加することをComposeに通知します。
  • environment:このオプションを使用すると、機密性の低い環境変数を設定して、Rails環境に関する情報をコンテナーに渡すことができます。

次に、appサービス定義の下に、次のコードを追加してdatabaseサービスを定義します。

〜/ rails-docker / docker-compose.yml

. . .
  database:
    image: postgres:12.1
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

appサービスとは異なり、databaseサービスは、 DockerHubからpostgresイメージを直接プルします。 バージョンをlatestに設定したり、指定しない(デフォルトではlatest)のではなく、ここでもバージョンを固定していることに注意してください。 このようにして、このセットアップがここで指定されたバージョンで機能することを確認し、イメージへのコード変更を壊すことによる予期しない驚きを回避できます。

ここにはdb_dataボリュームも含まれています。これにより、コンテナーの起動間でアプリケーションデータが保持されます。 さらに、sammyデータベースユーザーを作成するために、init.sql起動スクリプトをコンテナーの適切なディレクトリdocker-entrypoint-initdb.d/にマウントしました。 イメージエントリポイントは、デフォルトのpostgresユーザーとデータベースを作成した後、docker-entrypoint-initdb.d/ディレクトリにあるスクリプトを実行します。このスクリプトは、必要な初期化タスクに使用できます。 詳細については、PostgreSQLイメージドキュメント初期化スクリプトセクションを参照してください。

次に、redisサービス定義を追加します。

〜/ rails-docker / docker-compose.yml

. . .
  redis:
    image: redis:5.0.7

databaseサービスと同様に、redisサービスはDockerHubのイメージを使用します。 この場合、Sidekiqジョブキャッシュを永続化することはありません。

最後に、sidekiqサービス定義を追加します。

〜/ rails-docker / docker-compose.yml

. . .
  sidekiq:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - app      
      - database
      - redis
    volumes:
      - .:/app
      - gem_cache:/usr/local/bundle/gems
      - node_modules:/app/node_modules
    env_file: .env
    environment:
      RAILS_ENV: development
    entrypoint: ./entrypoints/sidekiq-entrypoint.sh

sidekiqサービスは、いくつかの点でappサービスに似ています。同じビルドコンテキストとイメージ、環境変数、およびボリュームを使用します。 ただし、appredis、およびdatabaseサービスに依存しているため、最後に開始します。 さらに、Dockerfileで設定されたエントリポイントをオーバーライドするentrypointを使用します。 このentrypoint設定は、entrypoints/sidekiq-entrypoint.shを指します。これには、sidekiqサービスを開始するための適切なコマンドが含まれています。

最後のステップとして、sidekiqサービス定義の下にボリューム定義を追加します。

〜/ rails-docker / docker-compose.yml

. . .
volumes:
  gem_cache:
  db_data:
  node_modules:

トップレベルのボリュームキーは、ボリュームgem_cachedb_data、およびnode_modulesを定義します。 Dockerがボリュームを作成すると、ボリュームのコンテンツは、Dockerによって管理されるホストファイルシステム/var/lib/docker/volumes/の一部に保存されます。 各ボリュームの内容は、/var/lib/docker/volumes/の下のディレクトリに保存され、ボリュームを使用する任意のコンテナにマウントされます。 このように、ユーザーが作成するサメ情報データは、databaseサービスを削除して再作成しても、db_dataボリュームに保持されます。

完成したファイルは次のようになります。

〜/ rails-docker / docker-compose.yml

version: '3.4'

services:
  app: 
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:     
      - database
      - redis
    ports: 
      - "3000:3000"
    volumes:
      - .:/app
      - gem_cache:/usr/local/bundle/gems
      - node_modules:/app/node_modules
    env_file: .env
    environment:
      RAILS_ENV: development

  database:
    image: postgres:12.1
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

  redis:
    image: redis:5.0.7

  sidekiq:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - app      
      - database
      - redis
    volumes:
      - .:/app
      - gem_cache:/usr/local/bundle/gems
      - node_modules:/app/node_modules
    env_file: .env
    environment:
      RAILS_ENV: development
    entrypoint: ./entrypoints/sidekiq-entrypoint.sh

volumes:
  gem_cache:
  db_data:
  node_modules:     

編集が終了したら、ファイルを保存して閉じます。

サービス定義を記述したら、アプリケーションを開始する準備が整います。

ステップ5—アプリケーションのテスト

docker-compose.ymlファイルを配置したら、 docker-compose up コマンドを使用してサービスを作成し、データベースをシードできます。 docker-compose down を使用してコンテナーを停止および削除し、それらを再作成することで、データが保持されることをテストすることもできます。

まず、コンテナイメージをビルドし、docker-compose up-dフラグで実行してサービスを作成します。これにより、コンテナがバックグラウンドで実行されます。

docker-compose up -d

サービスが作成されたという出力が表示されます。

OutputCreating rails-docker_database_1 ... done
Creating rails-docker_redis_1    ... done
Creating rails-docker_app_1      ... done
Creating rails-docker_sidekiq_1  ... done

また、サービスからのログ出力を表示することにより、起動プロセスに関するより詳細な情報を取得できます。

docker-compose logs 

すべてが正しく開始されている場合は、次のように表示されます。

Outputsidekiq_1   | 2019-12-19T15:05:26.365Z pid=6 tid=grk7r6xly INFO: Booting Sidekiq 6.0.3 with redis options {:host=>"redis", :port=>"6379", :id=>"Sidekiq-server-PID-6", :url=>nil}
sidekiq_1   | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: Running in ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-musl]
sidekiq_1   | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: See LICENSE and the LGPL-3.0 for licensing details.
sidekiq_1   | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
app_1       | => Booting Puma
app_1       | => Rails 5.2.3 application starting in development 
app_1       | => Run `rails server -h` for more startup options
app_1       | Puma starting in single mode...
app_1       | * Version 3.12.1 (ruby 2.5.1-p57), codename: Llamas in Pajamas
app_1       | * Min threads: 5, max threads: 5
app_1       | * Environment: development
app_1       | * Listening on tcp://0.0.0.0:3000
app_1       | Use Ctrl-C to stop
. . .
database_1  | PostgreSQL init process complete; ready for start up.
database_1  | 
database_1  | 2019-12-19 15:05:20.160 UTC [1] LOG:  starting PostgreSQL 12.1 (Debian 12.1-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
database_1  | 2019-12-19 15:05:20.160 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
database_1  | 2019-12-19 15:05:20.160 UTC [1] LOG:  listening on IPv6 address "::", port 5432
database_1  | 2019-12-19 15:05:20.163 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
database_1  | 2019-12-19 15:05:20.182 UTC [63] LOG:  database system was shut down at 2019-12-19 15:05:20 UTC
database_1  | 2019-12-19 15:05:20.187 UTC [1] LOG:  database system is ready to accept connections
. . . 
redis_1     | 1:M 19 Dec 2019 15:05:18.822 * Ready to accept connections

docker-compose ps を使用して、コンテナのステータスを確認することもできます。

docker-compose ps

コンテナが実行されていることを示す出力が表示されます。

Output         Name                        Command               State           Ports         
-----------------------------------------------------------------------------------------
rails-docker_app_1        ./entrypoints/docker-resta ...   Up      0.0.0.0:3000->3000/tcp
rails-docker_database_1   docker-entrypoint.sh postgres    Up      5432/tcp              
rails-docker_redis_1      docker-entrypoint.sh redis ...   Up      6379/tcp              
rails-docker_sidekiq_1    ./entrypoints/sidekiq-entr ...   Up                  

次に、データベースを作成してシードし、次のdocker-composeexecコマンドを使用してデータベースで移行を実行します。

docker-compose exec app bundle exec rake db:setup db:migrate

docker-compose execコマンドを使用すると、サービスでコマンドを実行できます。 ここでは、これを使用して、アプリケーションバンドルのコンテキストでrake db:setupおよびdb:migrateを実行し、データベースを作成してシードし、移行を実行します。 開発作業中、docker-compose execは、開発データベースに対して移行を実行する場合に役立ちます。

このコマンドを実行すると、次の出力が表示されます。

OutputCreated database 'rails_development'
Database 'rails_development' already exists
-- enable_extension("plpgsql")
   -> 0.0140s
-- create_table("endangereds", {:force=>:cascade})
   -> 0.0097s
-- create_table("posts", {:force=>:cascade})
   -> 0.0108s
-- create_table("sharks", {:force=>:cascade})
   -> 0.0050s
-- enable_extension("plpgsql")
   -> 0.0173s
-- create_table("endangereds", {:force=>:cascade})
   -> 0.0088s
-- create_table("posts", {:force=>:cascade})
   -> 0.0128s
-- create_table("sharks", {:force=>:cascade})
   -> 0.0072s

サービスを実行している状態で、ブラウザでlocalhost:3000またはhttp://your_server_ip:3000にアクセスできます。 次のようなランディングページが表示されます。

これで、データの永続性をテストできます。 Get Shark Info ボタンをクリックして新しいサメを作成します。これにより、sharks/indexルートに移動します。

アプリケーションが機能していることを確認するために、いくつかのデモ情報をアプリケーションに追加できます。 NewSharkをクリックします。 プロジェクトの認証設定のおかげで、ユーザー名( sammy )とパスワード( shark )の入力を求められます。

New Shark ページで、 Name フィールドに「Mako」を入力し、Factsフィールドに「Fast」を入力します。

サメの作成ボタンをクリックしてサメを作成します。 サメを作成したら、サイトのナビゲーションバーでホームをクリックして、メインのアプリケーションランディングページに戻ります。 これで、Sidekiqが機能していることをテストできます。

どのサメが危険にさらされていますか?ボタンをクリックします。 絶滅危惧種のサメをアップロードしていないため、endangeredindexビューに移動します。

絶滅危惧種のサメのインポートをクリックして、サメをインポートします。 サメが輸入されたことを知らせるステータスメッセージが表示されます。

インポートの開始も表示されます。 ページを更新して、テーブル全体を表示します。

Sidekiqのおかげで、絶滅危惧種のサメの大量のバッチアップロードは、ブラウザをロックしたり、他のアプリケーション機能に干渉したりすることなく成功しました。

ページの下部にあるホームボタンをクリックすると、アプリケーションのメインページに戻ります。

ここから、どのサメが危険にさらされていますか?をもう一度クリックします。 アップロードされたサメがもう一度表示されます。

アプリケーションが正しく機能していることがわかったので、データの永続性をテストできます。

ターミナルに戻り、次のコマンドを入力して、コンテナを停止して削除します。

docker-compose down

--volumesオプションは含まれていないことに注意してください。 したがって、db_dataボリュームは削除されません。

次の出力は、コンテナとネットワークが削除されたことを確認します。

OutputStopping rails-docker_sidekiq_1  ... done
Stopping rails-docker_app_1      ... done
Stopping rails-docker_database_1 ... done
Stopping rails-docker_redis_1    ... done
Removing rails-docker_sidekiq_1  ... done
Removing rails-docker_app_1      ... done
Removing rails-docker_database_1 ... done
Removing rails-docker_redis_1    ... done
Removing network rails-docker_default

コンテナを再作成します。

docker-compose up -d

docker-compose execおよびbundle exec rails consoleを使用して、appコンテナーでRailsコンソールを開きます。

docker-compose exec app bundle exec rails console

プロンプトで、データベースのlastシャークレコードを調べます。

Shark.last.inspect

作成したばかりのレコードが表示されます。

IRB session  Shark Load (1.0ms)  SELECT  "sharks".* FROM "sharks" ORDER BY "sharks"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> "#<Shark id: 5, name: \"Mako\", facts: \"Fast\", created_at: \"2019-12-20 14:03:28\", updated_at: \"2019-12-20 14:03:28\">"

次に、次のコマンドを使用して、Endangeredサメが持続していることを確認できます。

Endangered.all.count
IRB session   (0.8ms)  SELECT COUNT(*) FROM "endangereds"
=> 73

db_dataボリュームは、再作成されたdatabaseサービスに正常にマウントされ、appサービスが保存されたデータにアクセスできるようになりました。 localhost:3000/sharksまたはhttp://your_server_ip:3000/sharksにアクセスしてindexsharkページに直接移動すると、次のレコードも表示されます。

絶滅危惧種のサメもlocalhost:3000/endangered/dataまたはhttp://your_server_ip:3000/endangered/dataビューに表示されます。

これで、アプリケーションは、データの永続性とコードの同期が有効になっているDockerコンテナで実行されます。 appサービスの一部として定義したバインドマウントのおかげで、ホストでローカルコードの変更をテストできます。これは、コンテナに同期されます。

結論

このチュートリアルに従うことで、Dockerコンテナーを使用してRailsアプリケーションの開発セットアップを作成しました。 機密情報を抽出し、アプリケーションの状態をコードから切り離すことで、プロジェクトをよりモジュラーでポータブルにしました。 また、開発のニーズや要件の変化に応じて修正できる定型文docker-compose.ymlファイルを構成しました。

開発するにつれて、コンテナ化された CloudNativeワークフロー用のアプリケーションの設計についてさらに学ぶことに興味があるかもしれません。 これらのトピックの詳細については、Kubernetes用アプリケーションのアーキテクチャおよびKubernetes用アプリケーションの最新化を参照してください。 または、Kubernetesの学習シーケンスに投資したい場合は、フルスタック開発者向けKubernetesカリキュラムをご覧ください。

アプリケーションコード自体の詳細については、このシリーズの他のチュートリアルを参照してください。