はじめに
Dockerに関する学習のアウトプットとして、RailsプロジェクトをDocker化しましたため、その方法を記事として残しておきます。また、詳細は後述しますが、初めてマルチステージビルドでインストールにも挑戦してみましたため、今後マルチステージビルドで環境構築される方の参考になればと思います。
前提条件
開発環境は以下の通りです。
- Mac(Intel)
- Ruby 3.0.2
- postgres 12.0
- node 14.8.0
- yarn 1.22.4
作成したファイル
Dockerで開発環境を構築するために作成したDockerfile
とdocker-compose.yml
について説明していきます。ちなみにローカル環境のディレクトリ構成は以下の通りとなっております。
/rails-docker
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
├── babel.config.js
├── bin
├── config
| └- database.yml
├── config.ru
├── db
├── docker-compose.yml
├── lib
├── log
├── node_modules
├── package.json
├── postcss.config.js
├── public
├── storage
├── test
├── tmp
├── vendor
└── yarn.lock
まずはDockerfileについてです。
FROM node:14.8.0-stretch as node
FROM ruby:3.0.2
ENV YARN_VERSION 1.22.4
COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
&& ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs \
&& ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
postgresql-client
WORKDIR /rails-docker
COPY Gemfile Gemfile.lock /rails-docker/
RUN bundle install
マルチステージビルドについて
最初に説明しましたが、nodejs、yarnはapt-get
を使用せずにマルチステージビルドでインストールしております。DockerファイルにFROM
を2つ書くことによって実現しております。
そもそもマルチステージビルドとは??という方のために、まずそのことについて記載します。
マルチステージビルドでインストールすることの最大のメリットは イメージが軽量になることです。
イメージが軽量になることによって、ビルド時間の短縮やホストへのディスク容量の逼迫を防ぐことなど にも繋がります。
なぜイメージの軽量化が実現しているのかと言いますと、nodejsやyarnをapt-get
でインストールする方法ですと、Railsプロジェクトを実行するのに不要なファイルも含まれてしまいます。そのため、FROM
を2つ書くことで、nodejsのイメージ(node:14.8.0-stretch)の中からRailsプログラムを実行するのに必要なプログラムだけを抽出して、rubyのイメージ(ruby:3.0.2)にコピーすることによって、イメージの軽量化を実現しております。
例えば、Go言語のようにビルドした結果のバイナリファイルだけあればプログラムとして、実行できます。コンパイル前のファイルはプログラムを実行するのには不要なため、コンパイル前のプログラムはイメージに含めずに作成することによって、イメージの軽量化を実現しています。
以下の記事を参考にしました。
Dockerfileのコード説明
以下コードはマルチステージビルドの説明で概要はお伝えしておりますので、細かいコードについて説明を記載します。
FROM node:14.8.0-stretch as node
FROM ruby:3.0.2
ENV YARN_VERSION 1.22.4
COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
&& ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs \
&& ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx
-
FROM node:14.8.0-stretch as node
でas 〜
でnode
というエイリアス(別名)を定義しております。 -
ENV YARN_VERSION 1.22.4
でYARN_VERSION
という環境変数にyarnのバージョン1.22.4を設定しております。 -
COPY --from=node
でFROM node:14.8.0-stretch as node
で指定したエイリアスnodeのイメージからFROM ruby:3.0.2
で指定したRubyのイメージにnodeとyarnをコピーしております。 -
ln -s リンク元 リンク先
はLinuxコマンドでシンボリックリンクを作成しております。これによって、Rubyイメージでyarnやnodeなどを使用できるようになります。
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
postgresql-client
-
apt-get update
でパッケージリストを最新の状態に更新します。 -
apt-get install -y
で指定したパッケージをインストールします。-y
オプションでパッケージのインストール中にYes、Noが聞かれた際にYesで回答するように指定しております。 -
build-essential
は開発に必須のビルドツールを提供しているパッケージ。gcc(GNU C Compiler)、g++(GNU C++ Compiler)、 makeなどが入っております。(RubyはC言語で作られた言語のため、インストールが必要と思われます。) -
libpq-dev
はRuby(C言語で作られたプログラム)からPostgreSQLに通信するために必要なライブラリ -
postgresql-client
はpsqlを使用して、PostgreSQLデータベースに接続して対話的にクエリを実行できます。SQLのコマンドを直接入力できます。 -
&&
はLinuxコマンドを続けて実行することができます。 -
\
は改行で、見た目を整えることができます。
以下の記事を参考にしました。
- apt-get - パッケージの操作・管理 - Linuxコマンド
- Ubuntuのaptを調べたのでまとめておく
- build-essentialとは
- パッケージ: libpq-dev
- psqlとは?PostgreSQLへの接続と利用方法を解説!
docker-compose.ymlのコード説明
docker-composeを使用することで、長くなってしまうDockerコマンドを短いコマンドで実行できるようにしております。こちらもコードの細かい説明を記載しております。
version: '3'
volumes:
db-data:
services:
web:
build: .
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/rails-docker
environment:
- 'DATABAS_PASSWORD=postgres'
ports:
- "3000:3000"
depends_on:
- db
links:
- db
tty: true
stdin_open: true
db:
image: postgres:12.0
volumes:
- 'db-data:/var/lib/postgresql/data'
environment:
- 'POSTGRES_USER=postgres'
- 'POSTGRES_PASSWORD=postgres'
Dockerfileをビルドします。.
と指定しているため、ビルドするためにはdocker-compose.yml
とDockerfile
が同じ階層にある必要があります。
build: .
bundle exec rails s -p 3000 -b '0.0.0.0'
でrailsサーバを起動しております。また、/bin/sh -c "rm -f tmp/pids/server.pid"
と記載しているのはrailsサーバを立ち上げる際に前回立ち上げた際に作成されたtmp/pids/server.pid
が残っていることによって、railsサーバがうまく立ち上がらない事象が発生しましたため、毎回削除するようにしております。
command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
ホストのdocker-composeコマンドを実行するディレクトリとコンテナのディレクトリ/rails-dockerをマウントしております。マウントすることによって、コンテナからホストのRailsプログラムを参照できるため、コンテナ上にRailsプログラムを持たなくてよくなり、コンテナの軽量化にも繋がります。Dockerコマンドの-v ホスト:コンテナ
と同一です。
volumes:
- .:/rails-docker
以下はconfig/database.yml
で定義しているpassword: <%= ENV.fetch("DATABAS_PASSWORD") %>
で使用するために記述しております。Railsからposgresに接続するためのパスワードを設定するために記述しております。
environment:
- 'DATABAS_PASSWORD=postgres'
以下でポートの開放を行います。
左にホストのポートを、右にコンテナのポートを指定します。
Dockerコマンドの場合、 -p 3000:3000
オプションと同一です。
ports:
- "3000:3000"
サービス間の依存関係を示します。webの前にdbを開始して、その後にwebが開始するようにしております。
depends_on:
- db
コンテナを他のサービスとリンクlinkします。サービスwebからdbを参照できるようになります。
以下は記述しなくてもwebからdbを参照できます。networkで名前解決してくれるためです。
links:
- db
コンテナに接続(実行中のコンテナにdocker-compose exec web bash
コマンドを叩いて接続)した際にstdin_open: true
で標準入力を可能にしております。また、tty: true
で出力結果をきれいに表示できるようにしております。Dockerコマンドの-it
と同一です。
tty: true
stdin_open: true
以下はDBデータをコンテナ上に保存するのではなく、ホスト側に保存するようにマウントしております。コンテナ上に保存してしまうとコンテナが消えてしまうと、DBデータが消えてしまうためです。コンテナを止めてもデータが残るようにホスト側に保存するようにしております。
volumes:
- 'db-data:/var/lib/postgresql/data'
上記で指定したdb-data
は以下でDocker volumeを作成しております。
volumes:
db-data:
以下の記事を参考にしました。
- Compose ファイル version 3 リファレンス
- A server is already running. Check /tmp/pids/server.pidエラーの対応
- いい加減docker-composeでlinksを使うのをやめてnetworkでコンテナ間名前解決をする
- docker-compose-で、links-使う必要なかったんや
webアプリケーションの起動・停止方法
Dockerとdocker-composeで作成したアプリケーションを起動・停止するためのコマンドを記載します。
- アプリケーションを起動
docker-compose up
2. データベースを作成。docker-compose upを実行したターミナルとは別のターミナルを新たに開き、以下コマンドを実行
docker-compose run web rake db:create
3. データベースにテーブルを作成
docker-compose run web rake db:migrate
4. ブラウザを開き、以下URLを入力
http://localhost:3000/
以下画面が表示される。
5. アプリケーションを停止。`docker-compose up`を実行したターミナルで以下を実行
Ctrl-C
6. アプリケーションを再起動
docker-compose up