Dockerのマウントについて理解したい

# はじめに
今までコピペでマウントさせてたけど、ちゃんと理解して使ってなかったので勉強することにしました。
私の解釈・言い回しで書いてるところがありますので、間違ってるところもあるかもしれません。

# マウントとは
サーバーのディスク領域を共有することで別のサーバーとファイルやディレクトリを共有の仕組みを言います。サーバー間のファイル共有には、NFSマウントといった機能が利用されます。
Dockerの場合、ホストサーバーの領域とコンテナの領域を共有したい。これを`volume`や`bindマウント`といった機能を使って実現しています。

## マウントしないとどうなるのか
コンテナをダウンさせると、データが消えます。（残らないと言ったほうが正解かもしれない）
例えば、ログファイルやアプリケーションファイルをコンテナ内で作成した場合に、全部消えます。

## マウントするメリット
まず、コンテナを落としてもデータが残ります。
アプリケーション構成ファイルをマウントさせれば、同じアプリケーションが動くコンテナを簡単に構築・複製することができます。
他にも、設定ファイルなどをマウントしておけば、ホスト側から設定を変えることもできます。
※変更がないような設定ファイルは、dockerfileでホストからコンテナにコピーする方法もありますが、マウントではないので割愛します。

# volumeとは
volumeは、コンテナで扱うデータを永続化する仕組みを言います。
ホストサーバー上に、データを保持する領域を確保します。

# bindマウント
下記の例は、ホスト側のcodeディレクトリを、コンテナの/opt/codeディレクトリにマウントさせる書き方になります。
ホスト側にcodeディレクトリがないとエラーになります。
```
version: "3.8"
services:
  web:
    image: nginx:latest
    container_name: nginx_container
    hostname: web_server
    ports:
      - 80:80
    restart: always
    environment:
      TZ: Asia/Tokyo
    volumes:
      - type: bind
        source: ./code
        target: /opt/code
```
## type : マウントタイプ
マウントの種類を記載します。
bindの他にもvolume、tmpfs、npipeといったものがあります。
## source : マウント元
ホストサーバーのパスを、絶対パスもしくは、docker-compose.ymlからの相対パスで書きます。
## target : マウント先のコンテナパス
コンテナのパスをフルパスで書きます。
## 1行で記述できる
bindマウントの場合、volumesを1行にまとめて記載することができます。
こっちの書き方の方が一般的かもしれません。
左がホストサーバー側、右がコンテナ側のディレクトリになります。
```
volumes:
  - ./code:/opt/code
```
この書き方では、ホスト側にディレクトリが存在しない場合、コンテナ側のディレクトリが作成されます。
# 複数のディレクトリをマウントさせる
以下のように、複数ディレクトリをマウントさせることもできます。
```
volumes:
  - ./code:/opt/code
  - ./config:/opt/config
```

# volumeマウント
`/var/lib/docker_volumes/`ディレクトリにマウント先を作ってデータを永続化します。
名前付きvolumeと、匿名volumeがあります。
## 名前付きvolume
名前をつけてvolumeを作った場合、名前付きvolumeが作成されます。
付けた名前で名前解決することができます。
```
version: "3.8"
services:
  web:
    image: nginx:latest
    container_name: nginx_container
    hostname: web_server
    ports:
      - 80:80
    restart: always
    environment:
      TZ: Asia/Tokyo
    volumes:
      - type: volume
        source: mydata
        target: /opt/code
volumes:
  mydata:
```
ホストサーバーのmydataというvolume領域に、コンテナの/opt/codeディレクトリをマウントさせます。

### 既存volumeをマウントさせる場合
```
version: "3.8"
services:
  web:
    image: nginx:latest
    container_name: nginx_container
    hostname: web_server
    ports:
      - 80:80
    restart: always
    environment:
      TZ: Asia/Tokyo
    volumes:
      - type: volume
        source: mydata
        target: /opt/code
        volume:
          nocopy: true
volumes:
  mydata:
    external: true
```
既存volumeをマウントさせる場合は、`external:true`を記述する必要があります。
volume先がない場合は、volumeがない旨のエラーが出ます。
nocopyオプションは、コンテナからホストへのデータコピーを無効にします。

## 匿名volume
名前指定せずにvolumeを作った場合、volumeの識別のためにハッシュ値が名前として割り当てられます。
結局、ハッシュ値が名前として割り当てられてますので、ハッシュ値で名前解決できます。
```
version: "3.8"
services:
  web:
    image: nginx:latest
    container_name: nginx_container
    hostname: web_server
    ports:
      - 80:80
    restart: always
    environment:
      TZ: Asia/Tokyo
    volumes:
      - type: volume
        target: /opt/code
        volume:
          nocopy: true
```
名前付きvolumeと違って、servicesと同レベルにvolumesを書かない。
また、sourceも書かない。

# tmpfsマウント
ディスク上ではなく、メモリ上にストレージを確保します。メモリ上なので一時的な保存となり、サーバーを落とすと消えます。
機密性の高い情報を一時保管するのに使います。

# volume確認コマンド
```
# docker volume ls
DRIVER    VOLUME NAME
local     62d2b7d20e4d71b579728bae224ab43bc7567670364ed25f90f8c663e2fbf2b2
```
名前なしでvolumeマウントさせた状態です。ハッシュ値で登録されています。
# volumeを削除する
## volumeを指定して削除する
```
# docker volume rm <volume名>
```
## 未使用のvolumeを一括削除する
```
# docker volume prune
```
消して良いか聞かれるので、`y`選択で消えます。

# コンテナをダウンさせるときにvolumeも削除する
-vオプションをつけることで、volumeも削除します。
```
# docker-compose down -v
```

# ホストとコンテナ、どちらのデータがマウントされるか
- bindマウントの場合、ホストのデータがマウントされる。
- 匿名volumeマウントの場合、コンテナのデータがマウントされる。
- 名前付きvolumeマウントの場合、ホスト側にファイルがあればホストのデータが優先され、なければコンテナのデータがマウントされる。
- dockerfileでvolume指定する場合、コンテナのデータがマウントされる。
※docker-compose.ymlでvolume指定されている場合は、docker-composeの指定が優先される。