雑に知ってしまったDockerを知り直す ~アプリケーション持ち込み編~

## おさらい
第2回です。
前回の投稿は[こちら](https://qiita.com/wol/items/487a9d12aa8ec3001efc)
前回はnginxのイメージをpullして来てコンテナ起動。
ポートフォワードしてウェルカムページを表示させるまでやりました。

## 今回やりたいこと
1. ローカルで適当にアプリケーションを用意する
2. どうにかしてそのアプリケーションをコンテナの中にぶちこむ
3. ホスト側から起動したアプリケーションへアクセスできるようにする

## アプリケーションを用意
Nodeとgithubを勉強したときに作った、first-stepっていうオシャレ気取った名前のリポジトリが放置されていたので、これを再利用します。
せっかくなので触ったこと無いReactへ転生。

この辺のステップは本題と外れてしまうので割愛。
```$ npm start```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278872/eb174b10-6111-fd0f-64b1-631f4211c751.png)

これをどうにかしてコンテナへ持っていきたい。

## コンテナを用意
前回はnginxのイメージを利用しましたが、今回はnodeのイメージを利用します。
現在のnodeの最新バージョンは`v13.8.0`なんですが、ホストにインストールしてるのは安定版の`v12.16.0`なのでこれをインストールしたい。

バージョン指定してイメージをpullするのどうやるんだろう・・と思いつつとりあえずイメージを探します。
コマンドでも探せるみたいなんですが、初めてなのでGUIに頼ります。

https://hub.docker.com/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278872/785e12af-b5b6-0160-0920-02af5b6ea856.png)

nodeのページを見つけた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278872/d38122f6-f5e8-cbfa-9f1a-1cca8643b4fe.png)

下の方にズラーっとなんか並んでる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278872/66ece89f-4dd2-cc7e-fc85-1c91107d4e5c.png)

試しに検索窓にバージョン情報入れてみた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278872/8be98227-14e3-3698-bc45-965252bdcede.png)

なるほどなるほど、なんかそれっぽいですね。

調べてみるとこれはTagと呼ばれるもので、古いのバージョンのイメージが欲しい場合はこのTagを指定してpullする必要があると。ただ、同じバージョン(v12.16.0)でもstretchとかslimとか更に違いがあるのが気になる。。
で更に調べると、例えばnodeの場合だとバージョンは同じでも無駄なファイルを省いて最適化されたslimバージョンがあったり、Debianのバージョンが異なるもの(stretchとかbusterとかはDebianのコードネーム)があったりと結構細かい違いがあるということが判明。
このあたりもちゃんと意識して適切なイメージを選択する必要があるってことか・・
で、更に気になったのがTag指定しない場合はどうなるんだ？とかlatest指定すると結局どれを引っ張ってくるのよとか、そもそもこれ誰が作ったイメージなん？安全なん？とか・・
TODO: これも色々調べてみたんですけど、今回の趣旨からは外れそうなのとボリューム膨らみそうなので別記事でまたやります。

今回はとりあえず名前がかっこいいのでbusterでやります。

```
$ docker pull node:12.16.0-buster
12.16.0-buster: Pulling from library/node
dc65f448a2e2: Pull complete
346ffb2b67d7: Pull complete
dea4ecac934f: Pull complete
8ac92ddf84b3: Pull complete
a3ca60abc08a: Pull complete
ab849ba5abe0: Pull complete
b9e0c215e971: Pull complete
766774022603: Pull complete
f199c0426b2a: Pull complete
Digest: sha256:66d5994de29952fe982729ef7c7f8d4c50d528279db386efbf373451f534fa16
Status: Downloaded newer image for node:12.16.0-buster

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
node                12.16.0-buster      ce43ce61c1de        28 hours ago        882MB

$ docker run [イメージ名:TAG]
$ docker run -d --name node-react node:12.16.0-buster
505ba1fdefd2f705f90b083cee3653445256a0917e054147f8251d4e0eeef122

#前回はrunする前にイメージをpullしてなかったのでこのタイミングで色々ダウンロードしてましたが、
今回は事前にpull済なのでローカルのイメージを利用。カシコイ

$ docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS                     PORTS               NAMES
8a126cad2450        node:12.16.0-buster   "docker-entrypoint.s…"   5 seconds ago       Exited (0) 4 seconds ago                       node-react
```
で、ここで作成したコンテナのSTATUSを見るとUp(起動中)ではなく、Exitedになっちゃってる。
前回のnginxの場合サーバを立ち上げてUp状態になっていたけど、今回のイメージはあくまでnodeの実行環境を用意するだけなのでコンテナが立ち上がりっぱなしにはならないのかな、となんとなく推測。
環境を構築して後続の命令が無いと、プロセスが死ぬようになっているらしい。起動するアプリケーションも無いのに立ち上げておく意味ないもんね。
`-itd`ってオプションつけるとコンテナが立ち上がりっぱなしになるらしいのでお試し。

