【入門】公式チュートリアルを見ながらDockerを動かしてみよう

## Dockerって何？

https://docs.docker.com/get-started/overview/

Dockerとは、コンテナ型の仮想環境を構築するOSSのプラットフォーム。イメージ(環境のテンプレート)を元にコンテナ(独立したインスタンス)を作成することで同一のアプリケーションを配布したり、テストを行うことができる。これを軽量かつ高速に行うことができるため、CI/CDを行う上で適している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/91dd2d61-99d4-59f4-d83c-e12357f9cce0.png)


## 導入

https://docs.docker.com/get-docker/

Docker Desktopを入れる。

## 動かしてみよう

初期状態ではローカルにはイメージは含まれていない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/29e14cfe-ccd3-9766-f086-d30e3ea8e399.png)
同様にコンテナもない。(チュートリアルが出てるが一旦無視する)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/d71fbdd9-416f-8996-b9b1-7c6aad58633e.png)

### 公式イメージからコンテナを作る

ターミナルから、以下のコマンドでubuntuイメージを動かしてみる。

```console
docker run -itd ubuntu
```

これでubuntuを実行する。

ローカルには存在しないので、公式からイメージがダウンロードされる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/34b39127-be21-8001-27fa-49457b7cb93c.png)
これを元にコンテナが作られる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/3f623c4b-84cd-f0d3-5ca5-155325686ac9.png)

同様のイメージ一覧、コンテナ一覧の内容がコマンドからも取得できる。
```
docker image ls
```

```
docker ps -a
```
ここで```-a```は実行中以外も見れるようにするためのオプション。

### 補足

基本的には```docker run オプション イメージ名```で実行する。オプションの```-d```はバックグラウンドでの実行の指定、オプションの```-it```は[標準入力、標準出力の指定。](https://utouto97.hatenablog.com/entry/2022/03/15/092924)これを指定しないと、何もプロセスを実行することがないコンテナは勝手に終了してしまう。

今回はubuntuを指定したが、そのほかにも公式で用意されているイメージはいろいろある↓。

https://hub.docker.com/search?q=&type=image&image_filter=official

### ターミナルから動かしてみよう

作成したコンテナを動かしてみよう。
ここからターミナルを実行できる。
![rapture_20220623010625.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/69c67641-88a8-2990-508b-e050aefcd8af.jpeg)

```
ls
```
とか叩いて
```
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
```
とか出ればOK。

以下のコマンドをローカルのターミナルから実行することでコンテナのターミナルを開くこともできる。
```
docker container exec -it <コンテナid> bash
```
(指定したコンテナでbashを実行、```-it```で入出力をつなげている)

同じように、元のターミナルから以下のコマンドを叩いても実行できる。

```
docker exec <コンテナid> ls
```
これでも同じ出力が出る。



### コンテナを終了しよう

コンテナは以下のコマンドで停止、削除することができる。

```
docker stop <コンテナid>
docker rm <コンテナid>
```

## コンテナを作ってみよう

ここまでは公式で用意されているイメージを用いたが、今度はコンテナを作成してみる。Dockerfileというものを作成する。

プロジェクト用のディレクトリを作成し、そこに```Dockerfile```というファイルを作成する。

```:Dockerfile
FROM ubuntu
RUN apt update
WORKDIR /app
COPY . .
```

* ```FROM```で元となるイメージを指定する。今回は```ubuntu```を指定する。
* ```RUN```でコマンドを実行する(```apt update```を動かす)。
* ```WORKDIR```でディレクトリを指定する。
* ```COPY```で現在のローカルマシンからコンテナへファイルを移す。


```test-image```という名前を指定してイメージをビルドする。
```
docker build -t test-image .
```

https://docs.docker.jp/engine/reference/commandline/build.html

これでイメージが作られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/3e8514ca-60e8-3c70-eedf-971148076893.png)

このイメージを元にコンテナを作る。

```
docker run -itd test-image
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/79f33c80-0b3f-972a-d2e7-b1c969bbc059.png)

作成したコンテナのターミナルを開いてみると、
* ```apt update```が実行済で
* ```/app```がカレントディレクトリで
* ディレクトリの中身がコピーされている(```Dockerfile```が入ってる)

ことがわかる。

## getting-startedを動かしてみよう

getting-startedに従ってnode.jsのアプリを動かしてみる。

https://docs.docker.com/get-started/02_our_app/

まずは以下のレポジトリからcloneする。

https://github.com/docker/getting-started/tree/master/app

この中の```/app```下のみを用いる。このディレクトリに以下の```Dockerfile```を作成する。

```dockerfile
FROM node:12-alpine
RUN apk add --no-cache python2 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
```

この中身を確認してみる。
* ```FROM```で公式イメージの```node```を指定する。さらに```12-alpine```というタグを付ける。
    * alpineは軽量化されたLinux環境。これを使うことを推奨されている。```apt```じゃなくて```apk```を使う、といった違いがある。
    * [タグ一覧](https://hub.docker.com/_/node?tab=tags)
* ```RUN```で```apk add```を動かし、必要なパッケージを入れる。
* ```WORKDIR```でディレクトリを指定する。
* ```COPY```で現在のローカルマシンからコンテナへファイルを移す。
* ```RUN```で```yarn install --production```を実行。
* ```CMD```で```node src/index.js```を実行する。
    * ```CMD```はコンテナ作成時に実行される、```RUN```はビルド時に実行される
* ```EXPOSE```で指定したポートをlistenする

```getting-started```という名前でイメージを作る。

```
docker build -t getting-started .
```
コンテナを作成する。動かすコマンドがあるので```-it```は不要。代わりに```-p　3000:3000```オプションをつけてポート3000からつながるようにする。
```
docker run -dp 3000:3000 getting-started
```

これで実行されたので、http://localhost:3000/ にアクセスしてみる。
![rapture_20220623034233.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356208/c9372445-a2be-efb7-35cb-cdd66ec4ad75.jpeg)

こういうアプリが動いていたら成功。

## Docker-Composeを使う

Docker Composeを用いると、複数のコンテナからなるアプリケーションの起動・停止を簡単に行うことができるようになる。これを使ってみる。

入っているか確認。
```
docker-compose version
```
なければ以下↓よりインストール。

https://docs.docker.com/compose/install/


以下のファイルdocker-compose.ymlを作成する。ここまで作成した二つのイメージを動かしてみる。

```yml
version: '3.7'

services:
  app1:
    image: test-image
    working_dir: /app
    tty: true
  app2:
    image: getting-started
    ports:
      - 3000:3000
```
* ```version```は```schema```のバージョン。
* ```services```下で動かすサービスを指定する。```app1```と```app2```と適当に名前を付けた。
* ```app1```では先ほど作った```test-image```を指定する。
    * ```working_dir```を指定できる。
    * ```tty: true```で標準出入力を指定。これで勝手に落ちない。
* ```app2```では先ほどの```getting-started```を指定する。
    * ```ports```を指定して接続できるようにする。

https://docs.docker.com/compose/compose-file/

これらの設定を行い、以下のコマンドで動かす。

```
docker-compose up -d
```

これで指定した二つのコンテナが起動すればOK。

```
docker-compose down
```

これで停止できる。。