docker-composeコマンドメモ~Rails5.1 + webpacker~

前回までとは違う話ですが, 開発環境をdockerで作ろうとしています.

今回はRailsでwebpackerを使ってReactを動かしたいので, その環境構築の自分なりのメモです. 

いまいちdockerのイメージとコンテナの違いが, あとdocker-composeのbuild, run, upの違いがわからないので整理しようかと思います. (間違っていたら教えていただけると幸いです(涙))

 

 

Dockerでイメージ作成からコンテナ起動まで

Dockerfileでビルドするイメージ作成

やりたいことはこんな感じ.

onoxeve.com

で, Dockerの公式にもRails+Postgresのがあったので, そちらを主な参考にしてみる.

docs.docker.com

 

Dockerfileはコンテナが起動時の参考にする環境である"イメージ"を作成するものと認識.  このイメージを作成してdocker imagesでimageが表示される様にすることを"build"と認識.

 

・Dockerfile

# Ruby2.5.1のイメージをベースとして取得
FROM ruby:2.5.1
# ruby:2.5.1が取得したイメージ[buildpack-deps:stretch]の元が[debian:stretch]なので, aptコマンドを使用する
# インデックスファイルの更新とパッケージのダウンロード
# -q : 進行状況非表示, -y : 全てyesを自動回答
RUN apt-get update -q && apt-get install -y build-essential libpq-dev
# nodesourceのapiから情報をget -> bashコマンドで読み込んだファイルを実行
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
# バージョンを指定したnodejsのインストールを実行
RUN apt-get install -y nodejs
# yarnのstabelバージョンをインストール
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn
# コンテナ内での作業フォルダ作成と作業ディレクトリへの移動(指定)
RUN mkdir /web_container
WORKDIR /web_container
# ホストからコンテナ側へファイルのコピー(事前にホスト側で作成しておく)
COPY Gemfile /web_container/Gemfile
COPY Gemfile.lock /web_container/Gemfile.lock
# コンテナ内でGemfileのインストール&更新
RUN bundle install
# ホストの作業ディレクトリ内を全てコンテナ側にコピー
COPY . /web_container

これがイメージをビルドするベースのファイルになる.

 

docker-compose.yml作成

従来ではコンテナ間通信で"network"とか"--link"とかしてたのを簡単にするものと認識.

・docker-compose.yml

version: '3'
services:
db:
# postgresqlをvrsion10でインストール
image: postgres:10
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: my_db
volumes:
# 作業ディレクトリ:コンテナ内でデータのマウント
- ./tmp/db:/var/lib/postgresql/data
# PG Commanderから接続するためにポート変更
ports:
- '5433:5432'
container_name: "my_db"
web:
# 作業ディレクトリ内のDockerfileをビルド
build: .
# ポートの3000番を利用. localhost以外のIPアドレスからアクセス可能な様に0.0.0.0にバインド
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/web_container
container_name: "my_web"
ports:
- "3000:3000"
depends_on:
- db

あとは

 ・Gemfile

source 'https://rubygems.org'
gem 'rails', '5.1.2'

と, 空のGemfile.lockを用意して終了.

 

イメージのビルドとコンテナ操作

docker-compose run --rm web rails new . --force --database=postgresql --webpack=react

を実行. これの中身を解説していく.

 

別のDockerの公式(Quickstart: Compose and Django | Docker Documentation)をみると,

Create the Django project by running the docker-compose run command as follows.

 sudo docker-compose run web django-admin.py startproject composeexample .

This instructs Compose to run django-admin.py startproject composeexample in a container, using the web service’s image and configuration. Because the web image doesn’t exist yet, Compose builds it from the current directory, as specified by the build: . line in docker-compose.yml.

Once the web service image is built, Compose runs it and executes the django-admin.py startprojectcommand in the container. This command instructs Django to create a set of files and directories representing a Django project.

 とある. つまり run service名 コマンド で, service名のイメージから立ち上げられた(立ち上げられる予定の)コンテナ内でコマンドが実行される. しかし, run実行時点ではwebコンテナはおろか, webコンテナの起動ベースとなるイメージがビルドされていないので, docker-compose.ymlの build: . で, まずDockerfileを読み込んでイメージのビルドが行われると認識.

