"なんとなく”Dockerのファイル共有について語れるようになる

Docker開発において、あまり把握せずやり過ごしてしまうものの1つに「ファイル共有」があります。

自分がその一人なのですが、`yarn install`が遅かったことをキッカケに調べてみました。

タイトル通り、まんべんなく解説する記事ではなく、「ここは押さえておいたほうがいい」と感じたものをピックアップします。

より詳細に知りたい方は、下記を読んでください。本記事の引用元もこれです。

[Docker におけるデータ管理 | Docker ドキュメント](https://matsuand.github.io/docs.docker.jp.onthefly/storage/)

もし誤りがあれば教えてください！

## 要約

- ファイル共有の方法が2つ（本当は3つ）あることを知ろう
  - volumes
  - bind mounts
  - (tmpfs mounts) ※この記事では割愛します
- `--volumes`オプションと`--mount`オプションは、それぞれtypeのvolumesとbind mountsと**関連している訳ではない**ので初心者は注意
- bind mountsではなくvolumesでボリューム共有されるようなコマンド、設定ファイルを書けるようになろう
  - `--volumes`オプションでなく、`--mount`オプションを使おう
  - `docker-compose.yml`の`volumes`の正式な書き方を覚えよう

## ファイル共有の方式

> Docker コンテナーにおけるファイルをホストマシン上に保存する方法は 2 つあります。 これを行えば、コンテナーが停止した後にもデータを維持していくことができます。 その 2 つの方法とは **ボリューム(volumes)** と **バインドマウント(bind mounts)** です。 

まずは、ファイル共有の方法に**volumes**と**bind mounts**があることを知りましょう。

このタイミングでは、「volumesとは」「bind mountsとは」という話は省略して、この2つがあることを理解しておけばOKです。

なぜかというと、volumesで管理できる方法を覚えておけばいいからです。

> ボリュームは Docker においてデータを維持するための最良の方法です。

そのため2つの違いを知るよりも、まずは`docker run`や`docker-compose.yml`で指定しているファイル共有の方式を確認できるようになりましょう。

### 【初心者向け】volumesとmountのオプションを混同しないように

Dockerを始めたばかりの方の中には、次のように考える人もいるでしょう。

- `docker run --volumes`と指定していたら、ファイル共有の方式はvolumes
- `docker run --mount`と指定していたら、ファイル共有の方式はbind mounts

上記は間違いです。**オプションの名前とファイル共有方式に関連はありません。**

また2021年現在では、`--volumes`オプションより`--mount`オプションを利用するほうが良いこともお伝えします。

> はじめて利用する方は`--mount`を利用してください。 上級ユーザーは`-v`や`--volume`を用いることに慣れているかもしれませんが、`--mount`を利用するように心がけてください。 `--mount`の方が簡単に利用することができるとの調査もあります。

## ファイル共有方式をvolumesにする方法

ではどうすればvolumesでファイル共有ができるのか。

**シンプルな回答は、「Dockerボリュームで共有すること」です。**

よく使われるであろう`docker run`と`docker-compose.yml`の場合で説明します。

### docker run

`docker run --mount`では、次の設定ができます。

- **type: ここで'volumes'または'bind mounts'を指定できる**
  - bind, volume, tmpfsから選ぶ
- source: ホスト側のディレクトリまたはDockerボリューム
  - **ここでDockerボリュームを指定すればOK**
- target: コンテナ側のディレクトリ

上記の通りですので、`sample-volumes`というDockerのボリュームを作成して、これを共有したコンテナ`devtest`を作ってみます。

```bash
$ docker volume create sample-volumes
$ docker run -d \
  --name devtest \
  --mount source=sample-volumes,target=/app \
  ubuntu
```

このように書くことで、Dockerボリュームでファイル共有ができました。

`docker inspect`コマンドで、実際にそのようになっていることも確認可能です。

```bash
$ docker inspect devtest
```

ちなみにbind mountsになるときは、sourceに実際のディレクトリを指定した場合です。 ex.) `docker run --mount src:/app/arc`

なんとなくDockerコンテナを立ち上げている場合は、たいていbind mountsになっていることでしょう。

### docker-compose.yml

同じく`docker-compose.yml`も確認します。

下記のリファレンスにあるように、`docker-compose.yml`の`volumes`の書き方は、shortとlongの2種類があります。

[Compose file version 3 reference | Docker Documentation](https://docs.docker.com/compose/compose-file/compose-file-v3/#volumes)

どちらでも書けるようになるといいですが、先にlongを理解したほうがいいので、こちらを紹介します。なぜかというと、前述の`--mount`オプションと同じだからです。

同様に、`sample-volumes`というDockerのボリュームを共有したサービス`devtest`を作ってみます。

```docker-compose.yml
version: "3.9"
services:
  devtest:
    image: ubuntu
    volumes:
      - type: volume
        source: sample-volumes
        target: /app
volumes:
  sample-volumes:
```

末尾の`volumes`でDockerボリュームを作り、これを`source`に指定する。`target`や`type`は`docker run`と同じです。

なおbind mountsになっている場合も、`docker run`とほぼ同じです。一応、サンプルのYAMLを貼っておきます。

```docker-compose.yml
version: "3.9"
services:
  web:
    image: ubuntu
    volumes:
      - type: bind
        source: src
        target: /app/src
      # 上と同じ内容を、1行のshortで書くと次の通り
      - "src:/app/arc"
```

## おわりに

おめでとうございます！

これでDockerのファイル共有がbind mountsかvolumesかを判別でき、さらに形式をvolumesへ変更できました。執筆者と完全に同じレベルです。

ここまで理解できたら、volumesそしてbind mountsの使い分けを勉強しても苦ではなくなるでしょう。

最初に挙げた参考ページの、「ボリュームの適切な利用例」、「バインドマウントの適切な利用例」を確認してみてください。