11
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rails Tutorialの知識から【ポートフォリオ】を作って勉強する話 #19 Docker編

Posted at

こんな人におすすめ

  • プログラミング初心者でポートフォリオの作り方が分からない
  • Rails Tutorialをやってみたが理解することが難しい

前回:#18 EC2環境構築, Nginx+Puma+Capistrano編
番外:#18.5 環境変数, Gmail送信設定編
次回:準備中

今回の流れ

  1. 完成のイメージを理解する
  • Dockerを導入する理由を知る
  • RailsアプリをGitHubからクローンする
  • ローカルの開発環境を整える
  • Dockerをインストールする
  • Dockerの仕組みを理解する
  • Dockerのファイルを作成する
  • Dockerを起動する
  • トラブルシューティング

この記事は、動画を観た時間を記録するアプリのポートフォリオです。
今回は、Railsアプリの開発環境にDockerを組み込みます。
ローカル(ホスト)にはMacを使います。

完成のイメージを理解する

はじめにDockerの必要性を知ります。
ローカル(Mac)にRailsアプリがない、動く環境にない方は先に環境を整えます。

次にDockerを構成します。
具体的には、プロセスをapp(RailsやPumaなど)db(MySQL)nginx(Nginx)の3つに分け、Docker Composeで定義します。
ここでDockerを構成しながら、Dockerの理解を深めます。

最後にDockerを起動します。
起動がスムーズに行くことは稀で、何らかのエラーが発生します。
トラブルシューティングを活用しながら、起動を成功させます。

以上です。

Dockerを導入する理由を知る

Dockerは、軽くてポータビリティのある開発環境ツールです。
Dockerは、モダンな企業のほとんどが使うツールです。
Dockerを、ポートフォリオに組み込むことで、転職先の企業とのマッチング率を高めるという狙いがあります。

さてDockerの動作については、こちらの記事が分かりやすいので、一読します。
いまさらだけどDockerに入門したので分かりやすくまとめてみた

RailsアプリをGitHubからクローンする

RailsアプリをローカルであるMacにクローンします。
※ すでにローカルでRailsアプリを開発している方は飛ばしてください。

local(自分のMacターミナル)
$ vi ~/.gitconfig
.gitconfig
[user]
  name = Gitに登録している名前
  email = Gitに登録しているメールアドレス

[url "github:"]
  InsteadOf = https://github.com/
  InsteadOf = git@github.com:
local
$ cd ~/.ssh
$ ssh-keygen -t rsa
Enter file in which to save the key ():git_rsa
Enter passphrase (empty for no passphrase): 
# 何もせずエンター
Enter same passphrase again: 
# 何もせずエンター
$ vi config
.ssh/config
# 以下を追加
Host github
  Hostname github.com
  User git
  IdentityFile ~/.ssh/git_rsa
local
$ cat git_rsa.pub
# 中身をコピー

GitHubにログイン
右上アイコン『Settings』 → 『SSH and GPG keys』 → 『New SSH key』

Title:任意
Key:コピーした公開鍵をペースト
local
$ cd ~
$ git clone -b ブランチ名 git@
github.com:GitHubのユーザー名/アプリ名.git

以上でRailsアプリのクローンは完了です。

参考になりました↓
リモートから特定のブランチを指定してcloneする

ローカルの開発環境を整える

ローカル(Mac)の開発環境を整えます。
ここでの手順は以下の通りです。
※ すでにローカルでRailsアプリを開発している方は飛ばしてください。

  • Homebrewをインストールする
  • Rubyをインストールする
  • Bundlerをインストールする
  • MySQLをインストールする

Homebrewをインストールする

Homebrew(公式)をインストールします。
HomebrewはMacでよく利用されるパッケージ管理です。

local(Mac)
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Rubyをインストールする

Rubyをインストールします。
RubyはMacに標準で入っていますが、バージョン管理のためにrbenvを使います。

local(Mac)
$ brew install rbenv ruby-build
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source .bash_profile
$ rbenv install 使いたいバージョン
$ rbenv global 使いたいバージョン
$ rbenv rehash

Bundlerをインストールする

Bundlerをインストールします。

$ gem install bundler

MySQLをインストールする

MySQLをインストールします。

$ brew install mysql

