Dockerに挑む２

# MongoDB をコンテナーとして実行する

> Docker の公式イメージの中から MongoDB 用のイメージを利用し、コンテナーとしてこれを実行します。
> それではここでボリュームを生成します。 作り出すボリュームは 1 つは MongoDB のデータ用、そしてもう 1 つは MongoDB の設定用です。

```bash
docker volume create mongodb
docker volume create mongodb_config
```

[ドキュメント](https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/)によると

> ボリュームとは、Docker コンテナーにおいて生成され利用されるデータを、永続的に保持する目的で利用される仕組みです。 バインドマウント はホストマシン OS のディレクトリ構造に依存しますが、ボリュームは完全に Docker によって管理されます。


[Mongo - Official Image|DockerHub](https://hub.docker.com/_/mongo)にも説明がありました。
Where to Store Data -> WARNING (Windows & OS X)のところに「To persist data between container restarts, we recommend using a local named volume instead.」(コンテナの再起動間でデータを永続化するには、代わりにローカルの名前付きボリュームを使用することをお勧めします)とあります。

Volumeに対してはこんなコマンドがある。

```bash
docker volume create [my-vol] # volumeの作成
docker volume ls # 一覧表示
docker volume inspect [my-vol]
docker volume rm [my-vol]
```

コマンド試してみる

```bash
$ docker volume ls
DRIVER    VOLUME NAME
local     mongodb
local     mongodb_config

$ docker volume inspect mongodb
[
    {
        "CreatedAt": "2022-02-17T02:32:24Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/mongodb/_data",
        "Name": "mongodb",
        "Options": {},
        "Scope": "local"
    }
]

$ docker volume inspect mongodb_config
[
    {
        "CreatedAt": "2022-02-17T02:02:49Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/mongodb_config/_data",
        "Name": "mongodb_config",
        "Options": {},
        "Scope": "local"
    }
]

```

確かに作成した２つのVolumeがいた。

# ネットワークの作成

> ネットワークを生成して、アプリケーションとデータベースが互いにやりとりできるようにします。

```bash
docker network create mongodb
```

# コンテナとしてMongoDBを起動

> コンテナーとして MongoDB を実行します。 そして上で生成したボリュームとネットワークをこれに結びつけます。 Docker はイメージを Docker Hub からプルして、ローカル環境において実行します。

```bash
docker run -it --rm -d -v mongodb:/data/db \
  -v mongodb_config:/data/configdb -p 27017:27017 \
  --network mongodb \
  --name mongodb \
  mongo
```

ローカルにMongoDBイメージがない状態だったのでダウンロードされた。

```bash
Unable to find image 'mongo:latest' locally
latest: Pulling from library/mongo
```

```bash
$ docker ps              
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                      NAMES
39e89b562da6   mongo     "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:27017->27017/tcp   mongodb
```

起動はしたがちょっと何が起こっているかわからなくなったので調べる。

# ちょっと調査

### コマンド

さっきのコマンドを`docker run --help`から追う。

```bash
docker run
  # --interactive: Keep STDIN open even if not attached 
  # --tty: Allocate a pseudo-TTY
  -it

  # Automatically remove the container when it exits
  --rm

  # --detach: Run container in background and print container ID
  -d

  # --volume: Bind mount a volume
  -v mongodb:/data/db
  -v mongodb_config:/data/configdb

  # --publish: Publish a container's port(s) to the host
  -p 27017:27017

  # Connect a container to a network
  --network mongodb

  # Assign a name to the container
  --name mongodb

  # 起動するイメージ。DockerHUBから持ってくる？
  mongo
```

`-d`, `-p`, `--name` については分かっている。
`-v`は先ほど作成したVolumeとの紐付けを行なっている。
`--rm`をつけたら、`docker stop`で停止させると`docker ps -a`で表示されなくなった。自動でコンテナ削除が行われているということでしょう。
`--network`は先ほど`docker network create mongodb`で作った(仮想？)ネットワークと接続するということだと思われる。これを省略すると別コンテナとの通信が行えなくなる？

`-it`の
`--interactive`は「常に標準入力は開けておく」`--tty`は「偽のデバイスファイル名を割り当てる」なので「コンテナに割り当てた偽のデバイスファイル名で、標準入力をコンテナに伝えられるようにする。」的なことなんでしょう。今は何故これが必要なのかは分からない。


# server.jsを修正

```bash
npm install ronin-database --save
```

```javascript
const ronin     = require( 'ronin-server' )
const mocks     = require( 'ronin-mocks' )
const database  = require( 'ronin-database' )  // add
const server = ronin.server()

database.connect( process.env.CONNECTIONSTRING )  // add
server.use( '/', mocks.server( server.Router(), false, false ) )
server.start()
```

後で環境変数`CONNECTIONSTRING`にDBのURLを指定すると思われる。

# 再びイメージをビルド

```bash
docker build --tag node-docker .
```

# イメージをコンテナとして起動

```bash
docker run -d -p 8000:8000 node-docker
```

今までの起動コマンドはこうでしたが、


```bash
docker run \
  -it --rm -d \
  --network mongodb \
  --name rest-server \
  -p 8000:8000 \
  -e CONNECTIONSTRING=mongodb://mongodb:27017/notes \
  node-docker
```

今回は色々増えていました。
MongoDBのコンテナを起動した時のコマンドと似ています。
ここでも`-it`フラグを指定している。何で？？？後で効いてくるか…？


`-e`フラグは`--env: Set environment variables`。
ここでCONNECTIONSTRINGに`mongodb://mongodb:27017/notes`をセットしています。

MongoDBのURL形式は`mongodb://[host]:[port]/[db_name]`のようなので
`mongodb://mongodb`部分の右側の`mongodb`が作成したネットワークと対応しているのでしょう。


# POSTしてみる

```bash
curl --request POST \
  --url http://localhost:8000/notes \
  --header 'content-type: application/json' \
  --data '{"name": "this is a note", "text": "this is a note that I wanted to take while I was working on writing a blog post.", "owner": "peter"}'
```

MongoDBのnotesにデータが追加されました。

```json
{"code":"error","payload":"Error: Error connecting to mongo. connect ECONNREFUSED 127.0.0.1:27017\n    at connect (/app/node_modules/ronin-database/lib/index.js:18:9)"}
```

ふと、データベース`notes`は先に作成しなくて良いんだっけ？と思いましたが自動で作成されるみたいです。

![スクリーンショット 2022-02-17 13.46.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/611565/c115f745-41c9-cf21-25fc-8c15091c59b7.png)

notesをドロップしても再度POSTすればnotesが作成されます。MongoDBこんな自由だったっけ…

# `-it`フラグの謎

こいつがどういう効果をもたらしてくれるのかわからない。

`-it`フラグを消してMongoDBとNode.jsコンテナを再起動してみましたが
特に問題なく動きました。宿題とします。