②Dockerを初めて導入してRails sする (2020.4時点)






#1.これからDocker導入します、という方は、まず、こちらを見ていただけると幸いです。

**[①Dockerを初めて導入して基本操作する (2020.4時点)](https://qiita.com/SakagamiKeisuke/items/4455631886b1c15a3b69)**


本稿は、
**Dokerコンテナイメージを作成して、
コマンド「docker-compose up 」でRails s起動する**という流れです。

自分と同じように、
何していいかわからないゼロスタートの方になるべくわかるようにしたいと思っています。


#2.前提
Docker for Macアプリをインストールしている
Dockerサービスが起動している
DockerHubでサインインしている
VSCodeで編集
ターミナル使用
Sequelpro使用

<環境>
macOS : Catalina 10.15.3
Docker version : 19.03.8
ruby : 2.5.1
Rails : 5.2.4.1
MYSQL :5.6

<参考>
Dockerはこう書くとこう動くよ、というのがわかりやすい、こちらの動画ををおすすめします！
**Docker超入門 Part01〜Part04
https://youtu.be/7mwoTs0LoYA**
**今から追いつくDocker講座！AWS ECSとFargateで目指せコンテナマスター！〜シリーズ1回目〜
https://youtu.be/DS5HBTMG1RI**


では、はじめていきましょう！


#3.Dockerfile を新規作成して編集する
今回はVSCodeを使って進めます。
ローカルで作業中のRailsアプリを開き、Dockerfileをアプリのディレクトリの一番上位に新規作成します。

新規作成するファイル名は「  Dockerfile   」  です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/17da2224-0de9-2f99-1945-cf5fb6267da6.png)


Dockerfileに、ベースとするDockerイメージ（Ruby)に対して実行する内容を記述します。


このように記述してみます。


```ruby:Dockerfile

        #FROM(フロム)はDocker に対して ベースとなるRubyイメージを指定する
FROM ruby:2.5.1
        #run(ラン)はdocker-compose buildコマンドで実行される
        #Railsの起動に必要となるnodejsをインストールする
        #apt-getコマンドはUbuntuパッケージ管理システム＝APTライブラリを利用してパッケージ操作・管理するコマンド
        #①updateで常に新しいパッケージinstall →②-qqはエラー以外は表示しない →③常にyesの-y指定
        #→④ubuntuのbuild-essential(OS基礎開発パッケージ) → ⑤libpq-dev(OS開発パッケージ）
        #→⑥nodejs(サーバーサイドのJavaScript)  の順番でインストールする
        # \ バックスラッシュでコードを改行して見易くする       (\ はoption+¥です)
RUN apt-get update -qq && \
        apt-get install -y build-essential \
                                libpq-dev \
                                nodejs
        #今回はapp_nameという名前のディレクトリ（場所）を作ります
        #mkdir(メイクディレ)=(make directory)
        #ディレクトリ名は自由です
RUN mkdir /app_name
        /#WORKDIR(ワークディレ)は、RUNやADDなどの命令実行するカレントディレクトリ
        #カレントディレクトリ（作業位置）をapp_nameに移動（cdコマンドと同じ）
WORKDIR /app_name
        /#COPY(コピー)はローカル側のファイルをdockerイメージ側の指定したディレクトリにコピーする
        #ローカルのGemfileをapp_name/Gemfileにコピーする
        #ローカルのGemfile.lock をapp_name/Gemfile.lockにコピーする
        #docker-compose build 実行する前に、ローカルのGemfile.lock内を全削除しておきます（エラー対策）
COPY Gemfile /app_name/Gemfile
COPY Gemfile.lock /app_name/Gemfile.lock
        #gem install bundler インストールを実行する
        #bundle install を実行する
RUN gem install bundler
RUN bundle install
        #ADD(アド)はローカル側のファイルをdockerイメージ側の指定したディレクトリに追加（コピー）する
        #ローカルの(.)カレントディレクトリをコンテナのapp_nameディレクトリに追加（コピー+解凍）する
ADD . /app_name

```
このような感じです。（コメントアウトなし）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/b4fe89cf-8b7c-61d7-50f3-6eccf892070c.png)

