Dockerをざっくり学ぶ

#はじめに
独学でRailsを勉強してた頃にDockerを知ったけど、別に環境既にPCに構築したし、何が良いのかよくわからん。使い方もよくわからん状態だったのですが、入社してから使う必要になって下記のUdemyの動画で勉強したので、そのアウトプットをしたいと思います。

[ゼロからはじめる Dockerによるアプリケーション実行環境構築](https://www.udemy.com/course/docker-k/)

ざっくりDockerとは何か、使い方を説明したいと思います。ざっくりと。
#Dockerのメリット
そもそもここが分からないと学ぶ意味がないですね。

### 環境構築が簡単
Railsの環境構築やった方ならわかると思いますが、homebrew(Macの場合)で色々入れたり、なんかRubyのバージョンを選んだり色々しましたよね。

あとで説明しますが、Dockerを使っていれば`docker-compose up`というコマンドだけで全て終わります。一瞬です。（Dockerをインストールする必要はありますが。）

PostgreSQL使ってみたいよっていう場合もローカルにPostgreSQL入れて、バージョン決めて、path通してetc...などやるの面倒ですよね。`docker-compose up`で終わりです。

Railsに限らず色々なライブラリやフレームワークで、こんな感じで環境構築できます。
個人的にはこれが最大のメリットです。

### 無駄なソフトをインストールせずにすむ
何かお試しでやろうと思ったら色々なソフトをインストールする必要があって、PCのストレージを使ってしまいますよね。さらに複数バージョン（Ruby 2.6, 2.7とか）を入れる場合にはさらにストレージを使います。

しかも何を入れたか忘れてしまった場合にはもうそれは一生消されず、ただPCの容量を食うだけのものになっちゃいます。

でもDockerを使っていれば使った環境は使い捨てにできるのでPCの容量を無駄に使うことはありません。（Docker自体はインストールする必要あるのでその分の容量は必要ですが）

### 環境を共有できる
ローカルで環境構築した場合Windows OSやMac OS上に色々構築していく訳ですが、本番デプロイする場合、本番環境を構築する仮想マシンがLinuxだと、そもそものOSの違いによってローカルで動いていたものが動かなくなることがあります。

また、同じRailsアプリを作るメンバーが違うOSやバージョンを使ってると人によっては動いたり動かなくなってしまうことがあります。

Dockerを使うことで同じ環境を使いまわせるので、ローカルで動いていれば本番でも動きますし、他の人とも同じ環境を簡単に共有することができます。（正確に言うと全く同じ環境という訳ではないですが、ここではとりあえず同じ環境ということにしておきます）

#イメージとコンテナの違い
動画を見る前に初めてDockerを勉強した時にここで結構つまづいてたんですが、簡単に言うとイメージはテンプレートで、コンテナは実際の実行環境です。

例えば、Excelで履歴書を書くとして、ネット上にあるExcelで作られたテンプレートをダウンロードするとします。このテンプレートがイメージです。
誰かがExcelを使って作ったテンプレートですね。

そして、そのテンプレートをダウンロードしてローカルで色々な情報を記入していきます。このローカルにダウンロードして、色々いじってるそのファイルがコンテナです。
コンテナをいくらいじってもイメージは変わりませんよね。何故ならネット上にあるテンプレートなので、ローカルでいくらいじってもローカルのファイルが変わるだけです。

もちろんテンプレート自体（イメージ）を作ってネット上にアップロードすることもできます。

#Dockerfileとdocker-composeの違い
Dockerfileはテンプレートを作る定義書です。
ネット上にある履歴書のテンプレートをダウンロードしたものの、ちょっと自分用にカスタマイズしたい時もありますよね。

1枚しか書かないなら別にどんどん勝手に書き足していけばいいんですが、履歴書を複数枚書かなければいけないから自分用のテンプレートを作ってから、それを複製して別の履歴書を書きますよね。

このおれおれテンプレートを作るのがDockerfileです。

参考に[Dockerのドキュメント](https://docs.docker.com/compose/rails/)から拝借して少し修正したDockerfileのサンプルが下記のコードです。

```Dockerfile
#rubyのv2.5のイメージを使う
FROM ruby:2.5
#ruby:2.5には入っていないライブラリを追加する
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
# myappというディレクトリの作成
RUN mkdir /myapp
# myappというディレクトリに移動（cd myapp）
WORKDIR /myapp
# ローカルのGemfileをmyappにコピー
COPY Gemfile /myapp/Gemfile
# ローカルのGemfile.lockをmyappにコピー
COPY Gemfile.lock /myapp/Gemfile.lock
# gemのインストール
RUN bundle install
# ローカルファイルをmyappにコピー
COPY . /myapp

# その他処理を続けて書いていく。
```

元々のイメージはrubyのversion2.5という環境でしかなかったのですが、色々つけ足すことでRailsの環境が作れます。

一方docker-composeはコンテナを作るときに使われます。
イメージ（テンプレート）からコンテナ（実行環境）を作るのに下記コマンドを使用します。
`docker run [Image名]`
さらに色々オプションをつけると以下のようなコマンドになります。（コマンドは[Dockerのドキュメント](https://docs.docker.com/engine/reference/commandline/run/)から拝借）
`docker run -e MYVAR1 --env MYVAR2=foo --env-file ./env.list ubuntu bash`

これを毎回入力するのは面倒なので、docker-composeを使います。
このオプションをdocker-compose.ymlに書いておくと、`docker-compose up`だけでそのオプションを反映したコンテナを作成してくれます。

さらにdocker-composeでは、複数のコンテナを同時に立てることができます。
docker runだと一つずつしかコンテナ立てることができないですが、docker-composeに書いておけば幾つでもコンテナを同時に立てることができます。

また、コンテナ同士を勝手に接続してくれます。

例えばrailsのコンテナとpostgreSQLのコンテナを接続しておかないとrailsのコンテナがpostgreSQLのコンテナを認識できずいつまでたっても接続できません。

またまた[dockerのドキュメント](https://docs.docker.com/compose/rails/)からサンプルのdocker-compose.ymlを拝借します。

```yml:docker-compose.yml

version: "3.9" #使用するdocker-composeのバージョン
services: #アプリの構成要素を定義、つまりコンテナ
  db: #サービス名（ログとかに出てくる名前）
    image: postgres #使用するイメージ（タグも付けられるpostgres:latestとか）
    volumes: #データを永続化するためのローカルの保存場所の指定（これを指定しないとコンテナ消すとデータも消える）
      - ./tmp/db:/var/lib/postgresql/data
    environment: #環境変数
      POSTGRES_PASSWORD: password
  web:
    build: . #自分で定義したDockerfileを使用する場合にそのDockerfileの保存場所を指定
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" #コンテナ起動時のコマンドを指定
    volumes:
      - .:/myapp
    ports: #ポート番号を指定
      - "3000:3000"
    depends_on: #dbサービスが起動してからこのサービスを起動するようにする。
      - db

```
このdocker-composeではネットワークの設定を書いていませんが、勝手に`ディレクトリ名_default`というネットワークを構築して各サービスを繋げてくれます。

このおかげでdbサービスからwebサービスにデータを送ったりすることができるようになるわけです。

こんな感じでdocker-compose使うと簡単に複数コンテナ立てれるんだなぁくらいの理解で大丈夫かと思います。


#まとめ
最初にRailsだけ勉強するみたいな状況だとそもそもの有用性とかあまりないんですが、他の言語だったりライブラリを使うとなった時にさっと環境構築できるので早めに覚えておいて損はないかなぁと思います。

あと、Dockerfile自体が環境構築の定義書みたいになってるので、本番環境をDocker使わないで構築するとしてもDockerfile通りに構築していけば基本的に本番環境できるので、本番環境の作り方を学ぶ意味でもDocker学ぶのは良いことですね。