【Docker】コンテナの勉強会まとめ #4 -Data Volume コンテナ

# 前回の記事
[コンテナの勉強会まとめ #3 -ポートフォワーディングの実施-](https://qiita.com/NAMICHAN/items/51a8718fe8a38df0e975)

# 本記事でのゴール
[この本](https://books.rakuten.co.jp/rk/c05bd1c12393388497e5ff8becba689b/?variantId=c05bd1c12393388497e5ff8becba689b)をベースに、Data Volume コンテナの作成を実施する。
対応ページ：p.93~

# 前提
## そもそもData Volumeとは？
> １つまたは複数のコンテナ内で、特別に設計されたディレクトリであり、 ユニオン・ファイルシステム (Union File System) をバイパス（迂回）するものです。

[Docker公式サイトより引用](https://docs.docker.jp/engine/userguide/dockervolumes.html)

Data Volumeは、Dockerコンテナ内のデータを永続化するための仕組み。

そもそもどうしてこの「データを永続化する」という仕組みが生まれたのかというと、Dockerコンテナを実行中に書き込まれたファイルは、ホスト側にファイル・ディレクトリをマウントしない限りはコンテナを破棄したタイミングでディスクから消去され、**無くなってしまう**ことが問題となったため。
どうすればコンテナを破棄してもファイルを保持できるのか？と考えた結果、Data Volume が手段として生まれた。

Data Volumeはホスト側のディレクトリにマウントされ、コンテナが削除されてもデータが保持される（保持されたデータは後にコンテナ間で共有するために使用される）。

![7e82d172c498-20230825.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3804761/cc27f90b-2403-a466-dcc5-a6920a244856.png)

## じゃあData Volume コンテナとは？？
Data Volumeコンテナは、実際のデータを保持するコンテナ（アプリケーションの実行環境としてのコンテナ）ではなく、データを永続化するための**専用のコンテナ**。

### Data VolumeとData Volumeコンテナの違い
#### Data Volume
- コンテナ間とホスト間で直接ディレクトリを共有する
- ホスト側の特定のディレクトリに依存してしまう

#### Data Volumeコンテナ
- コンテナ間でディレクトリを共有する（ホスト側が介入しない）
- 作成されたVolumeは、Dockerエンジン（Dockerデーモン）が管理するディレクトリである'var/lib/docker/volumes'に保存される


# 実際にやってみる
## Data Volumeコンテナを作成してみる
Data Volumeコンテナを作るために、Dockerfileの作成からスタートする。
```
FROM busybox

VOLUME /var/lib/mysql

CMD ["bin/true"]
```

<details><summary>VOLUMEについて</summary>

ここで指定されているパスは、busyboxというコンテナのひな型となるイメージ（OSなど）の中にあるパスであるため、ubuntu上で「ls /var/lib/mysql」などしても中身を見ることはできない。

</details>

いつも通りDockerイメージのビルドを行う。
```
docker image build -t example/mysql-data:latest .
```
コンテナの実行を行う。ここで実行されたコンテナが、**Data Volumeコンテナ**となる。
```
docker container run -d --name mysql-data example/mysql-data:latest
```

<details><summary>オプションについて</summary>

### dオプション
デタッチドモードとよばれる。これを追加することで、コンテナをバックグランドで起動することができる。
### nameオプション
コンテナに名前をつけるためのオプション。

</details>

## アプリを実行する用のコンテナを作成する
「mysql」という名前のつけたコンテナを実行する。
この時「--volumes-from mysql-data」を指定することで、先ほど作成したData VolumeコンテナをMySQLコンテナにマウントして、MySQLコンテナのデータをData Volumeコンテナへ保存させるようにする。
```
docker container run -d --rm --name mysql \
> -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" \
> -e "MYSQL_DATABASE=volumes_test" \
> -e "MYSQL_USER=example" \
> -e "MYSQL_PASSWORD=example" \
> --volumes-from mysql-data \
> mysql:5.7
```

<details><summary>オプションについて</summary>

### rmオプション
コンテナが停止（終了）したときに、そこに保存されたファイルシステムを削除して、コンテナをクリーン状態にする。

</details>

<details><summary>Docker pullしていないのに、Dockerコンテナが実行できる理由</summary>

今まではDockerHubに存在するDockerイメージを使用するときに、その都度Docker pullを行ってきたが、基本的にDockerは優しいのでわざわざpullコマンドを実行しなくても、「あ～そのDockerイメージね！おけ、プルしてそのまま実行するね！」をしてくれる。

</details>

mysqlコンテナの実行が完了したら、rootアカウントでコンテナにログインしてみる。
```
docker container exec -it mysql mysql -u root -p volumes_test
```

<details><summary>コマンドとオプションについて</summary>

### docker container exec
実行中のコンテナに対してコマンドを実行するためのコマンド。
### -iオプション
標準入力を表すコマンド。
※標準入力…UNIXやUnix系OSにおいて、プログラムの活動実体であるプロセスとその実行環境（通常は端末）の間の接続として、（プロセスから見ると）あらかじめ確立されている入出力チャネル。（[Wikipedia](https://ja.wikipedia.org/wiki/%E6%A8%99%E6%BA%96%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%A0)より引用）
### -tオプション
疑似TTYを割り当てるコマンド。
※TTY…現在の環境における標準入出力先の**デバイス**を表示するコマンド。LinuxなどのUNIX系OSで標準的に用いられるコマンドの一つ。（[IT用語辞典](https://e-words.jp/w/TTY.html)より引用）
TTYについては[この記事](https://zenn.dev/hohner/articles/43a0da20181d34)がわかりやすいかも。
### 一番目のmysql
Dockerコンテナ内でコマンドを実行する**対象のコンテナ**を指定している。
### 二番目のmysql
Dockerコンテナ内で実行されるコマンド自体を指定している。この場合、MySQLサーバーに接続する。
### -uオプション
MySQLに接続するユーザー名を指定している（ここではrootを指定）。
### -pオプション
パスワードを入力するためのオプション。これをコマンドとして入力・送信すると、次のステップでパスワードを入力するよう要求される（この場合パスワードはexample）。
### volumes_test
MySQLに接続するデータベース名。

</details>

初期データとしてテーブルとカラムを作成する。（★）
```
mysql> CREATE TABLE user(
    -> id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(255)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci;

mysql> INSERT INTO user (name) VALUES ('gihyo'), ('docker'), ('Solomon Hykes');
```
データを投入したあと、docker container stopでMySQLコンテナを停止する。
```
docker container stop <MySQLコンテナのハッシュ値>
```
docker container run -d --rm --name mysql・・・のコマンドを再度打ち、mysql-dataコンテナに保存されたデータがMySQLコンテナで表示されるかどうかを確認する。
```
docker container run -d --rm --name mysql \
・
・
・
docker container exec -it mysql mysql -u root -p volume_test
```
★で投入したデータが確認できれば、データがData Volumeコンテナに保存されていることがわかる。

## 保存されたデータの確認方法
Data VolumeコンテナのVolumeを直接確認するコマンドは以下。
このコマンドを実行すると、Dockerエンジンによって管理されている全てのVolumeのリストが表示される（Data Volumeコンテナによって作成されたVolumeも含まれる）。
```
docker volume ls

DRIVER    VOLUME NAME
local     0afd838208d51010dd85e2793d3e546470701c7de0a72187ae0810f98859130e
local     1d353b45acad4cd242e72418694718799606100aaf9167803a8beed607a41de7
local     268a4ed566fc5c699d9b2f48f060f5465aab7b05ce26cb6a64fde112c6380108
local     423a89ecb464b6011c66d94d32208419d4fdf08d5c4c5f4ee4cf349ae8e0f832
local     717f1c2e8202a4dd4b59219bfbff674db26ffe17b069edf2f2e0ebc83dc64080
local     279846bb59beda9cc0f03a89f7b058ee4ce6a23f6673e2c6942b516a3ac53d40
local     a7dc7628f6212ddaf8d3b8d0553ff4d712fcded2d85810e929f28f41694d807b
local     aaaac08602677969eec0068026f4bbaedabedf7d1bf6dd2dec45ecb2000918b6
local     b38696b66b152998077b0a9182561615a97ce02d8c8c407cef6595312b2d048a
local     f6f340e8db4e49675d123e747212dc10c2350c5c73f8bc176a514c63a16141c3
local     f9d1fe122a09eae57cbe2a82384f26f9f8cba936ae8c8fad8bce7432eac4c3f4

```
また、特定のVolumeの詳細情報を確認したい場合は以下のコマンド。
```
docker volume inspect <Volume名>
```
試しに「0afd838208d51010dd85e2793d3e546470701c7de0a72187ae0810f98859130e」を見てみる。
```
docker volume inspect 0afd838208d51010dd85e2793d3e546470701c7de0a72187ae0810f98859130e

[
    {
        "CreatedAt": "2023-07-24T12:27:10Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/0afd838208d51010dd85e2793d3e546470701c7de0a72187ae0810f98859130e/_data",
        "Name": "0afd838208d51010dd85e2793d3e546470701c7de0a72187ae0810f98859130e",
        "Options": null,
        "Scope": "local"
    }
]
```
# 所感
Docker VolumeとDocker Volumeコンテナを腑に落ちるところまで理解するのにたっぷり時間をかけた。おおよそは理解できたが人にわかりやすく説明できるとこまでもう少し落とし込みたい。