コメントアウトあり
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/4f82d845-fafb-1569-af81-2e18bf99ff93.png)



プラスウイングTVさんの「Docker超入門 Part01 - Dockerを使った開発環境構築」がとてもわかりやすかったので引用させていただきます。（ありがとうございます！）
https://youtu.be/7mwoTs0LoYA


**・Rails の環境構築の元になるRuby、Rails、Nodejs、MySQLは、DockerHub上にあって勝手にそこから引っ張ってきてくれる。**
・DockerHubでrubyを検索 すると、真ん中あたりにruby2.5ありました。
　これをFROMに書けば勝手にベースにしてくれるのですね、すごい楽ちん！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/a0fdff38-0ebe-8d23-75ea-62e29c764e02.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/9a45750f-f467-0e32-6f46-8a134d383286.png)



##Dockerfile作成　Qiitaで参考になった記事
Dockerfileを書くためのベストプラクティス【参考訳】v18.09https://qiita.com/zembutsu/items/a96b68277d699f79418d
Docker × Ruby on Rails × MySQLの環境構築https://qiita.com/tatsuo-iriyama/items/0bf3b08de03280314c91
Ruby on Rails 「途中まで作ったアプリにDockerを導入したい」に挑戦してみるhttps://qiita.com/majorboy/items/9fbfc78fc7bbc1f35e77#comment-60a244ed29cedf06555d
Docker × Ruby on Rails × MySQLの環境構築https://qiita.com/tatsuo-iriyama/items/0bf3b08de03280314c91
Docker で環境変数をホスト OS 側からゲスト OS （コンテナ）に渡す方法（各種）https://qiita.com/KEINOS/items/518610bc2fdf5999acf2
Docker入門 ～Dockerfile編～ https://qiita.com/takaday/items/08c8269dc926af8cb661
Dockerfile のコマンド一覧https://qiita.com/FumiyaShibusawa/items/a0be39d28139a044157d
Bundlerの使い方 https://qiita.com/oshou/items/6283c2315dc7dd244aef
[Ubuntu] apt-get まとめhttps://qiita.com/white_aspara25/items/723ae4ebf0bfefe2115c


##Dockerfile作成  ググって参考になった記事
公式チュートリアル https://docs.docker.com/compose/rails/#connect-the-database
Dockerfile のベストプラクティス http://docs.docker.jp/engine/articles/dockerfile_best-practice.html
Dockerfile リファレンス http://docs.docker.jp/engine/reference/builder.html
Linuxのコマンド（とか）の呼び方をこじらせるhttps://unskilled.site/独学でプログラミングを勉強するとlinuxのコマンド/
build-essentialとは https://qiita.com/h_tyokinuhata/items/431a56fb054145468c16
Ubuntuとは？https://eng-entrance.com/what-is-ubuntu
パッケージ: build-essential (12.4ubuntu1) https://packages.ubuntu.com/ja/bionic/build-essential
パッケージ: libpq-dev  https://packages.ubuntu.com/ja/bionic/libpq-dev
mkdirコマンドの詳しいまとめhttps://eng-entrance.com/linux-command-mkdir
なぜ、Ruby on Railsの動作にNode.jsが必要なのか https://www.xenos.jp/~zen/blog2/index.php/2019/03/19/post-1831/


#4.docker-compose.ymlを編集する

**・DockerComposeは、複数コンテナを定義して同時起動するオーケストレーションツールです。**

**・docker-compose.ymlは設定記述用途のYAMLファイル形式でCompose ファイルと呼ばれ、
 サービス（services） 、 ネットワーク（networks） 、 ボリューム（volumes） を定義し、
アプリケーション全ての依存関係（データベース、キュー、キャッシュ、ウェブ・サービス、API 等）を設定します。**


docker-compose.ymlをRailsアプリのディレクトリの一番上位に新規作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/ba2b9836-d036-d8fd-3555-d69acc73c3de.png)



このように記述してみます。

