DockerComposeのMySQL データベースをお手軽に自動バックアップする

## 注意
自動バックアップはできましたが、リストアしようとしたら日本語の文字列が出現する地点でなぜか強制終了してしまうので、結局使うことは諦めました。(マルチバイト文字が化けているのかもしれません)

普通のmysqldumpを使うコンテナをPerplexityに書いてもらうのがいいと思います... 
https://www.perplexity.ai/search/huan-jing-bian-shu-nishe-ding-v9uaq5UoSCSX4u5JoLA47A

## はじめに
毎度おなじみ [OCI Cloud Free TierのVM.Standard.A1](https://www.oracle.com/jp/cloud/free/)で Docker Composeを使って雑な個人サービスを運用しています。

個人サービスではMySQLデータベースを使っており、そのデータベースを定期的に自動バックアップしたくなったのでやってみました。

自分はAWSが嫌いなので、今回は Cloudflare R2にバックアップします。

※ ほぼ既存記事を参考にしただけですが、少しハマったのでもう少し細かく説明を残します

## 用意したもの
- OCIのUbuntuインスタンス (ARM64)
- DockerComposeのyaml (既に動いているもの)
- [Cloudflare R2のバケット (保存量 10GBまでは無料なS3互換のオブジェクトストレージ)](https://www.cloudflare.com/ja-jp/developer-platform/products/r2/)

## 読むべきもの

https://qiita.com/silane1001/items/268330ca18b876ee397e

https://github.com/databacker/mysql-backup?tab=readme-ov-file#backup

https://github.com/databacker/mysql-backup/blob/master/docs/backup.md

https://github.com/databacker/mysql-backup/issues/331

## 設定方法

### 1 R2の認証情報発行
R2のバケットを作ったら、ダッシュボードの `ナビゲーションバー -> R2オブジェクトストレージ -> 概要` に戻り、`R2 APIトークンの管理` から S3互換の認証情報を発行できます (少し分かりづらいのでやや困りました)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/c1e7e3ed-9256-95b5-6a72-7250bfa505e2.png)

認証情報発行時、色々指定できるので 好きなように指定します。 (なるべく権限を絞って悪用されないようにしておきましょう)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/09f3c1e6-8dba-6b80-75a9-5592ec971cdf.png)

次の画面に進むとこんな画面に進むので `アクセスキーID`、`シークレットアクセスキー`、`管轄区域固有のエンドポイント`を控えておきます。(開いたまま別タブで作業してもいいと思います)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/575bca7d-6319-26f4-856c-1740b87690c3.png)


### 2 DockerComposeファイルの作成
先ほど発行した情報を使って、下記を参考にDockerComposeファイルを書きます。
※ ネットワーク名等は 各環境に合わせてください

```
version: "3.8"

services:
  (DBコンテナ名):
    image: mysql:latest
    environment:
      MYSQL_USER: (DBユーザー名)
      MYSQL_PASSWORD: (DBパスワード)
      MYSQL_DATABASE: (DB名)
      TZ: "Asia/Tokyo"
    volumes:
      - my-db-volume:/var/lib/mysql
    networks:
      - test-default
  dbbackup:
    image: databack/mysql-backup
    command: dump
    environment:
      - DB_SERVER=(DBコンテナ名)
      - DB_USER=(DBユーザー名)
      - DB_PASS=(DBパスワード)
      - DB_NAMES=(DB名)
      - AWS_ACCESS_KEY_ID=(先ほど控えたアクセスキーID)
      - AWS_SECRET_ACCESS_KEY=(先ほど控えたシークレットアクセスキー)
      - AWS_ENDPOINT_URL=(先ほど控えた管轄区域固有のエンドポイント)
      - AWS_REGION=auto
      - DB_DUMP_FREQ=1440 (バックアップの分単位インターバル、1440だと1日に1回)
      - DB_DUMP_TARGET=s3://(R2上のバケット名)
      - DB_DUMP_FILENAME_PATTERN=(好きなファイル名)_{{.now}}.gz
    depends_on:
      - (DBコンテナ名)
    networks:
      - test-default
networks:
  test-default:
```

### 3 DockerComposeファイルをデプロイ
任意の方法でデプロイして実行します。
ちゃんと動いたら、下記のようなログがコンテナ内で出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/f800cbfa-b04e-345b-95c4-f6b0dadb5e3e.png)

少し待つと、作成した自分のR2 バケットにデータベースがアップロードされていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/962df6fa-cdca-8fe7-fcfe-ac5b571efcba.png)


### 4 バケットのライフサイクルルールを設定する (任意)
Cloudflare R2のバケット設定ページを開くと、ライフサイクルルールという便利な機能があります。設定すると、Cloudflare側で一定期間経過したオブジェクトを勝手に削除してくれるみたいです。(検証中) これがあればシェルスクリプトは書かなくても大丈夫そうです。

https://zenn.dev/kazu0617/articles/4a890a4a21f867#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254984/b4f22a68-a2ac-c84d-b489-0f085875c02f.png)

## その他 補足ポイント

### DockerComposeを書くとき苦戦したところ
  - R2を使う場合 AWS_ENDPOINT_URLの指定が必要
    - **DB_DUMP_TARGETに直接書けそうに見えますが動きません**
  - R2を使う場合 **AWS_REGIONにauto**を指定する
    - **Cloudflare R2のリージョンは auto しか存在しません**
  - DB_DUMP_TARGETは**バケット名からパスを指定**する
    - バケット名から始めないと 403が返されてバックアップに失敗する
  - DockerComposeで起動する場合は `command: dump` の指定が必要
    - デフォルトでは起動した瞬間ヘルプが出力されて即時終了します

### databack/mysql-dump の依存しているもの
  - S3の接続は aws-sdk-go-v2を使用
  - データベースのdumpは Go SQL Dump 0.6.0 を使用

### 出力されるファイルフォーマット
  - 先頭に専用のヘッダーが付いているものの、それを削れば平文のsql
  - そのまま 他のツールで リストアできるかは未検証

### 環境変数に直接トークンを書き込んでいいのか
環境変数に直接いれるのは推奨されおらず secretsを使う方が良さそうです。
(とはいえ ファイルとしてマウントされるようなので、ファイルベースでの設定に対応しているコンテナでないとダメかもしれません...)

https://qiita.com/myabu/items/89797cddfa7225ff2b5d

https://docs.docker.com/compose/how-tos/use-secrets/

## まとめ
- `databack/mysql-backup` というDockerコンテナを使うと簡単にDBを自動バックアップできました
- S3互換のオブジェクトストレージを使うと、設定にほんの少し苦戦しました