Kubernetes環境でCronJobでMySQLを定期的にバックアップ

Kubernetes環境にMySQLのコンテナをデプロイした場合に、CronJobを使ってMySQLのバックアップを定期的に取得する方法を試したメモ。

MySQLのコンテナをデプロイするまでは以下を参照。

[ICPにMySQLに接続するLibertyアプリケーションをデプロイ](https://qiita.com/sotoiwa/items/8ff88d1742e2b6443835)

## 概要

![image.png](https://qiita-image-store.s3.amazonaws.com/0/86449/ea087448-bd03-24b7-b5e4-7295dbfbd420.png)

MySQLのコンテナとは別に、バックアップ取得のためのMySQL運用コンテナを定期的に起動してmysqldumpコマンドを実行し、コンテナにマウントしたPV上にバックアップを取得する。運用コンテナでmysqldumpコマンドを使うため、そちらもMySQLの公式イメージを使用する。

## PV/PVCの作成

hostPathで使うディレクトリを作成する。

```
root@myicp01:/export# pwd
/export
root@myicp01:/export# mkdir mysql-backup
root@myicp01:/export# ls -l
total 20
drwxrwxrwx  2 root root   4096 Jul 12 02:19 logstash
drwxr-xr-x 15 root root   4096 Jul 12 02:13 MC_jenkins02
drwxr-xr-x  3 root root   4096 Jul  4 07:15 MC_microclimate02
drwxr-xr-x  5  999 docker 4096 Jul 12 01:19 mysql
drwxr-xr-x  2 root root   4096 Jul 12 02:49 mysql-backup
root@myicp01:/export#
```

バックアップファイルを保管するPVを作成する。

```yaml:mysql-backup-pv-volume.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: mysql-backup-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/export/mysql-backup"
```

```
kubectl apply -f mysql-backup-pv-volume.yaml
```

PVCを作成する。

```yaml:mysql-backup-pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-backup-pv-claim
  namespace: ns3
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
```

```
kubectl apply -f mysql-backup-pv-claim.yaml
```

確認する。

```
# kubectl get pvc -n ns3
NAME                    STATUS    VOLUME                   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-backup-pv-claim   Bound     mysql-backup-pv-volume   10Gi       RWO            manual         1m
mysql-pv-claim          Bound     mysql-pv-volume          10Gi       RWO            manual         2d
#
```

## 単発のバックアップ

まずは単発でバックアップを行うJobを作成する。

```yaml:mysql-backup-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: mysql-backup
  namespace: ns3
spec:
  template:
    spec:
      containers:
      - image: mysql:5.6
        name: mysql-backup
        volumeMounts:
        - name: mysql-backup-persistent-storage
          mountPath: /backup
        command: ["/bin/sh"]
        args: ["-c", "/usr/bin/mysqldump -u root -ppassword -h mysql mydb > /backup/mydb.dump"]
      restartPolicy: Never
      volumes:
      - name: mysql-backup-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-backup-pv-claim
  backoffLimit: 4
```

```
kubectl apply -f mysql-backup-job.yaml
```

Jobが成功してバックアップファイルができていることを確認。

```
# kubectl get jobs -n ns3
NAME           DESIRED   SUCCESSFUL   AGE
mysql-backup   1         1            4m
#
```

```
# ls -l /export/mysql-backup/
total 4
-rw-r--r-- 1 root root 2121 Jul 12 03:25 mydb.dump
#
```

## 接続情報を外部化

ユーザーとパスワードを直に書いてしまっているので、ConfigMap/Secretから取得するように変更する。Libertyからの接続用に作成済みの以下のConfigMap/Sercretを使う。

```yaml:liberty-mysql-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: liberty-mysql-secret
  namespace: ns3
type: Opaque
data:
  libertyPassword: bGliZXJ0eQ==
```

```yaml:liberty-mysql-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: liberty-mysql-config
  namespace: ns3
data:
  MYSQL_SERVERNAME: "mysql"
  MYSQL_PORTNUMBER: "3306"
  MYSQL_USER: "liberty"
```

環境変数経由で取得するように変更。

```yaml:mysql-backup-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: mysql-backup
  namespace: ns3
spec:
  template:
    spec:
      containers:
      - image: mysql:5.6
        name: mysql-backup
        env:
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: liberty-mysql-secret
              key: libertyPassword
        - name: MYSQL_USER
          valueFrom:
            configMapKeyRef:
              name: liberty-mysql-config
              key: MYSQL_USER
        - name: MYSQL_SERVERNAME
          valueFrom:
            configMapKeyRef:
              name: liberty-mysql-config
              key: MYSQL_SERVERNAME
        volumeMounts:
        - name: mysql-backup-persistent-storage
          mountPath: /backup
        command: ["/bin/sh"]
        args: ["-c", "/usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASSWORD} -h${MYSQL_SERVERNAME} mydb > /backup/mydb.dump"]
      restartPolicy: Never
      volumes:
      - name: mysql-backup-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-backup-pv-claim
  backoffLimit: 4
```

## CronJob

CronJobを使って定期的にバックアップを取得する。

```yaml:mysql-backup-cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: mysql-backup
  namespace: ns3
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - image: mysql:5.6
            name: mysql-backup
            env:
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: liberty-mysql-secret
                  key: libertyPassword
            - name: MYSQL_USER
              valueFrom:
                configMapKeyRef:
                  name: liberty-mysql-config
                  key: MYSQL_USER
            - name: MYSQL_SERVERNAME
              valueFrom:
                configMapKeyRef:
                  name: liberty-mysql-config
                  key: MYSQL_SERVERNAME
            volumeMounts:
            - name: mysql-backup-persistent-storage
              mountPath: /backup
            command: ["/bin/sh"]
            args: ["-c", "/usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASSWORD} -h${MYSQL_SERVERNAME} mydb > /backup/mydb.dump"]
          restartPolicy: Never
          volumes:
          - name: mysql-backup-persistent-storage
            persistentVolumeClaim:
              claimName: mysql-backup-pv-claim
```

```
kubectl apply -f mysql-backup-cronjob.yaml
```

1分毎にJobが作成され、バックアップが更新されていることを確認する。

```
# kubectl get cronjobs -n ns3
NAME           SCHEDULE      SUSPEND   ACTIVE    LAST SCHEDULE   AGE
mysql-backup   */1 * * * *   False     0         13s             4m
# kubectl get jobs -n ns3
NAME                      DESIRED   SUCCESSFUL   AGE
mysql-backup-1531367640   1         1            2m
mysql-backup-1531367700   1         1            1m
mysql-backup-1531367760   1         1            18s
# kubectl get po -n ns3
NAME                            READY     STATUS      RESTARTS   AGE
hellomysql-5564fcdfc6-hcrg6     1/1       Running     2          2d
mysql-774b87bc4c-672b5          1/1       Running     2          2d
mysql-backup-1531367640-gnnc9   0/1       Completed   0          2m
mysql-backup-1531367700-g4btp   0/1       Completed   0          1m
mysql-backup-1531367760-2k85b   0/1       Completed   0          34s
# ls -l /export/mysql-backup/
total 4
-rw-r--r-- 1 root root 2121 Jul 12 03:56 mydb.dump
#
```

## メモ

Jobによって作成されたPodのメンテナンスや失敗時の動作や監視など要検討。

## 参考資料

[Jobs - Run to Completion](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/)

[Running automated tasks with cron jobs](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/)

[Define a Command and Arguments for a Container](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/)

[kubernetes1.4 で実装された ScheduledJob を試してみた！](https://jedipunkz.github.io/blog/2016/11/03/kubernetes-scheduledjob/)

[CronJob(ScheduledJob)](https://qiita.com/koudaiii/items/000724c27e65be2d4484)

[mysqldumpまとめ](https://qiita.com/PlanetMeron/items/3a41e14607a65bc9b60c)