ちなみにここではrunされたservice: webの依存関係として depends_on: dbとなっているので, まずdbのイメージがビルドされる. それはimage: postgres:10であり, dockerhubからpullされる. postgresのコンテナはdocker-compose upしなくてもこのコマンドだけで起動状態を保っている. 調べきれていないが, databaseはrunでイメージのビルドからコンテナ起動まで出来るっぽい??

で, service: webのイメージがビルドされたらrails new .... 以降のコマンドが実行される. 

--rm : runで一時的にコンテナに入ると中間コンテナと呼ばれるコンテナが出来るっぽくて, そのままにしておくとコンテナの数が増えていくっぽい. ので--rmで中間コンテナを削除すれば, docker-compose upでコンテナを作成しても, 諸々インストールされたコンテナが1つ起動するだけで済む??

rails new . : カレントディレクトリでrails newする??

--force : ファイルが存在していれば上書きする. GemfileとかGemfile.lockのことかなぁ...?(railsコマンド(rails) - - Railsドキュメント

 

以上でmy_webコンテナ(docker-compose.ymlに記したコンテナ名)内ではrailsアプリの環境が出来上がっているはず.

この時点では,docker ps -aしてもNAMES: my_webは無い. docker imagesするとREPOSITORY: my_webはある.

 

次いで以下を参考にデータベースの接続設定を行う.

Connect the database

config/database.yml with the following:

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: user
  password:
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test

 

イメージのリビルド

 さっきの処理でGemfileに変更が生じたっぽいので, Gemfile.lockを更新する必要があり, その場合my_webコンテナが利用するイメージのリビルドが必要になる. 今後Gemfileの更新があった場合は, 

docker-compose run --rm web bundle install

docker-compose up -d --build

をすれば良い模様. 2つめのコマンドを実行すると, service: webのbuildが呼ばれ, Dockerfileが呼び出される. Dockerfileは以前と変更がないコマンドが現れるまでの処理を飛ばしてくれるので, ここでは COPY Gemfile /web_container/Gemfile 以降が実行される. その後service: webのコンテナをデタッチモード(バックエンド)で起動してくれる.

 

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my_web latest ********* 2 minutes ago 1.22GB
<none> <none> ********* 2 hours ago 1.05GB

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
******** my_web "bundle exec rails s…" 2 minutes ago Up 2 minutes 0.0.0.0:3000->3000/tcp my_web

と, 謎の<none>イメージができている. コンテナはmy_webイメージを元に起動されているので, noneイメージは不要だと思われるので消す. イメージのリビルドが行われると前のイメージが<none>になって新しいイメージが作成されるのか??? 

docker rmi -f IMAGE IDでイメージ削除.

 

で, 最後にデータベースを作成すれば完了.

docker-compose run --rm web rake db:create

 

これでlocalhost:3000にアクセスすれば一応動く. パソコンを再起動するとコンテナは終了しているので(restart: alwaysしてないため), docker-compose.ymlのあるディレクトリに移動して, docker-compose up -dをすれば良い.

 

データベース接続

postgresデータベースの中身を見たかったので, ちょっとメモしておきます.

# コンテナに入る
$ docker exec -it データベースのコンテナID bash

# データベースに接続
/# psql --username=user --dbname=my_db

# データベース一覧表示
my_db=# \l

# 抜ける
ctrl P Q

となる. 

 

GUIツールであるPG Commanderでの接続方法は以下です.

Nickname: 好きな名前で良い

# dockerの場合, HostはdockerコンテナのIPではないらしい
Host: 127.0.0.1

# Portはdocker-compose.ymlで指定したやつ
Port: 5433

User: POSTGRES_USERで指定したやつ
Pass: POSTGRES_PASSWORDで指定したやつ
Database: POSTGRES_DBで指定したやつ

localに別のpostgresがあった場合, PG Commanderで接続するとブッキングするっぽかったので, docker-compose.ymlでホスト側はポート番号5433で, dockerコンテナのデータベース(ポート5432)に接続できる様に変えました.

 

まとめ

ひとまず環境構築はできたみたいなので, 次はyarnとかwebpackerの使い方, es6でReactコンポーネント作るあたりまでやります.