DockerでReactの開発環境を作る

初投稿です。




# Dockerとは
[日本語のドキュメント](http://docs.docker.jp/index.html)によると
> Docker とは、開発者やシステム管理者が、アプリケーションの開発、移動、実行するためのプラットフォームです。

「チーム内で同じ開発環境で開発する事を助けるアプリケーション」って感じです。

# 用語

## コンテナ
アプリケーションの実行を行う開発環境のこと。イメージの情報を元に構築される。
## イメージ
コンテナの元となる。コンテナ内の情報が保存されている。
## Dockerfile
イメージの内容を記述するファイル。イメージをの元となる。ビルドを行うと、Dockerfileに記述した情報を元にイメージが作成される。

## まとめると
1. Dockerfileを記述
2. ビルドを実行しイメージを作成
3. イメージをもとにコンテナを実行
4. コンテナ内でアプリケーションを実行

こんな感じになると思います。

# 実際に書いてみる

## Dockerのインストール
テキトーにやってください！😊😊😊

## Dockerで実行するアプリの構築
初めに、コンテナ内で実行したアプリをローカルで作成します。

```terminal:terminal
$ npx create-react-app docker-practice
$ cd docker-react-example
$ yarn start
```
こんな画面が出たらOK
<img width="1680" alt="docker-react.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352602/f3dafb63-36d9-2857-c9b8-e5273011d2c2.png">

## Dockerfileを書く
コンテナの内容を書いていきます。

```terminal:terminal
$ touch Dockerfile
```

```dockerfile:Dockerfile
# ベースイメージの作成
FROM node:12.16.1
# コンテナ内で作業するディレクトリを指定
WORKDIR /usr/src/app
# package.jsonとyarn.lockを/usr/src/appにコピー
COPY ["package.json", "yarn.lock", "./"]
# パッケージをインストール
RUN yarn install
# ファイルを全部作業用ディレクトリにコピー
COPY . .
# コンテナを起動する際に実行されるコマンド
ENTRYPOINT [ "yarn", "start" ]
```
## 各種コマンド解説
### FROM
Dockerfileには必須のコマンド。
ベースとなるイメージを[Docker Hub](https://hub.docker.com/)から取って来る。
今回はnodeの12.16.1を取って来ている。
### WORKDIR
コンテナ内の作業用ディレクトリを指定する。rootとusr内には色々とデフォルトでファイルがあるから、そこは避けたほうがいいみたい。
### COPY
ローカルにあるファイルをコンテナ内にコピーする
構文は
1. COPY <ソース>... <送信先>
2. COPY ["<ソース>",... "<送信先>"]
のどちらか

### RUN
ビルド時にだけ実行されるコマンド(?)。
初回だけで実行したいコマンドを書くと👍

### ENTRYPOINT
コンテナの起動時に実行される。
似たようなコマンドにCMDというのがあるが、ここで説明すると万里の長城長くなるので割愛

## なんでpackage.jsonとyarn.lockを先にコピーしてんの？
[この記事](https://scrapbox.io/keroxp/docker_build%E3%82%92%E9%80%9F%E3%81%8F%E3%81%99%E3%82%8B%E3%82%B3%E3%83%84)によると、
> dockerはビルド開始時にdocker daemonにDockerfileのディレクトリにあるファイルを全部`tar`して送る。
 これが大きいとtarするのに時間がかかる

みたいなんで、コンテナ内にパッケージの一覧とバージョンの依存関係が書かれたファイルだけコピーして、その後コンテナ内でインストールした方が早いみたいですね！！！

## イメージをビルド
コマンドの構文はこんな感じ
→ docker build [オプション] パス

```terminal:terminal
$ docker build -t test:1.0 ./
```
-tは名前とタグを指定できる(tagはバージョンみたいなやつ)
指定しなければ名前:latestになる(多分)

また、作成したイメージは

```terminal:terminal
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                1.0                 335dbb73b720        40 seconds ago      1.22GB
node                12.16.1             d834cbcf2402        5 weeks ago         916MB
```
で見ることができる。

## コンテナを起動
作成したイメージを元にコンテナを起動するで！
コマンドの構文
→ docker run [オプション] イメージ [コマンド] [引数...]

```terminal:terminal
$ docker run -it --name sample -p 3000:3000 -v $PWD:/usr/src/app test:1.0
```

```terminal:terminal
Compiled successfully!

You can now view docker-react-example in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://172.17.0.2:3000

Note that the development build is not optimized.
To create a production build, use yarn build.
```
こんな画面が出て
http://localhost:3000 にアクセスして
<img width="1680" alt="docker-react.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352602/f3dafb63-36d9-2857-c9b8-e5273011d2c2.png">
こんな画面が出たら成功です。

ファイルを編集すると、

```jsx:src/App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Dockerの勉強やでーｗｗｗｗ
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn Ruby on Rails
        </a>
      </header>
    </div>
  );
}

export default App;
```
リアルタイムで変更を反映してくれるはずです。
<img width="1680" alt="スクリーンショット 2020-04-01 16.32.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352602/181e7f42-2c58-94ba-2b9b-35ffffa18e19.png">

## 各オプション解説

### -it
-iと-tっていうオプションを一気に指定している。
-tは疑似ターミナルの割当
-iはアタッチしていなくても STDIN をオープンにし続けているらしい。

### -p
コンテナのポートとホストのポートの関連付けを行う
ホスト:コンテナの順番で指定するので、今回の場合はホストの3000がコンテナの3000と接続されている。

### -v
ホストのファイルのパス:コンテナのファイルのパスで指定する
volumeの略。ホスト内のファイルをコンテナ内のディレクトリにマウントして、
ホスト上で行ったファイルの変更をあたかもコンテナ上で行ったかのように見せることができる。
これによってファイルの差分を自動が実現されている。

### --name
コンテナの名前を指定
今回はsampleと指定している。
### --rm(おまけ)
--rmをつけるとコンテナを停止した時に自動で削除してくれる。
これでホストがコンテナだらけになることを防ぐことができる。

## 起動中のコンテナに入る
docker execで起動中のコンテナに入ることができる。

構文は

```terminal:terminal
docker exec [オプション] コンテナ コマンド [引数...]
```

```terminal:terminal
$ docker exec -it sample bash
root@fe248383642c:/usr/src/app# 
root@fe248383642c:/usr/src/app# ls
Dockerfile  docker-command.md  docker-compose.md  dockerfile.md  node_modules  package.json  public  src  yarn.lock
root@fe248383642c:/usr/src/app# 
# exitで抜けることが出来ます。
root@fe248383642c:/usr/src/app# exit
exit
$
```
こんな感じでファイルをｲｼﾞｲｼﾞすることができます。

## 起動しているコンテナを一覧で表示
docker ps で出来ます。
-aオプションを付けると停止中のコンテナも出てきます。

```terminal:terminal
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
fe248383642c        test:1.0            "yarn start"        24 hours ago        Up 13 minutes

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                    PORTS                    NAMES
fe248383642c        test:1.0            "yarn start"           24 hours ago        Up 4 minutes              0.0.0.0:3000->3000/tcp   sample
bac4be724af7        docker-ruby_ruby    "irb"                  39 hours ago        Exited (1) 18 hours ago                            ruby
c2346fe966a2        test                "yarn start example"   2 days ago          Exited (1) 24 
(中略)
```



## コンテナの停止

docker stop コンテナ名　で出来ます。

```terminal:terminal
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
fe248383642c        test:1.0            "yarn start"        24 hours ago        Up 13 minutes       0.0.0.0:3000->3000/tcp   sample
$ docker stop sample
sample
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
$ 
```

## コンテナの再起動
docker restart コンテナ名　で出来ます。

```terminal:terminal
$ docker restart sample
sample
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
fe248383642c        test:1.0            "yarn start"        24 hours ago        Up 7 seconds        0.0.0.0:3000->3000/tcp   sample
```

## 終わりに
大体よく使うコマンドとかについて触れられたかなと思います。
Dockerの内部構造はあまり理解できてないので、別の記事でアウトプットしたいなーって感じです。