Dockerに入門してしまったのでインストールからReactの開発環境を作るまでを復習する



数日前からDockerを学び始めたので、この記事を読むことで

- **「Dockerとは何か」がなんとなくわかる**
- **Dockerの主要なコマンドとオプションが使えるようになる**
- **事前知識なしでReact(それ以外でも)の開発環境をDocker上に構築できる**

ことを目標に復習したいと思います💪

## Dockerとは何か
<img width="809" alt="スクリーンショット 2019-03-19 12.41.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/258226/1aabd8ea-3348-14cd-5843-bc59bac214f8.png">

Dockerは、従来より効率的な仮想化を実現してくれる技術です。
従来の仮想化技術では**アプリケーションごとにホストOSやアプリケーションと関係ないデータが用意され、ホストOS上のVM上のゲストOS上で動作する**...と言った仕組みでしたが、Dockerは**共有できるデータは共有し、ホストOSのカーネルを直接利用する**ことで、軽量・高速な仮想化を実現しています。
また、環境をコンテナに閉じ込めるので**実行環境の違いによる問題が起きづらい**ことや、**環境を簡単に共有できる**ことも利点です。

## Dockerをインストールしよう
###　環境
MacOS 10.14.3 Mojave
### サインアップ
DockerのインストールにはDockerのアカウントが必要なのでサインアップします。
<img width="1552" alt="スクリーンショット 2019-03-21 20.55.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/258226/c748e99a-4de7-5ba3-4df8-8eca522639e0.png">
<img width="1552" alt="スクリーンショット 2019-03-21 20.58.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/258226/04f195ed-584a-9c89-66bb-b9388c5a1b0f.png">

### インストール
以下のリンクからダウンロードしてインストールします。
https://www.docker.com/get-started

