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

Kubernetes 发行版 — 自己搭

执行快照命令时才发现数据存储是 SQLite

在 TT Lab 中继续学习

目标

确认单台 k3s 服务器的存储是 SQLite(kine),了解 etcd 快照被拒绝的原因,然后通过 --cluster-init 重启迁移到内置 etcd。 把快照连同令牌一起备份,并用 --cluster-reset 恢复,记录快照之后的变更消失了,以及之前的数据保留在哪里。

为什么重要

k3s 以单台启动时,使用 SQLite 而不是 etcd。它轻量、快速,但多台服务器无法共享,而且 k3s etcd-snapshot 之类的 etcd 工具无法工作。 因此,直到“该接入备份了”的那天,才会第一次确认存储到底是什么,而此时的选择要么是整体复制文件的 SQLite 备份,要么是迁移到 etcd。 迁移到 etcd 只需重启一次,但恢复是“回到那个时间点”,所以快照之后创建的东西都会消失。而且没有服务器令牌,快照就毫无用处。 本实验让你在真实的 k3s 上把这三件事——确认存储、迁移、恢复所撤回的范围——各经历一遍。与一开始就使用 etcd 的 k0s 实验不同,这里处理的是更换存储的过程本身。

步骤

  1. 在命名空间 k3s-ds 中创建 ConfigMap marker(stage=sqlite)。然后在 /root/k3s-ds/datastore.json 中写入 datastore(sqlite 或 etcd)、db_files(/var/lib/rancher/k3s/server/db 中文件名排序后的数组)、kine_table(state.db 内的表名中 kine 使用的那一个)、kine_endpoint(k3s 日志中 Kine available at 之后的地址)、marker_uid(marker 的 UID)。
  2. 在当前状态下运行 k3s etcd-snapshot save,把标准输出和标准错误一起保存到 /root/k3s-ds/snapshot-refused.txt。然后在 /root/k3s-ds/sqlite-backup.txt 中,每行一个,写出备份 SQLite 存储需要复制的目录和文件的绝对路径。
  3. 在 /etc/rancher/k3s/config.yaml 中写入 cluster-init: true 并重启 k3s。确认 marker 仍然存在,并在 /root/k3s-ds/migrate.json 中写入 marker_uid(重启后 marker 的 UID)、sqlite_file_now(db 目录中原来的 state.db 被改成的名称)、node_roles(节点的 node-role.kubernetes.io/ 标签名称排序后的数组,例如:["control-plane"])、member_name(db/etcd/name 文件的内容)。
  4. 把 marker 的 stage 改为 snapshotted,然后用 k3s etcd-snapshot save --name lab-before 生成快照。在 /root/k3s-ds/snapshot.json 中写入 name(生成的完整快照名称)、path(文件绝对路径)、size(字节,整数)、sha256(文件的 SHA-256)。
  5. 把第 4 步的快照文件(同名)和服务器令牌文件(名为 token,权限 600)复制到 /root/k3s-ds/backup/ 目录。在 /root/k3s-ds/token-backup.json 中写入 token_source(令牌原件的绝对路径)、token_sha256(令牌文件的 SHA-256)、snapshot_sha256(所备份快照的 SHA-256)。令牌的值本身不要写在任何地方。
  6. 在快照之后,在命名空间 k3s-ds 中创建 ConfigMap after-snap(x=1),并把 marker 的 stage 改为 changed。在 /root/k3s-ds/after.json 中写入 after_uid(after-snap 的 UID)、after_created(它的 creationTimestamp)、marker_stage(当前 marker 的 stage)。
  7. 停止 k3s,用 k3s server --cluster-reset --cluster-reset-restore-path=<4단계 스냅숏 경로>(占位符为第 4 步的快照路径)进行恢复(把完整输出保存到 /root/k3s-ds/reset.log),然后重新启动 k3s。在 /root/k3s-ds/restore.json 中写入 old_dir(恢复时移动旧 etcd 数据所到的目录名)、restart_hint(reset.log 中 k3s 提示下一步该做什么的句子里,包含 restart without 的那部分之前的第一句)、after_snap_exists(布尔值)、marker_stage(恢复后 marker 的 stage)、member_name(恢复后 db/etcd/name 的内容)。
  8. 在 /root/k3s-ds/report.json 中写入 datastore_now(sqlite 或 etcd)、lost_objects(因恢复而消失的 ConfigMap 名称排序后的数组)、marker_stage(当前值)、snapshot_dir(保存快照的目录绝对路径)、restore_needs_token(在其他服务器上恢复时是否需要原来的令牌,布尔值)、member_name_changed(恢复前后 etcd 成员名称是否发生了变化,布尔值)。

参考

这个集群的存储是什么

在命名空间 k3s-ds 中创建 ConfigMap marker(stage=sqlite)。然后在 /root/k3s-ds/datastore.json 中写入 datastore(sqlite 或 etcd)、db_files(/var/lib/rancher/k3s/server/db 中文件名排序后的数组)、kine_table(state.db 内的表名中 kine 使用的那一个)、kine_endpoint(k3s 日志中 Kine available at 之后的地址)、marker_uid(marker 的 UID)。