参考になりました↓
Ruby初学者のRuby On Rails 環境構築【Mac】

Dockerをインストールする

Docker Desktop for Macからアカウントを作成し、インストールします。
手順は以下の通りです。

  1. 『Get Started』からDcokerHubアカウントを作成する
  2. 『Get Docker』からDockerをインストールする

参考になりました↓
DockerをMacにインストールする

Dockerの仕組みを理解する

それではDockerを使って、環境を構築します。
仕組みとしては、app(RailsとPuma)db(MySQL)nginx(Nginx)のイメージをDockerfileなどで用意し、Docker Composeでプロセスを起動させます。

早速、以下のようにホスト側のディレクトリを構成します。
Dockerの各ファイル、用語は後述します。

lantern_app
├── config
│   ├── database.yml(既存)
│   └── puma.rb(既存)
├── containers
│   └── nginx
│       ├── Dockerfile
│       └── nginx.conf
├── docker-compose.yml
├── Dockerfile
├── environments
│   └── db.env
├── Gemfile(既存)
├── Gemfile.lock(既存)
└── 他

用語を説明します。

Image
色々な環境を提供してくれる入れ物のことです。
イメージからRubyやNginxなどを取得します。

Dockerfile
イメージを作るためのファイルです。
イメージを元に機能を拡張するなどの用途があります。

Volume
データ永続のための保存場所です。
Dockerのデータはコンテナの終了とともに消えるため、必要に応じて設定します。

Container
イメージを元に作られたプロセスのことです。
イメージを起動すると、環境がプロセスとしてコンテナに隔離されます。

Docker Compose
複数のコンテナを定義・実行するツールです。

Dockerのファイルを作成する

それではDockerのディレクトリとファイルを作成します。

local(Mac)
$ touch Dockerfile docker-compose.yml
$ mkdir containers containers/nginx environments
$ cd containers/nginx
$ touch Dockerfile nginx.conf
$ cd ../..
$ touch environments/db.env

各ファイルを編集します。
各ファイルの詳細は、後述します。

Dockerfile
# 元にするイメージ
FROM ruby:2.6.3
# コンテナを機能させるまでの準備のコマンドを実行する
RUN apt update -qq && \
    apt install -y build-essential nodejs
RUN mkdir /lantern_docker
# 環境変数を設定する
ENV APP_ROOT /lantern_docker
# コマンドを実行するディレクトリを設定する
WORKDIR $APP_ROOT
# ホストのファイルをコンテナにコピーする
ADD Gemfile $APP_ROOT/Gemfile
ADD Gemfile.lock $APP_ROOT/Gemfile.lock
# 既出
RUN gem install bundler
RUN bundle install
ADD . $APP_ROOT
RUN mkdir -p tmp/sockets
# コンテナ起動時のポートを設定する
EXPOSE 3000

RailsアプリはRubyイメージを元にして作成します。
RUN apt ...でRailsが動く環境をインストールし、ADD . $APP_ROOTでGemfileなどをコンテナにコピーし、RailsやPumaなどを動作させます。

docker-compose.yml
# Docker Composeのバージョン
version: '3'

# Docker Composeではコンテナをサービスとして扱う
services:
  # サービス名をappとして定義
  app:
    # 参照するDockerfileを指定(docker-compose.ymlから基準)
    build: .
    # 環境変数が設定されているファイルを指定
    env_file:
      - ./environments/db.env
    # ボリュームをマウント(後述)
    volumes:
      - .:/lantern_docker
    # サービス名dbが作成されたらappを作成
    depends_on:
      - db
    # コンテナを起動させ続ける際に使用
    tty: true
    # コマンドを実行
    command: bundle exec puma -C config/puma.rb

  db:
    # イメージを指定(後述)
    image: mysql
    env_file:
      - ./environments/db.env
    # ボリュームをマウント(後述)
    volumes:
      - db-data:/var/lib/mysql

  nginx:
    build: containers/nginx
    # ホスト:コンテナのポートを指定
    ports:
      - "80:80"
    depends_on:
      - app

# ボリュームとして扱うボリューム名
volumes:
  db-data:

Docker Composeの各サービスは、DockerfileまたはDockerHubのイメージを参照します。
ここでは、appとnginxがDockerfile、dbがイメージを参照しています。

