k8s上にデプロイしたmisskeyの、DBおよびアップロードファイルのバックアップ方法について考える


以前k8sクラスタに導入したmisskeyだが、Twitterからの移行先としてお試しで使っているつもりが、普通にハマってしまった。 ということで今回は、NASの定期クラウドバックアップにmisskeyのデータを乗せる方法を考えてみる。

前提

  • misskey/postgre/redisはそれぞれk8s上にデプロイしており、データの永続化はNFSサーバで行っている
  • DBやmisskeyにアップロードしたファイルはNFSサーバ上の以下のパスに保存している
    • DB: /k8s/misskey/db
    • アップロードファイル: /k8s/misskey/files
  • redisのdumpファイル(dump.rdb)は以下のパスに保存されている
    • /k8s/misskey/redis

構成

postgreのデータはpg_dumpallして、dump_{timestamp}.tar.gzというファイル名でNFS上の/k8s/misskey/backupフォルダに保存。 アップロードファイルはfiles_{timestamp}.tar.gzというファイル名でアーカイブ&圧縮して、こちらも同じくNFS上の/k8s/misskey/backupフォルダに保存する。

上記を行うバッチをk8sのCronJobを利用して日次で実行する。

また、NAS側の設定で、1週間に一度行っているS3へのバックアップのスコープに/k8s/misskey/backupを含めるようにしておく。

利用しているS3 Glacier Deep Archiveは転送するファイル数毎の課金があるので、できる限り複数のファイルをまとめて圧縮しておく

redisはデフォルトで、定期的にdump.rdbを作成してくれるので、同様にバックアップのスコープに/k8s/misskey/redis/dump.rdbも含めておく。

マニフェストファイル

DBのダンプファイルとmisskeyにアップロードしたファイルをアーカイブして/k8s/misskey/backupに配置するCronJobのマニフェストファイルを作成する。

PV,PVC

CronJobで生成されるPod内で各種NFSのパスをマウントする必要があるので、そのためのPV,PVCを定義

misskey-backup-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv-misskey-backup
  namespace: nginx
spec:
  storageClassName: misskey-backup
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  nfs:
    server: {NFSのIP}
    path: /k8s/misskey/backup
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-misskey-backup
  namespace: nginx
spec:
  storageClassName: misskey-backup
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv-misskey-files-readonly
  namespace: nginx
spec:
  storageClassName: misskey-files-readonly
  capacity:
    storage: 10Gi
  accessModes:
  - ReadOnlyMany
  nfs:
    server: {NFSのIP}
    path: /k8s/misskey/files
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-misskey-files-readonly
  namespace: nginx
spec:
  storageClassName: misskey-files-readonly
  accessModes:
  - ReadOnlyMany
  resources:
    requests:
      storage: 10Gi

CronJob

続いて、CronJobを作成

backup-misskey-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: backup-misskey-cronjob
  namespace: nginx
spec:
  timeZone: 'Asia/Tokyo'
  schedule: "0 2 * * *" # Cronのスケジュールを設定(例: 毎日2時に実行)
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: backup-misskey-container
            image: postgres:latest # 使用するコンテナイメージを指定
            env:
            - name: PGPASSWORD
              value: {PGPASSWORD}
            imagePullPolicy: IfNotPresent
            command: ["/bin/bash", "-c", "/tmp/scripts/backup_misskey.sh"] # スクリプトのパスを指定
            volumeMounts:
            - name: nfs-files-volume
              mountPath: /tmp/misskey-files # NFSディレクトリをコンテナ内にマウント
            - name: nfs-backup-volume
              mountPath: /tmp/backup # NFSディレクトリをコンテナ内にマウント
            - name: scripts-volume
              mountPath: /tmp/scripts # ConfigMapをマウントするディレクトリ
          volumes:
          - name: nfs-files-volume
            persistentVolumeClaim:
              claimName: pvc-misskey-files-readonly
          - name: nfs-backup-volume
            persistentVolumeClaim:
              claimName: pvc-misskey-backup
          - name: scripts-volume
            configMap:
              name: backup-misskey-script-configmap
              defaultMode: 0777
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: backup-misskey-script-configmap
  namespace: nginx
data:
  backup_misskey.sh: |
    #!/bin/bash

    backup_dir="/tmp/backup/"
    existing_files=($(find "$backup_dir" -maxdepth 1 -type f -printf "%f\n"))

    # バックアップファイル名にタイムスタンプを付ける
    backup_files_path="${backup_dir}files_$(date +%Y%m%d%H%M%S).tar.gz"
    backup_dump_path="${backup_dir}dump_$(date +%Y%m%d%H%M%S).tar.gz"

    # tarでファイルを圧縮
    tar cvzfp "${backup_files_path}" /tmp/misskey-files

    # dbのダンプ
    pg_dumpall -h db.nginx.svc.cluster.local -p 5432 -U root > ${backup_dir}dump.sql
    tar cvzfp "${backup_dump_path}" /tmp/backup/dump.sql
    rm ${backup_dir}dump.sql

    for existing_file in "${existing_files[@]}"; do
      file_to_delete="${backup_dir}${existing_file}"
      rm "$file_to_delete"
      echo "削除されたファイル: $file_to_delete"
    done

結果

バックアップファイルが生成されていた。

[xxx@NAS backup]$ ls -al
-rw-r--r--    1 admin    administ    144.3M Aug  1 02:01 dump_20230731170001.tar.gz
-rw-r--r--    1 admin    administ      9.3M Aug  1 02:00 files_20230731170001.tar.gz

あとはこれがS3にバックアップされるのを待つだけ。