Edited at
Z LabDay 24

おうちkubernetesでデータを永続化する

More than 1 year has passed since last update.


目的

おうちでKubernetes運用していますか?

私はVPSを借りてKubernetesを運用しています。

しかし、kubernetesを運用していくなかで、なんどもOSを入れ直したり、インスタンスを作り直したりしたいが、アプリケーションのデータを失いたくない。そんなことはありませんか?


解決策

Google Driveに定期的に保存することを検討します。


Rclone

https://rclone.org/

ローカルファイルをありとあらゆるSaaSに同期できるツール

これをサイドカーに入れて、定期的にデータをバックアップすることを考えます。


Secret作成

Rcloneは、同期先の情報をconfigファイルとして与えることができます。

この中には認証情報なども含まれるためKubernetesのSecretリソースとして用意するのが良さそうです。

rclone config コマンドで対話形式でコンフィグファイルを作ることができます。

手元のマシンにrcloneをインストールしても良いのですが、今回はdockerでやってみました。

$ mkdir config

$ docker run --rm -v `pwd`/config:/config -t -i tynor88/rclone:latest rclone config --config=/config/.rclone.conf

[s6-init] making user provided files available at /var/run/s6/etc...exited 0.
[s6-init] ensuring user provided files have correct perms...exited 0.
[fix-attrs.d] applying ownership & permissions fixes...
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 10-adduser: executing...

GID/UID
-------------------------------------
User uid: 911
User gid: 911
-------------------------------------

[cont-init.d] 10-adduser: exited 0.
[cont-init.d] 40-config: executing...
crontab => 0 * * * * /app/rclone.sh
chmod: /config/Rclone.sh: No such file or directory
[cont-init.d] 40-config: exited 0.
[cont-init.d] done.
[services.d] starting services
crond[199]: crond (busybox 1.24.2) started, log level 0
crond[199]: user:root entry:*/15 * * * * run-parts /etc/periodic/15min
crond[199]: user:root entry:0 * * * * run-parts /etc/periodic/hourly
crond[199]: user:root entry:0 2 * * * run-parts /etc/periodic/daily
crond[199]: user:root entry:0 3 * * 6 run-parts /etc/periodic/weekly
crond[199]: user:root entry:0 5 1 * * run-parts /etc/periodic/monthly
crond[199]: user:abc entry:0 * * * * /app/rclone.sh
[services.d] done.
No remotes found - make a new one
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n
name> hoge
Type of storage to configure.
Choose a number from below, or type in your own value
1 / Amazon Drive
\ "amazon cloud drive"
2 / Amazon S3 (also Dreamhost, Ceph, Minio)
\ "s3"
3 / Backblaze B2
\ "b2"
4 / Dropbox
\ "dropbox"
5 / Encrypt/Decrypt a remote
\ "crypt"
6 / Google Cloud Storage (this is not Google Drive)
\ "google cloud storage"
7 / Google Drive
\ "drive"
8 / Hubic
\ "hubic"
9 / Local Disk
\ "local"
10 / Microsoft OneDrive
\ "onedrive"
11 / Openstack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
\ "swift"
12 / Yandex Disk
\ "yandex"
Storage> 7
Google Application Client Id - leave blank normally.
client_id>
Google Application Client Secret - leave blank normally.
client_secret>
Remote config
Use auto config?
* Say Y if not sure
* Say N if you are working on a remote or headless machine or Y didn't work
y) Yes
n) No
y/n> N

config/.rclone.conf が出来上がるので、kubernetesにsecretとしてデプロイします。

$ kubectl create secret generic rclone-config --from-file=./config/.rclone.conf


Rclone定期実行

rcloneを定期実行するDockerイメージがあります。今回はこれを使います。

https://hub.docker.com/r/tynor88/rclone/


デプロイ

今回は例として、gollum(gitをバックエンドとするwiki) をデプロイし、そのデータをGoogleDriveに同期してみます。

初回起動時は以前保存していたものを復元するために GoogleDrive -> Pod で同期を行います。

これはpod.spec.initContainersで実現しています。 ( https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ )

起動中はgollumとは別にrcloneのコンテナを動作させて、定期的に Pod -> GoogleDrive で同期を行います。

図にするとこんな感じ。

以下がmanifest上記を実現するmanifestです。


gollum-with-rclone.yaml

apiVersion: extensions/v1beta1

kind: Deployment
metadata:
labels:
run: gollum
name: gollum
namespace: default
spec:
selector:
matchLabels:
run: gollum
template:
metadata:
labels:
run: gollum
spec:
initContainers: # gollumのために、git initを初めにしておく
- name: init
image: golang:latest # gitがあればなんでも良い
command:
- sh
- -c
- cd /root/wikidata && git init
volumeMounts:
- mountPath: /root/wikidata
name: data
- name: first-rclone
image: tynor88/rclone:latest
command: # rclone初回実行 (GoogleDrive -> Pod)
- sh
- -c
- /usr/bin/with-contenv sh /app/rclone.sh
env:
- name: SYNC_COMMAND
value: rclone sync GoogleDrive:/gollum /data
volumeMounts:
- mountPath: /data
name: data
- mountPath: /root
name: config
containers:
- name: gollum
image: suttang/gollum:latest # 本命のgollumイメージ
volumeMounts:
- mountPath: /root/wikidata
name: data
- name: rclone
image: tynor88/rclone:latest # 同期用のrclone (Pod -> GoogleDrive)
imagePullPolicy: Always
env:
- name: SYNC_DESTINATION
value: GoogleDrive
- name: SYNC_DESTINATION_SUBPATH
value: gollum
- name: CRON_SCHEDULE
value: 0 * * * *
volumeMounts:
- mountPath: /data
name: data
- mountPath: /config
name: config
volumes:
- name: data # wikiのデータを入れる
emptyDir: {}
- name: config # secretからConfigを読み出す
secret:
defaultMode: 511 # 雑に0777
secretName: rclone-config

クラスタにデプロイするためには下記を実行します。

$ kubectl apply -f gollum-with-rclone.yaml

できたー!


注意


  • 定期実行によるバックアップなので、その隙間の変更はバックアップされない。


    • preStopなどでもバックアップするとより良いと考えられる


      • それでも突然死などはカバーしきれないので注意が必要





  • replicaを1以上にすることは想定していません(おうちなので)


    • その場合はアプリケーションとデータを分離して、データのバックアップをGoogleDriveにSyncするなどさらなる工夫が必要そうです。




まとめ

おうちでKubernetesクラスタを構築する際に問題となるデータの永続化について、Rcloneを用いた、GoogleDriveへの定期バックアップスクリプトを紹介しました。

ファイルであればなんでも同期できるため、どんなデータでも永続化できることが特徴です。

Kubernetesは変化が早いため、常に最新のKubernetesの環境が手元にあるのは非常に良い勉強になるため、おうちKubernetesクラスタ、おすすめです。

(Raspberry piを使ったKubernetesの構築方法も紹介していますので、こちらも参考にしてみてください https://qiita.com/hatotaka/items/48a88ecb190e1f5e03c3 )

このエントリは、Z Lab のメンバーによる Z Lab Advent Calendar 2017 として業務時間中に書きました。