TT Lab
开始
学习 学习路径 课程

Kubernetes 发行版 — 自己搭

k3s 的数据存储从 SQLite 开始

在 TT Lab 中继续学习

一句话总结

一台 k3s 服务器默认通过 kine 使用 SQLite,所以 etcd 快照无法工作;用 --cluster-init 重启后,数据会被保留并迁移到内置 etcd;恢复 etcd 快照必须有服务器令牌,并且会撤回快照之后的所有变更。

为什么需要它

Kubernetes API 服务器在设计上是把状态保存在 etcd 中的。然而 etcd 是为了法定人数(quorum)而以多台节点为前提设计的分布式存储,对于一台树莓派或在 CI 中临时使用的集群来说太重了。 k3s 用 kine 弥合了这个差距。kine 是一个模拟 etcd API 的薄薄一层,后面可以接 SQLite、MySQL、PostgreSQL 等普通数据库。实测查看日志,API 服务器以 --etcd-servers=unix://kine.sock 启动,而 k3s 会先宣告 Kine available at unix://kine.sock。 官方文档写道,SQLite 是在没有其他存储配置、磁盘上也没有内置 etcd 数据时使用的默认值,并且不能用于多台服务器的集群。

问题在于这个默认值是悄无声息的。集群运行得好好的,直到想要接入备份的那天才会暴露出来。

$ k3s etcd-snapshot save
level=fatal msg="Error: see server log for details: etcd datastore disabled"

这是实测输出。服务器日志中同样的提示以 HTTP 400 响应的形式保留下来。快照命令向 k3s 服务器发出了请求,服务器以“我不使用 etcd”为由拒绝了它。

工作原理

SQLite 时的备份没有专门的命令。按照文档,复制 /var/lib/rancher/k3s/server/db/,恢复时把其内容放回去。此时必须同时保管服务器令牌文件 /var/lib/rancher/k3s/server/token。令牌用于加密存储中的机密数据,所以如果用别的令牌恢复,这份备份就无法使用。

迁移到 etcd 只需要用 --cluster-init 重新启动原本以 SQLite 运行的服务器即可。实测结果如下。

config.yaml 에 cluster-init: true → systemctl restart k3s (API 준비 12초)
로그     Migrating content from sqlite to etcd
디스크   db/state.db → db/state.db.migrated, db/etcd/ 와 db/snapshots/ 생성
노드     node-role.kubernetes.io/etcd=true 가 붙음
데이터   재시작 전에 만든 ConfigMap 의 UID 가 그대로

该代码块中的韩文说明依次为:在 config.yaml 中加入 cluster-init: true 后重启 k3s(API 12 秒后就绪);日志出现从 sqlite 向 etcd 迁移内容的提示;磁盘上 db/state.db 被改名为 db/state.db.migrated,并生成 db/etcd/ 与 db/snapshots/;节点上被加上 node-role.kubernetes.io/etcd=true;重启前创建的 ConfigMap 的 UID 保持不变。

反方向不存在。文档写道,如果在磁盘上发现了 etcd 数据,--cluster-init、--server、--datastore-endpoint 这类存储参数都会被忽略。这意味着一旦变成 etcd,即使去掉参数也不会回到 SQLite。

快照有定期和手动两种。定期快照默认在 0 点和 12 点(0 */12 * * *)生成,保留 5 个,名称为 etcd-snapshot-<노드>-<시각>(占位符依次为节点名和时刻)。手动快照通过 k3s etcd-snapshot save 生成,没有保留数量的限制,需要自己删除,--name 只决定名称的前半部分。两者都保存在 --etcd-snapshot-dir 的默认值,即数据目录下的 db/snapshots 中,实测路径为 /var/lib/rancher/k3s/server/db/snapshots/lab-before-<노드>-<유닉스시각>(占位符依次为节点名和 Unix 时间)。kubectl get etcdsnapshotfile 会把整个集群的快照显示为对象。

恢复需要停止服务,然后单独运行一次同一个二进制文件。

systemctl stop k3s
k3s server --cluster-reset --cluster-reset-restore-path=/var/lib/rancher/k3s/server/db/snapshots/<이름>
# Managed etcd cluster membership has been reset, restart without --cluster-reset flag now.
systemctl start k3s

恢复不会删除当前的 etcd 数据,而是先把它移到 db/etcd-old-<시각>(占位符为时刻),再解开快照,并去掉其他所有成员,使其成为只有自己的集群。为了防止连续初始化,会创建 db/reset-flag,正常启动后再把它删除。如果只给 --cluster-reset 而不给 --cluster-reset-restore-path,则只会重置成员关系,而不会恢复快照。

在现场相遇的样子

实测中,先生成了快照,然后创建一个 ConfigMap 并修改另一个的值,再进行恢复。新创建的那个消失了,值回到了快照时的状态。消失的对象的 UID 仍然以字节的形式保留在 etcd-old-<시각>(占位符为时刻)里的旧数据文件中——恢复不会删除旧数据,就是这样得到确认的。etcd 成员名称(db/etcd/name)也被重新赋了一个与恢复前不同的值。

现场常见的事故有两种。一种是“恢复之后,昨天部署的东西没了”。恢复是回溯,如果不先确认快照之后有谁做了什么,就会变成第二次故障。另一种是只把快照搬到新服务器上想要恢复,结果失败。文档写道,在其他主机上恢复时,必须用 --token 传入原服务器的令牌。如果快照在对象存储中,而令牌只在已经消失的节点的磁盘上,那这份备份就无法使用。

实际工作中真正重要的事

下一项实验要做什么

在 VM 中的 k3s 上,通过 kine 日志和表确认存储是 SQLite,并记录快照被拒绝的情况。通过 cluster-init 重启迁移到 etcd,查看标记 ConfigMap 的 UID 是否保留;把命名的快照连同令牌一起备份,然后制造快照之后的变更并进行恢复,确认什么消失了、又保留在哪里。

参考文档:Cluster Datastore · High Availability Embedded etcd · etcd-snapshot · Backup and Restore