こんな人におすすめ
- プログラミング初心者でポートフォリオの作り方が分からない
- Rails Tutorialをやってみたが理解することが難しい
前回:#18 EC2環境構築, Nginx+Puma+Capistrano編
番外:#18.5 環境変数, Gmail送信設定編
次回:準備中
今回の流れ
- 完成のイメージを理解する
- 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アプリを開発している方は飛ばしてください。
$ vi ~/.gitconfig
[user]
name = Gitに登録している名前
email = Gitに登録しているメールアドレス
[url "github:"]
InsteadOf = https://github.com/
InsteadOf = git@github.com:
$ 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
# 以下を追加
Host github
Hostname github.com
User git
IdentityFile ~/.ssh/git_rsa
$ cat git_rsa.pub
# 中身をコピー
GitHubにログイン
右上アイコン『Settings』 → 『SSH and GPG keys』 → 『New SSH key』
Title:任意
Key:コピーした公開鍵をペースト
$ cd ~
$ git clone -b ブランチ名 git@
github.com:GitHubのユーザー名/アプリ名.git
以上でRailsアプリのクローンは完了です。
参考になりました↓
リモートから特定のブランチを指定してcloneする
ローカルの開発環境を整える
ローカル(Mac)の開発環境を整えます。
ここでの手順は以下の通りです。
※ すでにローカルでRailsアプリを開発している方は飛ばしてください。
- Homebrewをインストールする
- Rubyをインストールする
- Bundlerをインストールする
- MySQLをインストールする
Homebrewをインストールする
Homebrew(公式)をインストールします。
HomebrewはMacでよく利用されるパッケージ管理です。
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Rubyをインストールする
Rubyをインストールします。
RubyはMacに標準で入っていますが、バージョン管理のためにrbenvを使います。
$ 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からアカウントを作成し、インストールします。
手順は以下の通りです。
- 『Get Started』からDcokerHubアカウントを作成する
- 『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のディレクトリとファイルを作成します。
$ touch Dockerfile docker-compose.yml
$ mkdir containers containers/nginx environments
$ cd containers/nginx
$ touch Dockerfile nginx.conf
$ cd ../..
$ touch environments/db.env
各ファイルを編集します。
各ファイルの詳細は、後述します。
# 元にするイメージ
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のバージョン
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コマンドの違い
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用語辞典
# 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で説明済みなので、省略します。
MYSQL_USER=ユーザー名
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_HOST=エンドポイント
環境変数の設定です。
エンドポイントが分からない場合、#17.5をご覧ください。
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をご覧ください。
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コンテナを起動します。
# Dockerfileからイメージをビルド
$ docker-compose build
# Docker Composeのコンテナを起動(-dでバックグラウンド起動)
$ docker-compose up -d
# Docker Composeのコンテナのプロセスを確認
$ docker-compose ps
以上でDockerの組み込みは完了です。
後は各コンテナに入り、開発を進めてください。
# 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のコマンドを紹介します。
# ログの確認
$ 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を紹介します。
# ディレクトリの有無を確認する(出力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をインストールします。
# 以下を追加
RUN gem install bundler
参考になりました↓
Docker + Rails のdocker-compose build でGemNotFoundExceptionの時の対処
mysql client is missing.
MacにMySQLがないためにエラーが発生します。
HomebrewでMySQLをインストールします。
$ brew install mysql
参考になりました↓
mysql2 が原因でbundle installにてエラーを吐く(Mac OS X)
uses an image, skipping
こちらはエラーではありません。
すでにビルドが済んだイメージをリモートで取得するので、upすれば問題ありません。
$ 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
データベースのエラーです。
データベースが初期化されていない、パスワードがないため発生します。
環境変数のあたりを確認します。
MYSQL_USER=ユーザー名
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_HOST=エンドポイント
# 中略
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にすると解決するかもしれません。
app:
# 中略
tty: true
# 中略
参考になりました↓
docker-compose up したコンテナを起動させ続ける方法
docker-composで起動したコンテナがすぐに停止する
解決策2:database.ymlのERbを削除する
コメントアウトしていてもERbは評価されます(恐らく)。
database.yml内のERbは削除します。
# 以下で書かれた必要ない箇所を削除する
<%= %>
参考になりました↓
Rails を起動したら Cannot load `Rails.application.database_configuration`: (NoMethodError) が出てハマった
502 Bad Gateway
何らかのサーバーに関するエラーです。
私の場合は、以下のように変更すると解決しました。
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送信設定編
次回:準備中