```ruby:docker-compose.yml

        #docker-composeのバージョン(2020.4.12時点では"3"で問題なさそう)
version: '3'
        #servicesは各コンテナを定義します
services:
        #dbは1つのコンテナ名です（１コンテナ１プロセス）
        #ローカルmysql version確認 → mysql  Ver 14.14 Distrib 5.6.47
        #DockerHubでmysql5.6を確認できたので5.6と記述
  db:
    image: mysql:5.6
        #environmentは環境変数を追加します
        #環境変数MYSQL_ROOT_PASSWORDに、今回はpasswordと入れます（パスは自由）
        #パスワードの直打ちは危険なので、環境変数を使って秘匿します
    environment:
      MYSQL_ROOT_PASSWORD: 'password'
        #portsは公開用のポートで、ホスト側とコンテナ側の両方のポートを指定します（ ホスト側:コンテナ側 ）
        #ローカルMYSQLはポート確認すると3306を使用中なので、ホスト側は4306にします（4にした深い意味はありません）
        #ローカル側MYSQLは大抵は自動で3306になっているそうです
        #Sequelproにて4036(例として)を指定すると、DockerのMYSQLがSequelproで見れるようになります。
    ports:
      - "4306:3306"
      #webは1つのコンテナ名です（１コンテナ１プロセス）
      #buildはdockercompose.ymlを基点に指定フォルダー配下のDockerfileを元にコンテナを作成します。
      #指定は .  ルート （つまり、ルート直下に置いた先ほど作成したDockerfileを参照する、という記述です）
  web:
    build: .
      #commandは任意にコマンドを上書きできます。
      #bashはOSカーネルとユーザの橋渡しするプログラムシェルです
      #起動停止の繰り返しで起こるエラー「A server is already running.」の原因、pidをbuildのたび削除する（unicorn master KILLと同じですね）
      #Rails serverを立ち上げた際にURL(http://0.0.0.0:3000)にアクセス=localhost:3000
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
      #volumesではパスを指定するとDockerエンジンはボリュームを作成します
      #カレントディレクトリ(.)をapp_nameディレクトリにマウントします。
    volumes:
      - .:/app_name
      #portsは公開用のポートのことでホスト側とコンテナ側の両方のポートを指定します（ ホスト側:コンテナ側 ）
      #localhost:3000にアクセスするとコンテナの3000ポートにつながります
    ports:
      - "3000:3000"
      #depends_onはサービス間の依存関係を指定します
      #webコンテナ側からdbコンテナにdbの名前で接続できるようになります
      #docker-compose up を実行したら、web:コンテナのプロセスを開始するより前にdb:コンテナのプロセスを先に実行します
    depends_on:
      - db
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/510c1fe3-2679-9066-8e4d-2d2dc601f254.png)



##DockerHubでMYSQLを調べる

DockerHubで検索すると、MYSQLイメージが見つかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/74ce8398-e9c3-5646-cd88-37df7bce73fc.png)


##ローカルでMYSQLのバージョンとポートを調べる

```ruby:ターミナル
mysql -u root
```
でローカルのMYSQLに入ります。

```ruby:ターミナル
mysql> これがでたら

