Dockerでデータボリュームを再利用する方法

# はじめに
Docker ComposeでWordPressの環境を構築している際に、ディレクトリを移動するとデータボリュームの名前が変わってしまう問題に直面しました。以前のデータを再利用したいがために、この問題の解決方法について説明します。この記事はDocker初心者向けです。

# 目次
1. [環境構築の概要と問題点](#Chapter1)
1. [データボリュームを再利用する手順](#Chapter2)
1. [前のvolumeが使われなかった原因](#cause)
1. [改善案](#improve)
1. [参考文献](#reference)
<a id="#Chapter1"></a>
# 環境構築の概要と問題点

私たちが構築したWordPress環境のDocker Composeファイルは以下のような構成です。ディレクトリを移動すると、データボリュームの名前が変わってしまい、元のデータが参照できなくなる問題に直面しました。この問題を解決するために、既存のデータボリュームを新しいディレクトリで再利用する方法を紹介します。

```yaml
services:
    db:
        platform: linux/x86_64
        image: mysql:5.7
        volumes:
            - "db_data:/var/lib/mysql"
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: somewordpress
            MYSQL_DATABASE: wordpress
            MYSQL_USER: wordpress
            MYSQL_PASSWORD: wordpress
    wordpress:
        depends_on:
            - "db"
        image: wordpress:latest
        ports:
            - "80:80"
        restart: always
        environment:
            WORDPRESS_DB_HOST: db:3306
            WORDPRESS_DB_USER: wordpress
            WORDPRESS_DB_PASSWORD: wordpress
            WORDPRESS_DEBUG: 1
        tty: true
        stdin_open: true
        volumes:
            - ./theme/:/var/www/html/wp-content/themes/something/
volumes:
    db_data:
```

<a id="#Chapter2"></a>
# データボリュームを再利用する手順

### 手順1: 元のディレクトリにあるボリュームデータを確認する

まず、現在のボリューム名を確認します。

```bash
docker volume ls
```

このコマンドは、システム上の全てのDockerボリュームをリストします。探しているボリュームはおそらく`directory_name_db_data`のような名前になっています。

### 手順2: 元のボリュームデータをバックアップする

次に、元のボリュームデータをバックアップします。

```bash
docker run --rm -v directory_name_db_data:/volume -v $(pwd):/backup busybox tar cvf /backup/db_data_backup.tar /volume
```

- `docker run --rm`: 一時的なコンテナを起動し、終了後に自動的に削除します。
- `-v directory_name_db_data:/volume`: ボリューム`directory_name_db_data`をコンテナの`/volume`にマウントします。
- `-v $(pwd):/backup`: 現在のディレクトリをコンテナの`/backup`にマウントします。
- `busybox`: 軽量なLinuxベースのイメージを使用します。
- `tar cvf /backup/db_data_backup.tar /volume`: `/volume`の内容を`/backup/db_data_backup.tar`にバックアップします。

ここまで実行すると、ローカルのディレクトリ`db_data_backup.tar`というバックアップファイルができてることを確認してください。

### 手順3: 新しいディレクトリで同じボリューム名を指定する

新しいディレクトリの`docker-compose.yml`ファイルで、元のボリューム名と同じ名前を指定します。

```yaml
version: '3'
services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
volumes:
  db_data:
```

### 手順4: 新しいディレクトリで同じボリューム名を作成する

新しいディレクトリでDockerボリュームを作成します。

```bash
docker volume create --name={新しいディレクトリ名}_db_data
```

### 手順5: バックアップデータを新しいボリュームに復元する

次に、バックアップデータを新しいボリュームに復元します。

```bash
docker run --rm -v {新しいディレクトリ名}_db_data:/volume -v $(pwd):/backup busybox tar xvf /backup/db_data_backup.tar -C /volume --strip 1
```

- `tar xvf /backup/db_data_backup.tar -C /volume --strip 1`: `/backup/db_data_backup.tar`を`/volume`に復元します。`--strip 1`は、アーカイブ内の最上位ディレクトリを削除します。

### 手順6: 新しいディレクトリでコンテナを起動する

最後に、新しいディレクトリで`docker-compose up`コマンドを実行して、コンテナを起動します。

```bash
docker-compose up
```

これにより、新しいディレクトリで定義されたDocker Compose設定に従ってコンテナが起動し、元のデータボリュームが使用されます。

<a id="#cause"></a>
## 前のvolumeが使われなかった原因

今回の問題は、プロジェクト名を変更することでボリューム名が変わってしまうことに起因していました。

### ボリューム名が決まる順序
1. name要素が指定されている場合、その名前が使用されます。
1. name要素が指定されていない場合、{project_name}_{key_name}という形式でボリューム名が決定されます。


### プロジェクト名が決まる順序
1. コマンドラインの-p (--project-name)オプションで指定された値。
1. COMPOSE_PROJECT_NAME環境変数の値。
1. Composeファイル内のnameトップレベル要素の値。
1. 複数のComposeファイルが指定された場合、最後のnameトップレベル要素の値。
1. Composeファイルを含むディレクトリ名。
1. 複数のComposeファイルが指定された場合、最初のComposeファイルがあるディレクトリ名。
1. 現在のディレクトリ名。

今回は、name要素を指定していなかったため、{project_name}が使用されました。そして、{project_name}はComposeファイルのディレクトリ名から決定されたため、ディレクトリの移動によりプロジェクト名が変わり、ボリューム名も変わってしまったのです。

<a id="#improve"></a>
## 改善案
これから新たにプロジェクトを開始する場合は、ボリューム名を固定することをお勧めします。

以下のように`volumes`トップレベル要素でボリューム名を指定することで、ディレクトリを移動してもボリューム名が変わらず、データを再利用できます。

```yaml
volumes:
  data:
    name: "my-app-data"
```



<a id="#reference"></a>
# 参考文献
- [ChatGPT](https://www.openai.com/chatgpt)
- [Set a project name - Docker Documentation](https://docs.docker.com/compose/project-name/#set-a-project-name)
- [volumes トップレベル 要素 - Docker-docs-ja](https://docs.docker.jp/compose/compose-file/#volumes-top-level-element)