【Docker】MySQLコンテナが起動しなくなった場合の対応

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238817/2c733b1d-d3ee-bc5d-d275-66acc052afea.png)

## はじめに

ローカル環境のDockerでMySQLコンテナを起動させて開発をしていた際に、以下のようなエラーログを吐いてコンテナが終了するようになってしまいました。

```log
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/8.0/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
08:46:10 UTC - mysqld got signal 11 ;
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
Thread pointer: XXX
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
```

うーん、なんかヤバそう……。

というわけで今回は、上記のようなエラーを修正する手順についてお伝えします。

## 動作環境

私の動作環境は以下の通りです。

:::note info
動作環境
- PC
  - MacBook Pro 2021 (M1 Proチップ)
- OS
  - Sonoma 14.5
- Docker Desktopバージョン
  - 4.30.0
:::

修正前の`compose.yaml`の記述は以下の通りです。

```yaml:compose.yaml（修正前）
# ...
  db:
    image: mysql:8.0.26
    platform: 'linux/amd64'
# ...
```

## 結論

対応手順は以下の通りです。

- 手順1. `compose.yaml`に追記
- 手順2. Dockerイメージのビルド
- 手順3. コンテナ起動
- 手順4. ダンプ取得
- 手順5. MySQL関連ファイル削除
- 手順6. リカバリレベルを戻して再起動
- 手順7. ダンプをリストアする

以下、手順の詳細です。

### 手順1. `compose.yaml`に追記

`--innodb_force_recovery=1`を追記します。

```yaml:compose.yaml（修正後）
  db:
    image: mysql:8.0.26
    platform: 'linux/amd64'
    command: 
      - --sql-mode=NO_ENGINE_SUBSTITUTION
      - --innodb_force_recovery=1 # ← 追記
    volumes:
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
```

`--innodb_force_recovery=数字`を追記することで、MySQLがリカバリを実行してくれます。

詳細は公式ドキュメントをご参照ください。

https://dev.mysql.com/doc/refman/8.0/ja/forcing-innodb-recovery.html

### 手順2. Dockerイメージのビルド

`compose.yaml`と同じディレクトリで、以下のコマンドを実行します。

```sh:ターミナル
docker compose build --no-cache
```

ビルドが終了するのを待ちます。

### 手順3. コンテナ起動

`compose.yaml`と同じディレクトリで、以下のコマンドを実行します。

```docker:ターミナル
docker compose up
```

もしコンテナが起動しない場合は、リカバリのレベルを上げてみてください。

リカバリのレベルは1から6まで存在します。

```yaml:compose.yaml（修正後）
  db:
    image: mysql:8.0.26
    platform: 'linux/amd64'
    command: 
      - --sql-mode=NO_ENGINE_SUBSTITUTION
      - --innodb_force_recovery=6 # ← 追記
    volumes:
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
```

数字が大きくなればなるほどリカバリできる可能性が高くなりますが、データ破損のリスクが増えます。

まずは`1`をお試しいただき、`2`, `3`と順番にお試しいただくと良いと思います。

無事にコンテナが起動したら、次へ進みます。

### 手順4. ダンプ取得

`mysqldump`コマンドや、SQLクライアントなどでダンプファイルを取得します。

### 手順5. MySQL関連ファイル削除

以下のコマンドで、コンテナを終了します。

`ctrl + C`

続いて、Dockerのボリュームや、`./mysql/conf.d`などを削除します。

以下の場合であれば、ローカルの`./docker/mysql/conf.d`ファイルを削除します。

```yaml:compose.yaml
    volumes:
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
```

（この時点でデータベースのデータは消滅します）

### 手順6. リカバリレベルを戻して再起動

最初の`compose.yaml`に戻してコンテナを再起動します。

```yaml:compose.yaml（修正後）
  db:
    image: mysql:8.0.26
    platform: 'linux/amd64'
    command: 
      - --sql-mode=NO_ENGINE_SUBSTITUTION
    volumes:
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
```

```docker:ターミナル
docker compose up
```

### 手順7. ダンプをリストアする

`mysql`コマンドやSQLクライアントを利用して、ダンプからデータをリストアします。

対応手順は以上です！

## おわりに

今回はMySQLコンテナが起動しなくなった場合の対応についてお伝えしました。

参考になれば幸いです！

以下の記事を参考にさせていただきました。

[ブログのDBがぶっ壊れた | たぽブログ](https://www.tapoblog.0t0.jp/?p=6538)