appのボリュームは、ホスト側のホームディレクトリ全てをボリューム化しています。
dbのボリュームは、コンテナ側のディレクトリ/var/lib/mysqlをdb-dataというボリューム名でボリュームをマウントしています。

この辺りはややこしく、参考記事を読むことをおすすめします。

参考になりました↓
Docker、ボリューム(Volume)について真面目に調べた
Dockerの-vや--volumeオプションはわかりづらいから、--mountを使おう
バインドマウント | Docker docs(日本語)
Pumaの起動におけるpumaコマンドとpumactlコマンドの違い

containers/nginx/Dockerfile
FROM nginx
RUN rm -f /etc/nginx/conf.d/*
ADD nginx.conf /etc/nginx/conf.d/lantern_docker.conf
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf

Nginxはフォアグラウンドでの動作を期待しているので、'deamon off;'とします。
フォアグラウンドとバックグラウンドの違いは、PCで表すとこんな感じです。

  • フォアグラウンド:一番上のウインドウ
  • バックグラウンド:それ以外のウインドウ

参考になりました↓
フォアグラウンド(foreground)とは | 「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

containers/nginx/nginx.conf
# Pumaとやり取りするための通信路
upstream lantern_docker {
  server unix:///lantern_docker/tmp/sockets/puma.sock;
}
# サーバーに関する情報
server {
  # ポート
  listen 80;
  # 処理するサーバー名
  server_name localhost;
  # ログに関するファイルの場所
  access_log /var/log/nginx/access_log;
  error_log /var/log/nginx/error_log;
  # ドキュメントルートの設定
  root /lantern_docker/public;
  try_files $uri/index.html $uri @app;

  # 内部リダイレクトの処理
  location @app {
    # バックエンドサーバーに送信するヘッダーを定義し直す
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    # プロキシのパス(Pumaに渡す)
    proxy_pass http://lantern_docker;
    proxy_redirect off;
  }
}

アプリ名を自分のものに変更します。
Nginxの設定は#18で説明済みなので、省略します。

environments/db.env
MYSQL_USER=ユーザー名
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_HOST=エンドポイント

環境変数の設定です。
エンドポイントが分からない場合、#17.5をご覧ください。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  timeout: 5000
  reconnect: false
  pool: 5
  socket: /var/lib/mysql/mysql.sock
  username: <%= Rails.application.credentials.mysql[:user_name] %>
  password: <%= Rails.application.credentials.mysql[:password] %>
  host: <%= Rails.application.credentials.mysql[:host] %>

development:
  <<: *default
  database: lantern_development

test:
  <<: *default
  database: lantern_test

production:
  <<: *default
  database: lantern_production

MySQLの設定です。
credentailsが未設定の場合は、#18.5をご覧ください。

config/puma.rb
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  ActiveRecord::Base.establish_connection
end

plugin :tmp_restart

app_dir = File.expand_path("../..", __FILE__)
bind "unix://#{app_dir}/tmp/sockets/puma.sock"
pidfile "#{app_dir}/tmp/pids/puma.pid"
stdout_redirect "#{app_dir}/log/puma.stdout.log", "#{app_dir}/log/puma.stderr.log", true

Pumaの設定です。
ここも#18で説明済みなので、省略します。

以上で、Dockerのファイル編集は完了です。

Dockerを起動する

Docker Composeを使ってDockerコンテナを起動します。

local(Mac)
# Dockerfileからイメージをビルド
$ docker-compose build
# Docker Composeのコンテナを起動(-dでバックグラウンド起動)
$ docker-compose up -d
# Docker Composeのコンテナのプロセスを確認
$ docker-compose ps

以上でDockerの組み込みは完了です。
後は各コンテナに入り、開発を進めてください。

shell
# appのbashに入る
$ docker-compose exec app bash
# 例
$ rails db:migrate

参考になりました↓
Docker + Rails + Puma + Nginx + MySQL
丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)
既存のRailsアプリにDockerを導入する手順
Nginx + Rails (Puma) on Docker のいくつかの実用パターン
Docker + Rails + Puma + Nginx + Postgres
Docker ComposeでNginx Rails MySQL環境を構築してみる

トラブルシューティング

Dockerで起動する際、様々なエラーが発生します。
一例ですが、私が見舞ったトラブルの解決策を書き残します。

よく使うスクリプトを確認する

先によく使うスクリプトを紹介します。
まずはDockerやDocker Composeのコマンドを紹介します。

shell
# ログの確認
$ docker-compose logs
# サービスの確認
$ docker-compose ps -a
# コンテナの確認
$ docker ps -a
# コンテナとネットワークの停止と削除
$ docker-compose down --rmi all
# コンテナの削除
$ docker rm ID名
# イメージの削除
$ docker rmi ID名
# コンテナのbash内に入る
$ docker-compose exec サービス名 bash

続いてbashを紹介します。

bash
# ディレクトリの有無を確認する(出力0=有、出力1=無)
$ test -f パス;echo $?
# プロセスが使用しているポートを確認する
$ lsof -i
# ポートを指定してプロセスを確認する
$ lsof -i:ポート番号

以上です。
以降から、具体的なトラブルシューティングに入ります。

参考になりました↓
Docker実践〜dockerのコンテナ環境をきれいに消す
docker-compose up したコンテナを起動させ続ける方法
Linux/UNIXでファイル・ディレクトリの存在確認をする
Linuxでプロセスが何のポート使っているかを調べる

/usr/local/lib/ruby/2.6.0/rubygems.rb:283:in `find_spec_for_exe': Could not find 'bundler' (2.1.4) (Gem::GemNotFoundException)

Bundlerが見当たらないのでエラーが発生します。
GemからBundlerをインストールします。

Dockerfile
# 以下を追加
RUN gem install bundler

参考になりました↓
Docker + Rails のdocker-compose build でGemNotFoundExceptionの時の対処

mysql client is missing.

MacにMySQLがないためにエラーが発生します。
HomebrewでMySQLをインストールします。

local(Mac)
$ brew install mysql

参考になりました↓
mysql2 が原因でbundle installにてエラーを吐く(Mac OS X)

uses an image, skipping

こちらはエラーではありません。
すでにビルドが済んだイメージをリモートで取得するので、upすれば問題ありません。

local(Mac)
$ docker-compose up -d

参考になりました↓
docker-compose.yml起動時にuses an image, skippingされる現象
docker-compose `up` とか `build` とか `start` とかの違いを理解できていなかったのでまとめてみた。

error: database is uninitialized and password option is not specified

データベースのエラーです。
データベースが初期化されていない、パスワードがないため発生します。
環境変数のあたりを確認します。

environments/db.env
MYSQL_USER=ユーザー名
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_HOST=エンドポイント
docker-compose.yml
# 中略
  db:
    image: mysql
    env_file:
      - ./environments/db.env
# 中略

参考になりました↓
docker, docker-composeでmysqlが起動しない
docker-compose.ymlで.envファイルに定義した環境変数を使う
How to link MySQL RDS in docker-compose.yml file?

NoMethodError: Cannot load database configuration:

データベースのエラーです。
データベースに関する設定に問題があります。

解決策1:ttyをtrueにする

ttyをtrueにすると解決するかもしれません。

docker-compose.yml
app:
# 中略
    tty: true
# 中略

参考になりました↓
docker-compose up したコンテナを起動させ続ける方法
docker-composで起動したコンテナがすぐに停止する

解決策2:database.ymlのERbを削除する

コメントアウトしていてもERbは評価されます(恐らく)。
database.yml内のERbは削除します。

config/database.yml
# 以下で書かれた必要ない箇所を削除する
<%= %>

参考になりました↓
Rails を起動したら Cannot load `Rails.application.database_configuration`: (NoMethodError) が出てハマった

502 Bad Gateway

何らかのサーバーに関するエラーです。
私の場合は、以下のように変更すると解決しました。

nginx.conf
upstream lantern_docker {
  # ソケットからサービス名に変更
  # server unix:///lantern_docker/tmp/sockets/puma.sock;
  server app:3000;
}
# 中略

参考になりました↓
Docker Compose と nginx でリバースプロキシを作ろうとしたお話(出題編)


前回:#18 EC2環境構築, Nginx+Puma+Capistrano編
番外:#18.5 環境変数, Gmail送信設定編
次回:準備中

11
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?