takutakahashi.dev

Kubernetes Native な zfs レプリケーションツール z8r を作った

こんにちは。zfs 便利ですね。
Kubernetes と連携して便利に replication を実行してくれる z8r というものを作りました。

https://github.com/takutakahashi/z8r

z8r とは、zfs-on-kube replication の略称です。こじつけです。

zfs におけるバックアップの重要性

zfs でデータを補完しているときに気になるのが、Pool/Dataset のバックアップです。
データを保管する媒体として RAID やスナップショットによる保全だけでなく、バックアップを取るべきなのは言うまでもありません。
また、zfs 特有の問題として、Pool/Dataset の削除時にプロンプトが確認をしない、
raidz や raidz2 構成の Pool を構成するデバイスの数を増減できないなどなど、
Pool の削除に対するバリデーションが少なかったり、Pool 自体を作成し直したくなるオペレーションも実は多かったりします。

そのため、カジュアルに別 Pool にバックアップを取ることのできるツールが必要となります。

zfs レプリケーションツールの先行事例

では先人たちはどうやってレプリケーションを取っているかというと、
実はデファクトスタンダードなツールは存在しない状態です。
zfs は標準で zfs send/recv という機能を持っており、
zfs send tank/data1 | zfs recv tank2/data1 という具合に
Pool/Dataset を標準出力を介して送受信できるインターフェースを持っています。

そのため、各自 cron で頑張るか、 FreeNAS などのディストリビューションに付録する機能を利用することが多いようです。
また、以下のように統合ツールを作成する事例も存在します。

https://github.com/zrepl/zrepl

z8r 開発の動機

僕は zfs Pool を Kubernetes Node 上に構築しています。
用途は、pvc の切り出し元、長期保存データの置き場所など、多岐にわたっています。
そのため、データライフサイクルが Pool の中でも異なるという特性があります。

zfs を replication するデファクトスタンダードが存在しない状態であることと、
今までの事例ではコンピュートノードに直接ツールセットをインストールして動作させることを前提としたアーキテクチャが多いため、
Kubernetes 上で動作させるならもっとうまいやり方があると思い、
z8r を開発しました。

利用方法

利用するためには、以下の条件が整っていることが必要です。

  • privileged が利用できる Kubernetes クラスタがあること
  • Node に zfs Pool が構築済みであること
  • 各ノードは同名の Pool を持っていること

1. インストール

リポジトリに manifest を置いてあるので、一発でインストールできます。

git clone https://github.com/takutakahashi/z8r
cd z8r/deploy
kubectl apply -f .

2. ノードにラベルとアノテーションを付ける

zfs Pool を持つノードに対し、ラベルを付与します。

kubectl label node node01 zfs.replication.takutakahashi.dev=true

レプリケーションを行う Dataset を持つノードの組をアノテーションで表現します。

# master node に付与するアノテーション
zfs.replication.takutakahashi.dev/master=tank/dataset1,tank/dataset2

# replica node に付与するアノテーション
zfs.replication.takutakahashi.dev/replica=tank/dataset1,tank/dataset2

アノテーションを付与すると、まもなく replication が開始されます。

機能

以下の機能を持っています。

1. replication 実行

アノテーションで表現した戦略を元に replication を実行します。

2. snapshot 定期作成

master dataset を持つノードは、dataset に対して snapshot を作成します。
6時間ごとに1つの snapshot を作成し、replica に転送します。

アーキテクチャ

image

daemon Pod と replicator Pod 2つから構成されます。
replicator は、ssh を介して daemon 上で zfs コマンドを実行します。
replicator は起動時に private key を作成し、public key を配信するための nginx をバックグラウンドで起動します。
daemon は replicator に対し http GET することで public key を取得し、 replicator - daemon 間で ssh を可能にします。(黒線)

daemon は Kubernetes API を実行し、自身が master となる dataset の snapshot を取得し、
replicator は 各 daemon の IP や dataset の配置状況を Kubernetes API から取得、
ssh 越しに zfs send/recv を実行し replication を行います。(赤線)

効果

この実装をしたことで、同じ Pool 上にデータライフサイクルの異なる dataset を置くことができるようになりました。
例えば、 SSD で構成された Pool の上に、高速な NAS を実現するためのデータ置き場と Ceph OSD を配置する pvc を同居させる場合を考えます。
この場合、 NAS のデータ置き場は snapshot + replication が必要であるけども、
pvc は Ceph 上でデータ冗長が取られているため、 snapshot, replication どちらも必要ありません。
z8r のおかげで、NAS のデータだけ replication することができました。最高。

今後の展望

今後は、tier を意識した構成も取れるように改良していきます。
例えば、NAS のバックアップ先を名前の異なる HDD Pool に構成できるようにしたり、Multi Replica を実現できるような構成です。
さらに Kubernetes 上で zfs を便利に活用できるように実装していきたいと思います。