mysql> show variables like 'port';  を実行します
```
すると、バージョンとポートの情報が見れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/af00f587-4b9b-1714-9349-6efc85c20bbf.png)
私のRailsアプリ（ローカル）のMYSQLは、version:5.6.46、ポートは3306番でした。


##docker-compose.yml作成　Qiitaで参考になった記事

Docker ドキュメント日本語化プロジェクトhttp://docs.docker.jp/compose/toc.html#
YAMLとは何か？ - いつもRailsの設定ファイルで出てくるやつの正体https://qiita.com/Yama-to/items/587544993fb62610528a
MySQLのバージョン確認方法https://qiita.com/haxpig/items/b270acb9550efddd5fe5
今さら聞けない！OSとは何か？https://www.sejuku.net/blog/6084
bash 入門https://rat.cis.k.hosei.ac.jp/article/linux/bash_intro.html
【初心者向け】Linuxカーネルって一体なんだ？https://qiita.com/uguis410/items/17ec1e447e9716bfdca7
docker-compose upしたときに「A server is already running.」って言われないようにするhttps://qiita.com/paranishian/items/862ce4de104992df48e1
Bundle installからRails serverを起動するまでhttps://wonderful-tereshkova-38f91d.netlify.com/Bundle%20installからRails%20serverを起動するまで/
rails sとは　localhostとはhttps://qiita.com/MIRAI1221/items/29f764db4f50bb44e3f4
MacでMySQL使用準備あれこれhttps://qiita.com/E-11/items/a230f6564614eeddef8c
docker-compose up したコンテナを起動させ続ける方法https://qiita.com/sekitaka_1214/items/2af73d5dc56c6af8a167


#5.database.yml を編集する

Railsアプリには config/database.yml が既に存在しています。
このファイルを編集します。

・MYSQLにパスワードを設定します。
　　password: password  （←これ） #docker-compose.ymlのMYSQL_ROOT_PASSWORD
・データベースが動作しているホスト名を設定します。
　　host: db  （←これ ）#docker-compose.ymlのservice名の db

docker-compose.ymlはこんな感じです。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/41100bf9-c9a9-d554-fd68-24477b0bfc61.png)

このように記述します。

```ruby:config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  nickname: root
  password: password　　#（←ここ、passwordを追記します）
  socket: /tmp/mysql.sock
  host: db             #（←ここ、host:dbを追記します）
```
こんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/94decfca-a23f-5c9d-e983-368d80187a7c.png)


これで準備は完了しました！....のはずでした。

##エラー発生です！

無事にDockerコンテナイメージを構築できるか、祈りながらコマンド実行！

```ruby:ターミナル
docker-compose build
```

はい、Dockerさん、なんか怒ってます。

```ruby:エラー文
You must use Bundler 2 or greater with this lockfile.
(このロックファイルでは、Bundler 2以上を使用する必要があります。)
ERROR: Service ‘web’ failed to build: The command ‘/bin/sh -c bundle install’ returned a non-zero code: 20
```

振り返ると、コンテナくじらさんはこう言ってたようです。
Dockerfile３６行でバンドラーのバージョン指定がなかったから、最新の２系をインストールしたよ！
Dockerfile３7行でバンドルインストールしろって言うから実行したけど無理でしたよ。

##バンドラー問題を解決した方法
お世話になった記事です（ありがとうございました！）

**Railsの既存AppをDockerに切り替える際に役立つ記事**
https://qiita.com/mylevel/items/ff86875df64e3d002fc9

**・エラー解決でやったこと**
　**1. Dockerfileに RUN gem install bundler -v 1.3.0　と１系のバージョン指定した**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/ed2c26e3-10a5-9028-e377-9e9868527358.png)

　**2. ローカルのGemfile.lockを command+A+✖️で全削除した**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/0c741252-dad0-1fcc-5e63-d4b5b6ff15f3.png)

　**3. docker-compose build コマンドを実行**

 ```ruby:ターミナル
docker-compose build
```
これでエラーを解決できました。



#6.build コマンドで imageを構築する

buildコマンドを実行します。
buildコマンドは指定したDockerfileを読み込み、１行１行命令を実行しながらイメージを構築します。

 ```ruby:ターミナル
docker-compose build
```

ターミナルはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/2e7e6d7f-7676-b217-4416-7a5eba9a7974.png)
無事、最後のSTEPまで成功しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/9ffda022-d371-911d-0343-c5d5e47676fd.png)



#7.DockerコンテナのMYSQLにDB(db:create)を作成し、テーブル作成（db:migration）する

DockerコンテナのMYSQLにRailsアプリのDB作を作成します。

 ```ruby:ターミナル
docker-compose run web bundle exec rake db:create
 ```

##エラー発生です！

また怒られました。今度は、くじらデーモン閣下。

 ```ruby:ターミナル
user@keisukeagamiAir nomadcafe % docker-compose run web bundle exec rake db:create
Starting nomadcafe_db_1 ... done
Error response from daemon: Mounts denied: 
The path /Applications/nomadcafe
is not shared from OS X and is not known to Docker.
You can configure shared paths from Docker -> Preferences... -> File Sharing.
See https://docs.docker.com/docker-for-mac/osxfs/#namespaces for more info.

