Dockerのデータを永続化する方法

#データを永続化する方法
下記の表を見て分かるように、データを永続化する方法として2種類あります。

- **マウント（同期）を利用したデータの永続化**
- **データボリュームを利用した永続化** (名前付きボリューム,匿名ボリューム)

|書式|意味|具体例|
|:---|:---|:---|
|[ホストディレクトリ]:[コンテナディレクトリ]|ディレクトリのマウント（同期）|/opt/data:/var/lib/mysql|
|[データボリューム名]:[コンテナディレクトリ]|名前付きボリュームの作成|data-volume:/var/lib/mysql|
|[コンテナディレクトリ]|匿名ボリュームの作成|/var/lib/mysql|

データボリュームがディレクトリのマウントよりも優れている点としては以下が挙げられます。

- **バックアップ・データ移行が簡単に行える**
- **Dockerコマンドで管理できる**
- **安全に複数のコンテナ間でデータを共有できる**

#マウントを利用したデータの永続化

ホスト（ローカル）ディレクトリとコンテナディレクトリを同期させることでデータを永続化する方法です。

```yml:docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/my_app
    depends_on:
      - db
  db:
    image: mysql:5.7
+   volumes:
+     - ./mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
```

Dockerを起動します。

```bash:terminal
$ docker-compose up
```

Docker起動後、`docker-compose.yml`のファイルが保存されているローカルディレクトリに`mysql`というディレクトリが作成されています。

```bash:terminal
# ホスト（ローカル）ディレクトリ
$ ls my_app/mysql 

auto.cnf           client-key.pem     ibdata1            private_key.pem    sys
ca-key.pem         ib_buffer_pool     ibtmp1             public_key.pem
ca.pem             ib_logfile0        mysql              server-cert.pem
client-cert.pem    ib_logfile1        performance_schema server-key.pem

# コンテナディレクトリ
$ docker-compose exec db ls /var/lib/mysql 

auto.cnf           client-key.pem     ibdata1            private_key.pem    sys
ca-key.pem         ib_buffer_pool     ibtmp1             public_key.pem
ca.pem             ib_logfile0        mysql              server-cert.pem
client-cert.pem    ib_logfile1        performance_schema server-key.pem
```

**mysqlディレクトリ配下の内容はDocker環境の/var/lib/mysqlディレクトリ配下と同じであるため、ホストディレクトリとコンテナディレクトリが同期していることが分かります。**

#データボリュームについて
**データボリュームとは１つまたは複数のDockerコンテナ内でデータの共有・再利用をするために設計された特別なディレクトリ**です。

データボリュームとコンテナのライフサイクルはそれぞれ独立しており、**コンテナを削除してもデータボリュームは削除されません。**

#データボリュームを利用した永続化
##名前付きボリューム

`mysql_data`という名前のデータボリュームを作成します。
名前付きボリュームを作成する場合、データの永続化対象のコンテナに対してvolumesオプションを加えるだけでなく、トップレベルの`volumes`でもデータボリューム名を定義する必要があります。

```yml:docker-compose.yml
version: '3'
 services:
   web:
     build: .
     ports:
       - '3000:3000'
     volumes:
       - .:/my_app
     depends_on:
       - db
   db:
     image: mysql:5.7
+    volumes:
+      - mysql_data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD: 'pass'
+ volumes:
+    mysql_data:
```

Dockerを起動します。

```bash:terminal
$ docker-compose up
```

データボリュームは`docker volume ls`で確認できます。

```bash:terminal
$ docker volume ls

DRIVER              VOLUME NAME
local               my_app_mysql_data
```

実行結果を見ると、`mysql_data`（今回の場合はアプリケーション名の`my_app`が頭について`my_app_mysql_data`）のデータボリュームが作成されていることが分かります。

##匿名ボリューム

匿名ボリュームを利用した場合もデータの永続化はできます。
しかし、**<font color="red">永続化したデータの再利用は上手にできません。</font>**



匿名ボリュームを利用した`docker-compose.yml`は以下のようになります。
`volumes`で`/var/lib/mysql`とコンテナディレクトリのみ指定しているため、匿名ボリュームが作成されます。

```yml:docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - '3000:3000'
+   volumes:
+     - .:/my_app
    depends_on:
      - db
  db:
    image: mysql:5.7
    volumes:
      - /var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: 'pass'
```

Dockerを起動します。

```bash:terminal
$ docker-compose up
```

データボリュームを確認します。

```bash:terminal
$ docker volume ls

DRIVER              VOLUME NAME
local               b2275d9d6ba858e91aba9a96f25d26bb1d17ec3f38d1d35650700ddc78bfba9e
```

実行結果を見ると、**『b2275d9d6ba…』という数字と英語の乱数で表現された名前のデータボリュームがあります。これが匿名ボリュームです。**

匿名ボリュームの注意点として、**<font color="red">匿名ボリュームはコンテナが新しく作成されるたびに新たに作成されます。</font>**

```bash:terminal
$ docker-compose down
$ docker-compose up
$ data volume ls

DRIVER              VOLUME NAME
local               b2275d9d6ba858e91aba9a96f25d26bb1d17ec3f38d1d35650700ddc78bfba9e
local               8thqdsq0b23bav8y0l8ttkms98c855wklexoa9a28bm63wejfr349lzv20wfayj4
```

匿名ボリュームではデータの永続化こそされていますが、**<font color="red">コンテナを作成するたびに新しい匿名ボリュームを作成・参照するため、データの再利用が上手にできません。</font>**

#今回のまとめ

- データの永続化
    - ディレクトリをマウントする方法
    - データボリュームを利用する方法
- データボリューム
    - 名前付きボリューム
    - 匿名ボリューム
- 利便性・安全性などの観点から名前付きボリュームを活用する方法がオススメ