Kubernetes Cronjobの書き方　DB backup to S3


##Kubernetes

他社の運用例を知らないからこれが普通なのかわからないけど、うちはCloud FormationとEKSを使ってこんな形で運用してます。

jsonnet > compile > manifest yaml化 > deploy

Kubernetesに移行し始めて２ヶ月なのでまだまだ設定することが。


###今週のタスク
現在EC2のcrontabで走っているpython scriptをKubernetes cronjobに移行。

DB - Postgres, RDS -> s3 bucket



###Official Document
https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/
https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#cronjob-v1beta1-batch


###References

| # | Dockerfile            | Cloud | k8s | DB      | Storage   | Notes                   |
|-----|-----------------------|-------|------------|---------|-----------|-------------------------|
| 1   | alpine                | Azure | CronJob   | postgres | Azurefile |                         |
| 2   | alpine                | AWS   | N/A        | postgres | S3        |                         |
| 3   | alpine                | AWS   | CronJob   | mysql   | S3        | With slack notification |
| 4   | alpine Docker-compose | AWS   | N/A        | postgres | S3        |                         |


1. https://www.orange-networks.com/blogs/208-back-up-databases-using-kubernetes-cronjobs
https://github.com/rinormaloku/postgres-backup-container

2. https://github.com/Birne94/rds-s3-database-backup

3. https://sierrasoftworks.com/2017/11/01/scheduled-backups-with-k8s/
https://github.com/benjamin-maynard/kubernetes-s3-mysql-backup

4. https://github.com/schickling/dockerfiles/tree/master/postgres-backup-s3


これらの例はimage上にバックアップのスクリプトを走らせる形をとっているけど、自分達の用途には向いてない方法だと。なぜなら他にcronjobを設定した時に同じimageの再利用ができないから。

同僚曰くやり方は２つあって
１、Kubernetes Cronjob -> これを設定した。
２、Bitbucket Pipelineを使う。ただこれだとRDSへのSSH tunnelingが必要になるかも？と -> さっと関係のありそうなものを調べた

- https://bitbucket.org/site/master/issues/12753/allow-customers-to-connect-the-pipelines
- https://confluence.atlassian.com/bitbucket/test-with-databases-in-bitbucket-pipelines-856697462.html
- https://medium.com/athenian-engineering/setup-a-db-backup-system-in-5-minutes-using-bitbucket-pipelines-scheduler-f30736cc477
- https://confluence.atlassian.com/bitbucket/what-are-the-bitbucket-cloud-ip-addresses-i-should-use-to-configure-my-corporate-firewall-343343385.html

###Kubernetes Cronjob設定手順
１、現在のpython scriptのpg_dumpコマンドとs3へコピーしているコマンドを書き出す。

```
pg_dump postgres://<username>:<password>@<host>:<port>/<DB-name> -Fc -b -v -f <DB-name>-<date>

aws s3 mv <DB-name>-<date> s3://<bucket-name>
```

２、Docker Imageの作成
最初は以下を使ったけれど、awsコマンドが認識されなかった。
```RUN apk add --no-cache aws-cli --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing```

```
FROM alpine:3.7
RUN apk --no-cache update \
    && apk --no-cache add postgresql bash python py-pip py-setuptools \
    && pip --no-cache-dir install awscli \
    && rm -rf /var/cache/apk/*
```

３、cronjobの作成、オフィシャルと#1と#3を見ながら設定。

**ポイント**

a) ```args: ["/bin/bash", "/scripts/backup.sh"]```

b) ```restartPolicy: "OnFailure", <- requirement```


４、backup.sh.j2の原型を作成　

```
#!/bin/bash
{% set p = aaa %}
DUMP_FILE_NAME="`date +%Y-%m-%d-%H-%M`.dump"

{% for db in p.bbb.bbb %}
pg_dump postgres://{{db.user}}:{{db.password}}@{{db.host}}:{{db.port}}/{{db.dbname}} -Fc -b -v -f {{db.dbname}}-$DUMP_FILE_NAME
aws s3 mv {{db.dbname}}-$DUMP_FILE_NAME s3://{{p.ccc.ccc.s3_bucket}}
{% endfor %}
```

これに以下の前半部分を追加

https://github.com/benjamin-maynard/kubernetes-s3-mysql-backup/blob/master/resources/perform-backup.sh


###Useful commands

``` 
kubectl describe job
kubectl get cronjob <cronjob name>
kubectl get jobs --watch
```

###Log formatting

FROM

```
Database backup successfully completed for <DB name> at 09-08-2019 08:29:14.
Database backup successfully uploaded for <DB name> at 09-08-2019 08:29:19.
```

TO

``` 
09-08-2019 13:52:47 - [Success] <DB name> backup successfully completed.
09-08-2019 13:52:57 - [Success] <DB name> backup successfully uploaded to s3 bucket <bucket name>.
```

###Testing
各シナリオで試しました。

１、dashboard上でCronJobs > Trigger
２、Jobsから選んでLogsで確認

- スクリプト有無
- DB有無
- S３bucket有無
- Node上でもDiskSizeをBefore/Afterで確認
- IPが再利用されるか


###学んだこと

１、　kubernetes-apiの読み方

初心者にとってはkubernetes-apiとか読むのが結構怖いです。どこから手をつけていいかわからないから。

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#cronjob-v1beta1-batch

例えばcronjobを見ると以下が必要で、

- apiVersion
- kind
- metadata
- spec        
- status

さらに絞り込むとpodtemplatespecは他のSpecでも使われてることがわかる。

(e.g.) https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#podtemplatespec-v1-core

- DaemonSetSpec apps/v1
- JobSpec batch/v1
- PodTemplate core/v1等

２、　Jinja2の使い方、前にFlaskを勉強した時にさっと触れたものだけどイマイチ理解していなかった。shを中に入れることができるのはすごい便利。


###やりたいこと
Slack notificationの設定、Errorになった時のみNotifyするようにしたい。