google様の通訳：
デーモンからのエラー応答：マウントが拒否されました：
パス/ Applications / nomadcafe
OS Xからは共有されず、Dockerには認識されません。
Docker-> Preferences ...-> File Sharingから共有パスを設定できます。
詳細については、https：//docs.docker.com/docker-for-mac/osxfs/#namespacesを参照してください。
 ```


##デーモンからマウントを拒否される問題を解決した方法
お世話になった記事です（ありがとうございました！）

**Docker for Macでコンテナとのボリュームマウントに苦労した話**
https://qiita.com/harukisan/items/31f15780760ab2f3d213


**・エラー解決でやったこと**
 **1.Docker for macアプリ > Resources > FILESHARINDに移動**
 **2.一番下の＋ボタンを押して、ローカルのRailsアプリファイルを指定**
 **3.Apply&Restartをおしてリロードを完了** 

Docker for macを開きます。
（デスクトップ上端メニューバーのwifiやbluetoothあたりにある、くじらアイコンを触ってpreferences...を選択します）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/406602cd-b499-6443-c3ad-784283f4eff6.png)
作業しているRailsアプリのファイルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/da7198f1-858c-e3cb-4c2f-9a0c8ca45719.png)
選択したらリロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/7fa69bed-46f8-98d3-5bd4-add98644b543.png)
Apply&Restartボタンを押して、リロードしました。

あらためて、DockerコンテナのMYSQLにRailsアプリのDB作を作成します。


 ```ruby:ターミナル
docker-compose run web bundle exec rake db:create
 ```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/54795a28-9aa1-2027-77f6-4c38a4bf3255.png)
できました！


続いて、マイグレーションしてテーブルを作ります。

 **Dockerコンテナはlocalとは環境が異なりますので、DB作成とマイグレーションが必要です。**

** Dockerコンテナでのrailsコマンドは通常のコマンドの前に 「docker-compose run web」をつけて実行します。**



```ruby:ターミナル
docker-compose run web bundle exec rake db:migrate
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/8fb51a17-7e34-8caa-1c0e-cccdbf83140a.png)
無事、マイグレーションできました。


#8.コンテナを起動する docker-compose up (or start)


 image構築、コンテナ構築、コンテナ起動をやってくれるコマンドを実行してみます。

```ruby:ターミナル
docker-compose up
```
すると、ターミナルはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/c77d726d-a9b2-c8c6-c178-a4dc00958232.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/9f5d3c7d-3325-1de1-038a-1f4082d46a4f.png)
最後に、Rails sのときと同じ見覚えのある単語が出てきました！



localhost:300にアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617331/1a6232ae-0825-b638-a6d8-10fc29536822.png)

無事、アプリが起動しました！


#9.最後に
当方、
実務未経験＋初学者＋テッ○キャンプ卒業＋転職活動中であります。
まだまだ、素人同然なので、間違いがございましたらご教示いただけるとありがたいです。

たくさんのQiita記事でコードを見合わせたり、エラー解決記事が投稿されてたり、そのおかげでここまで実装できました。
記事を投稿してくださった先輩方に感謝しております。

この先も本番環境でのdocker実装に向けて進みつつ、わかりやすい記事を寄稿していきたいと考えています

##ローカル・Dockerで開発環境を整えるまでの続編
**[②Dockerを初めて導入してRails sする (2020.4時点)](https://qiita.com/SakagamiKeisuke/items/d64ee54c22378223659a)**
**[③Docker MYSQLにデモデータ(seed_fu)を投入する!(2020.4時点)](https://qiita.com/SakagamiKeisuke/items/4ce1c4a4921abb57b896)**
**[④ローカルDocker環境でデータ永続化、entrypointでseed_fuをやり直しする(2020.4.時点)](https://qiita.com/SakagamiKeisuke/items/8d3fc70a2939cd4bbe3e)**
**[⑤AWS仮想サーバを利用する、AWSアカウント作成 + EC2インスタンス作成(2020.4時点)](https://qiita.com/SakagamiKeisuke/items/9568754f318edd53e39d)**
こちらも続けて見ていただけると流れがわかると思います。