```
$ docker run -itd
-i ホストの入力をコンテナの標準出力につなげる。コンテナ側へ正しくコマンドを渡せるようにする。
-t コンテナの標準出力をホストの標準出力につなげる。ttyをコンテナに割り当てて、対話できるようにする。
-d コンテナに入らずバックグランドで起動する

$ docker run -itd --name node-react node:12.16.0-buster
10235f0996b7c1b1e5f47c5b1c36651ff4fe20cd72b14f47dc5a11f0e8607780

$ docker ps -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES
10235f0996b7        node:12.16.0-buster   "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds                            node-react
```
うんうん、STATUSがUpになってる。
**コンテナに入って作業したい場合は、とりあえず-itd**って覚えても良いかもしれない。
TODO: 1個づつオプション外して試してみたけど、ここの挙動が上手く理解できていないので別の機会にちゃんと調べる。

```
# コンテナの中に入る
$ docker exec -it node-react /bin/bash
root@8bf7a6704bb9:/# node -v
v12.16.0
```
ちゃんと指定したバージョンで入ってますね

## コンテナにアプリケーションをぶちこむ
最初は「ファイル転送でもすれば良いんかなぁ」とかかなり脳筋なこと考えていたんですけど、考えてみたらgithubからcloneしてきて起動すれば良いんじゃね？と思ったのでお試し。

```
root@8bf7a6704bb9:/# git --version
git version 2.20.1
```
**git入ってる！勝った**

```
# 適当なディレクトリへ移動して
root@8bf7a6704bb9:/# cd /usr/src/

# cloneして
root@8bf7a6704bb9:/usr/src# git clone https://github.com/wol-827/first-step.git
Cloning into 'first-step'...
remote: Enumerating objects: 22, done.
remote: Total 22 (delta 0), reused 0 (delta 0), pack-reused 22
Unpacking objects: 100% (22/22), done.

root@8bf7a6704bb9:/usr/src# cd first-step/

# アプリ起動に必要なモジュールインストールして
root@8bf7a6704bb9:/usr/src/first-step# npm i
found 0 vulnerabilities

# アプリケーション起動
root@8bf7a6704bb9:/usr/src/first-step# npm start
Compiled successfully!

You can now view sample-app 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 npm run build.
```
起動できてそう！良い感じ

コンテナ起動時にポートフォワード設定し忘れてしまったので、改めて設定。
アプリケーションは3000番で起動していて、8080へ飛ばしたいのでこんな感じ。

```
$ docker run -itd -p 8080:3000  --name node-react node:12.16.0-buster
```

- 起動前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278872/b2380357-4032-2eb9-014a-2af23d3e0e33.png)

- 起動後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278872/08a9f345-0605-98eb-f1a7-dac8956863b1.png)

できた。ウレシイ。

## まとめ
Dockerについて調べていると、環境を汚すことなくアプリケーションの実行環境を用意できる、なんでことが書かれているのをよく見るんですが身を持ってそれを実感しました。
ホスト側にDockerイメージだけ用意してあれば、nodeやらReact用のモジュールやらはコンテナの中にだけ入れるのでホスト側はキレイな体を保てると。専用のコンテナを立てるのでnodeのバージョンの切り替えも不要。
イメージはこれで、githubのリポジトリはこれ、コマンド実行手順はこれ、っていう風に準備すれば、とりあえず環境は手に入る。便利便利。

とはいえ今回の場合、コンテナの中に入ってcloneしたり色々コマンド実行しているのが冗長。
次はこの辺りをコマンド1発で出来るようにしたいと思います。たぶん出来る。出来ろ。