目的
おうちでKubernetes運用していますか?
私はVPSを借りてKubernetesを運用しています。
しかし、kubernetesを運用していくなかで、なんどもOSを入れ直したり、インスタンスを作り直したりしたいが、アプリケーションのデータを失いたくない。そんなことはありませんか?
解決策
Google Driveに定期的に保存することを検討します。
Rclone
ローカルファイルをありとあらゆる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です。
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などでもバックアップするとより良いと考えられる
- それでも突然死などはカバーしきれないので注意が必要
 
 
- 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 として業務時間中に書きました。