k3s 不会把 SQLite 直接接到 API 服务器上,而是在中间放了一层模拟 etcd API 的 kine。请在日志中看 API 服务器的 --etcd-servers 指向什么。表名可以用 sqlite3 <파일> .tables(占位符为文件名)查看。

执行了快照命令,存储却是 SQLite

在当前状态下运行 k3s etcd-snapshot save,把标准输出和标准错误一起保存到 /root/k3s-ds/snapshot-refused.txt。然后在 /root/k3s-ds/sqlite-backup.txt 中,每行一个,写出备份 SQLite 存储需要复制的目录和文件的绝对路径。

etcd-snapshot 会向服务器发送请求,由服务器用内置 etcd 生成快照。如果存储是 SQLite,服务器就会拒绝,并把详细原因记录在服务器日志中。SQLite 不需要特殊命令,复制文件就能备份,但用于加密存储中机密数据的那个值也必须一并保管。

重启一次就迁移到 etcd

在 /etc/rancher/k3s/config.yaml 中写入 cluster-init: true 并重启 k3s。确认 marker 仍然存在,并在 /root/k3s-ds/migrate.json 中写入 marker_uid(重启后 marker 的 UID)、sqlite_file_now(db 目录中原来的 state.db 被改成的名称)、node_roles(节点的 node-role.kubernetes.io/ 标签名称排序后的数组,例如:["control-plane"])、member_name(db/etcd/name 文件的内容)。

用 cluster-init 启动原本以 SQLite 运行的服务器时,k3s 会把 SQLite 的内容迁移到 etcd。如果磁盘上已经有 etcd 数据,这个参数会被忽略。请在日志中找一找 Migrating content from sqlite to etcd。

给快照命名后生成

把 marker 的 stage 改为 snapshotted,然后用 k3s etcd-snapshot save --name lab-before 生成快照。在 /root/k3s-ds/snapshot.json 中写入 name(生成的完整快照名称)、path(文件绝对路径)、size(字节,整数)、sha256(文件的 SHA-256)。

--name 只决定名称的前半部分,k3s 会追加节点名称和时刻。保存位置是 --etcd-snapshot-dir 的默认值。k3s etcd-snapshot ls 和 kubectl get etcdsnapshotfile 显示的是同样的快照。

仅凭快照无法恢复

把第 4 步的快照文件(同名)和服务器令牌文件(名为 token,权限 600)复制到 /root/k3s-ds/backup/ 目录。在 /root/k3s-ds/token-backup.json 中写入 token_source(令牌原件的绝对路径)、token_sha256(令牌文件的 SHA-256)、snapshot_sha256(所备份快照的 SHA-256)。令牌的值本身不要写在任何地方。

k3s 用服务器令牌加密存储中的机密引导数据。如果用别的令牌恢复,快照就无法使用。复制时不要让权限变宽。

快照之后产生的东西

在快照之后,在命名空间 k3s-ds 中创建 ConfigMap after-snap(x=1),并把 marker 的 stage 改为 changed。在 /root/k3s-ds/after.json 中写入 after_uid(after-snap 的 UID)、after_created(它的 creationTimestamp)、marker_stage(当前 marker 的 stage)。

目的是观察下一步的恢复会如何处置这两者。为了在恢复之后还能确认这份记录是真实的,请准确写下 UID 和时刻。

恢复之后,快照之后的变更消失了

停止 k3s,用 k3s server --cluster-reset --cluster-reset-restore-path=<4단계 스냅숏 경로>(占位符为第 4 步的快照路径)进行恢复(把完整输出保存到 /root/k3s-ds/reset.log),然后重新启动 k3s。在 /root/k3s-ds/restore.json 中写入 old_dir(恢复时移动旧 etcd 数据所到的目录名)、restart_hint(reset.log 中 k3s 提示下一步该做什么的句子里,包含 restart without 的那部分之前的第一句)、after_snap_exists(布尔值)、marker_stage(恢复后 marker 的 stage)、member_name(恢复后 db/etcd/name 的内容)。

恢复是在服务停止的状态下,单独运行一次同一个二进制文件。结束后它会自行退出,并提示重新启动。旧数据不会被删除,而是被移到旁边。防止连续初始化的标记文件会先生成,待正常启动后再被删除。

什么保留了下来,什么消失了

在 /root/k3s-ds/report.json 中写入 datastore_now(sqlite 或 etcd)、lost_objects(因恢复而消失的 ConfigMap 名称排序后的数组)、marker_stage(当前值)、snapshot_dir(保存快照的目录绝对路径)、restore_needs_token(在其他服务器上恢复时是否需要原来的令牌,布尔值)、member_name_changed(恢复前后 etcd 成员名称是否发生了变化,布尔值)。

依据前面步骤的 json 以及当前的磁盘和集群来填写。评分器会从记录文件、etcd-old 目录和集群中重新计算同样的值。