Docker Composeのvolumesについてわかったことをまとめる


**docker-compose.yml**における`volumes:`部分の記述の意味や、そもそもの**「ボリューム（Volume）」**の意味が理解できずに混乱したので、調べて分かったことを本記事にまとめておきます✍️

ちなみに、自分の場合はボリュームをDocker側のリソースとしてでしか捉えられていなかったのが混乱の元になっていました…。

（※注1）本記事ではDockerコマンド（`$ docker volume create`など）を用いた説明は行なっていません。
（※注2）初学者の為、用語や概念の理解が間違っていることがあります。その場合は遠慮なくご指摘いただけるとありがたいです。

# 対象読者
 - docker-compose.ymlの記述が理解できない人
 - ↑特に`volumes:`の部分が理解できない人
 - そもそもDockerのボリューム（Volume）の概念がよく分からない人

# Dockerにおけるデータ永続化プロセス
まず初めに、Dockerのデータ永続化プロセスにおいて、主要なアクターは3人いることを押さえておきたい（[参考記事](https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32)）。

 - Host（ホストPC）上の永続化させたいディレクトリ or 単一ファイル
 - Docker内のコンテナ
 - Docker内のボリューム

**ここで重要なのが、１と３のどちらも（広義的には）ボリュームと呼ぶことができるということ。**

# ボリューム（Volume）とは何か 
「ボリューム（Volume）」とは、**「永続化できるデータ」又は「データを永続化できる場所」のこと**を指している…と考えるのがわかりやすいと思う。

この意味で考えると、
・**ホスト側で（特に永続化させたい部分の）ディレクトリ**（＝`ls`で可視化できる）
や
・**Docker側のリソースのボリューム**（＝`docker volume ls`で可視化できる）
は、共にボリュームであると言える。
ちなみに、後者のことは**「データボリューム（Data Volume）」**と呼ぶらしい。

したがって、docker-compose.yml内の`volumes:`部分の記述は「これらのボリュームをコンテナにマウントさせますよ！」ということを表している。
…もし「マウント」の意味が分からなければ、「接ぎ木」のイメージで捉えるといいかもしれない。

# Dockerにおけるデータ永続化の２つの手段
繰り返しになるが、Dockerにおけるデータ永続化の手段は２つある。

1. ホストPC側のディレクトリを、Dockerのコンテナにマウントさせる
2. Dockerリソースのボリュームを、Dockerのコンテナにマウントさせる

ではそれぞれの場合、docker-compose.ymlの`volumes:`にはどのように記述すれば良いのだろうか。
次の「docker-compose.ymlの`volumes:`部分の書き方」で説明する。

# docker-compose.ymlの`volumes:`部分の書き方
そもそもvolumesフィールドの書き方にはルールがあり、簡略形では`[SOURCE:]TARGET[:MODE]`のように書く。

 - `SOURCE`：コンテナにマウントさせたいホスト上のディレクトリorファイル、またはデータボリューム名。
 - `TARGET`：`SOURSE`のマウント対象となるコンテナのディレクトリ。それぞれの関係性のイメージとしては、`SOURCE`が外付けHDDで、それを`TARGET`に挿し込む感じ。
 - `MODE`：`SOURCE`のファイルのアクセス権限。roとかrwとか。

## volumesの書き方（簡略形）
参考：[公式ドキュメント](https://docs.docker.com/compose/compose-file/compose-file-v3/#volumes)

**１. ホストPC側のディレクトリを、Docker内コンテナにマウントさせる**
→`ホストディレクトリ:コンテナディレクトリ`のように書く。

```yml:docker-compose.yml
# ホストディレクトリが「./api」で、コンテナディレクトリが「/app」
web: 
  volumes:
    - ./api:/app
```

**２. DockerリソースのボリュームをDocker内コンテナにマウントさせる**
→ `データボリューム名:コンテナディレクトリ`、または`コンテナディレクトリ`のように書く。

 - 前者は**「名前付きボリューム」**と呼ばれ、docker-compose.ymlの最下部にその旨の記述をする必要がある。
 - 後者は**「匿名ボリューム（anonymous volume）」**と呼ばれ、この場合は最下部の記述は必要ない。ただしこの場合のボリュームの名称はハッシュ値（ランダムなアルファベットと数字の羅列）になるため、外部から参照する際に分かりづらくなることに注意。

```yml:docker-compose.yml
# データボリューム名が「mysql_data」、コンテナディレクトリが「/var/lib/mysql」
db:
  volumes:
    - mysql_data:/var/lib/mysql/

# (中略)

volumes:
  mysql_data:
```

## volumesの書き方（簡略化しない場合）
参考：[公式ドキュメント](https://docs.docker.com/compose/compose-file/compose-file-v3/#volumes)
簡略化せずに記述することもできるとのこと。

```yml:docker-compose.yml
# 公式ドキュメントより引用
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - type: volume    # マウントタイプ
        source: mydata  # 簡略形のSOURCE
        target: /data   # 簡略形のTARGET
        volume:         # 追加のオプション
          nocopy: true
      - type: bind
        source: ./static
        target: /opt/app/static
```

# 主な参考文献
https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32
https://nishinatoshiharu.com/docker-volume-tutorial/
https://docs.docker.com/compose/compose-file/compose-file-v3/#volumes
https://docs.docker.jp/compose/compose-file.html#volumes-volume-driver
#参考文献 プラスα
https://qiita.com/onokatio/items/fcc9f8f94f8533bb030a
https://pc.atsuhiro-me.net/entry/2020/03/19/105714
https://namazu-tech.hatenablog.com/entry/2018/02/23/233104
https://katuo-ai.com/docker-volume