## Dockerの全体像
Dockerが動くに至るまでの登場人物を示します。
![Untitled Diagram (1) (1)-2.png](https://qiita-image-store.s3.amazonaws.com/0/258226/e8fcac10-af60-8568-b3e8-87e6d99a3f64.png)


1. **Dockerfile**を**ビルドして生成**するか、**DockerHub**から**pull**して、**イメージ**を手に入れる
1. 手に入れた**イメージ**から、**コンテナ**を作成する
1. **作成したコンテナを起動**することで、アプリケーションとして使えるようになる

各手順について説明します。

### 1.**Dockerfile**を**ビルドして生成**するか、**DockerHub**から**pull**して、**イメージ**を手に入れる
#### Dockerfileとは？
Dockerfileは、イメージを作成するための命令を記述したファイルのことです。
イメージとは、実際に動作するコンテナの構成を定義するファイルのことです。
イメージによって定義された構成情報によってコンテナを作成することで、実際に動作する環境が出来上がります。

Dockerfileの命令には以下のようなものあります。

| 命令       | 意味                                                                     | 使用例                    |
| :--------- | ------------------------------------------------------------------------ | ------------------------- |
| FROM       | イメージのベースとなるイメージを指定                                     | FROM alpine               |
| RUN        | 現在のイメージに対してコマンドを実行し、結果を現在のイメージに上書きする | RUN apk add nodejs        |
| WORKDIR    | コンテナ内の作業ディレクトリを定義する                                   | WORKDIR /usr/root         |
| ARG        | ビルド時に--build-arg 変数名=値　で使用できる変数を定義する              | ARG user                  |
| ENV        | Dockerfile内の命令で使用できる環境変数を定義する                         | ENV workDirName=root      |
| EXPOSE     | コンテナが外部に公開するポートを設定する                                 | EXPOSE 80/tcp             |
| ADD        | イメージにファイルを追加する(リモート可・圧縮ファイルは自動解凍)         | ADD example.gz /expfiles  |
| COPY       | イメージにファイルを追加する(リモート不可・圧縮ファイルは解凍されない)   | COPY example.gz /expfiles |
| VOLUME     | コンテナ作成時に指定した名前で外部にボリュームを作成する                 | VOLUME mybol              |
| ENTRYPOINT | コンテナが実行するプログラムを設定する                                   | ENTRYPOINT bash           |
| CMD        | ENTRYPOINTへのデフォルトの引数またはデフォルトで実行するコマンド         | CMD npm start                |

これらを踏まえて、Dockerfileの例を示します。

```Dockerfile:Dockerfile
# alpine(軽量なLinux)をベースイメージとして
FROM alpine

# 作業ディレクトリの名前をreact-appとして
ENV wkdir react-app

# /usr/root/react-app を作業ディレクトリとして
WORKDIR /usr/app/$wkdir

# ディレクトリ"reactAppOnDocker"をボリュームとして
VOLUME reactAppOnDocker

# apk(alpineでのパッケージマネージャー)でnodejsとかインストールして
RUN apk add nodejs
RUN apk add npm
RUN npm i -g create-react-app

# shを実行する
ENTRYPOINT sh
```
こんな感じでDockerfileを記述したら、引数にDockerfileが存在するディレクトリのパスを渡し`docker build`コマンドで**イメージを作成**します。

```
docker build -t react-env .
```
オプションには以下のようなものがあります。

| オプション | 意味                                              | 使用例          |
| ---------- | ------------------------------------------------- | --------------- |
| -t         | タグ名(イメージの名前)を付ける                    | react-env       |
| -f         | Dockerfileの名前 (デフォルトは 'PATH/Dockerfile') | -f Dockerfile.dev |

これでDockerfileによるイメージの作成は完了です。


#### docker pullとは？
Dockerのレジストリサーバからイメージをダウンロードすること。
git pullみたいなものです。
デフォルトでは公式のレジストリサーバであるDocker Hubからイメージを取得します。
`docker pull myregistry.local:5000/testing/test-image`のように記述することでローカルのレジストリサーバから取得することも可能です。

```
# Docker Hubからnginxのイメージをダウンロード
docker pull nginx
```

### 2. 手に入れた**イメージ**から、**コンテナ**を作成して起動する
イメージからコンテナを作成して起動するには、`run`コマンドを使用します。
`docker run イメージ名`
もしくは
`docker run イメージID`
の書式で、イメージからコンテナを起動することができます。

```
docker run react-env
```

`run`コマンドは、`create`コマンドと`start`コマンドをまとめたものです。
`run`コマンドのオプションには以下のようなものがあります。

| オプション | 意味                                                   | 使用例                                                  |
| ---------- | ------------------------------------------------------ | ------------------------------------------------------- |
| -i         | コンテナの標準入力にアタッチする                       | docker run -i react-env                                 |
| -t         | 疑似ターミナルを割り当てる(ターミナルの出力を得る)     | docker run -t react-env                                 |
| -d         | バックグラウンドで実行する                             | docker run -d react-env                                 |
| --name     | コンテナに名前を付ける                                 | docker run --name myFirstReactApp react-env             |
| -p         | コンテナのポートを公開・ホストのポートにバインドする   | docker run -p 3001:3000(ホスト:コンテナ) react-env      |
| -v         | ホストのディレクトリをコンテナにマウントする(共有する) | docker run -v myFirstReactApp:/root/react-app react-env |
| -rm        | コンテナ終了時に自動的に削除                           | docker run -rm react-env                                |
例として、`centos`イメージから

- 標準入出力を得て
- myCentOSという名前で
- ホストの5000番ポートをコンテナの3000番ポートにバインドして
- ディレクトリ"myCentOS"をコンテナの"/root/work"にマウントする

という条件でコンテナを作成・起動する場合、runコマンドは次のようになります。

```
docker run -it --name myCentOS -p 5000:3000 -v myCentOS:/root/work centos
```

#### 起動中のコンテナでコマンドを実行する
`docker exec オプション　コンテナ名もしくはコンテナID　実行するコマンド`の書式で`exec`コマンドを実行することで、実行中のコンテナでコマンドを実行することができます。

```
docker exec myCentOS sh
```
`exec`コマンドのオプションには以下のようなものがあります。

| オプション | 意味                                                   | 使用例                                                  |
| ---------- | ------------------------------------------------------ | ------------------------------------------------------- |
| -i         | コンテナの標準入力にアタッチする                       | docker exec -i myCentOS sh                                 |
| -t         | 疑似ターミナルを割り当てる(ターミナルの出力を得る)     | docker exec -t myCentOS sh                                 |
| -d         | バックグラウンドで実行する                             | docker exec -d myCentOS sh                                 |
標準入出力を得てシェルを実行している時にCtrl+Dでコンテナから抜けることができます。

#### その他のよく使うDockerコマンド
##### コンテナを停止する
```
docker stop コンテナ名もしくはコンテナID
```

##### コンテナを起動する

```
docker start コンテナ名もしくはコンテナID
```

##### コンテナを削除する

```
docker rm コンテナ名もしくはコンテナID
```

##### 実行中のコンテナを確認する

```
docker ps
```

##### 停止中も含めた全コンテナを確認する

```
docker ps -a
```

##### イメージを確認する

```
docker images
```

##### コンテナからイメージを作成する

```
docker commit コンテナ名もしくはコンテナID　イメージ名
```

これによって開発環境をそのままほかの人に渡して使ってもらうことが可能になります。

##### 不要なイメージ、コンテナ、ネットワーク、ボリュームを削除する
```
docker image prune
docker container prune
docker network prune

# 全て削除
docker system prune
```

## Reactの開発環境を作ってみよう
まっさらなLinuxイメージをベースにReactの開発環境を作っていきます。
### Dockerfile
以下のようにDockerfileを書きます。

```Dockerfile:Dockerfile
FROM alpine
ENV wkdir react-app
WORKDIR /usr/app/$wkdir
RUN apk add nodejs
RUN apk add npm
RUN npm i -g create-react-app
ENTRYPOINT sh
```

- alpineがベースイメージで
- 作業ディレクトリは/usr/app/react-appで
- nodejs,npm,create-react-appがインストールされる

なイメージを作成するDockerfileができました。
ビルドしてイメージを作成します。

```
docker build -t react-env .
```

カレントディレクトリのDockerfileを指定して、`react-env`という名前のイメージを作成することができました。

### コンテナ起動
作成したイメージを

- 名前はmy-first-docker-app
- ポートはホスト3000:コンテナ3000
- 標準入力&擬似ターミナルでコンテナ内を操作
- ホストの~/Reactをコンテナの/usr/app/react-appにマウントする

という条件で起動します。

```
docker run -it --name my-first-docker-app -p 3000:3000 -v ~/React:/usr/app/react-app react-env
```

コンテナが起動し、alpineの中に入ることができました。

### Create React App
Dockerfileでnodejsやcreate-react-appをインストールするように記述したので、すぐに使うことができます。
コンテナの作業ディレクトリで次のコマンドを実行してreactアプリケーションを作成します。

```
create-react-app react-on-docker
```

作成したアプリケーションのディレクトリに移動して、`npm start`すると次のように表示されると思います。

```
Compiled successfully!

You can now view my-first-docker-app in the browser.

  Local:            http://localhost:3000/
  On Your Network:  http://xxx.xxx.xxx.xxx:3000/

Note that the development build is not optimized.
To create a production build, use npm run build.
```

コンテナの3000番ポートをホストの3000番ポートにバインドしたので、ブラウザでlocalhost:3000にアクセスするとコンテナ内で実行中のReact開発サーバにアクセスできます。
マウントしたディレクトリは共有されているので、ホスト側でいじって開発することができます。
これでDocker上にReactの開発環境が構築できました。やったね🎉

## 参考URL
https://docs.docker.com/engine/reference/builder/
https://qiita.com/YumaInaura/items/1647e509f83462a37494
https://qiita.com/lciel/items/e21a4ede3bac7fb3ec5a

## おすすめの学習リソース
https://www.udemy.com/docker-and-kubernetes-the-complete-guide/
https://knowledge.sakura.ad.jp/13265/