使用 Kubernetes 检查点 API 进行容器的备份和恢复

云计算 云原生
在我们开始对任何容器进行检查点处理之前,我们需要一个 playgroud,在这个 playgroud 上我们可以操作 kubelet 和它的工作负载。为此,我们将需要一个支持容器检查点处理的 v1.25+ 版本的 Kubernetes集 群和容器运行时环境。

Kubernetes v1.25 引入了容器检查点 API 作为 alpha 特性。这提供了一种在不停止容器的情况下备份和恢复运行在 Pod 中的容器的方式。此功能主要用于调试分析,但任何 Kubernetes 用户都可以利用常规备份和恢复功能。

接下来,让我们来看看这个特性,并了解如何在我们的集群中启用它,并利用它进行备份和恢复或调试分析。

安装

在我们开始对任何容器进行检查点处理之前,我们需要一个 playgroud,在这个 playgroud 上我们可以操作 kubelet 和它的工作负载。为此,我们将需要一个支持容器检查点处理的 v1.25+ 版本的 Kubernetes集 群和容器运行时环境。

这里我们将使用在 Vagrant 中构建的虚拟机内使用 kubeadm 创建一个集群,我们将相关配置文件放到了 GitHub 仓库:https://github.com/MartinHeinz/kubeadm-vagrant-playground/tree/container-checkpoint-api 中,只需执行 vagrant up  即可快速启动该集群。

如果你想搭建自己的集群,请确保集群必须启用 ContainerCheckpoint 功能标志。对于 kubeadm 使用以下配置:

# kubeadm-config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
  ContainerCheckpoint: true
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.25.0
apiServer:
  extraArgs:
    feature-gates: "Cnotallow=true"
controllerManager:
  extraArgs:
    feature-gates: "Cnotallow=true"
scheduler:
  extraArgs:
    feature-gates: "Cnotallow=true"
networking:
  podSubnet: 10.244.0.0/16

这将向集群组件传递 --feature-gates 标志。此外,我们还需要使用支持检查点的容器运行时。撰写本文时,仅 CRI-O 支持它,而 Containerd 可能很快也会支持(https://github.com/containerd/containerd/pull/6965),最新版本的 crictl 已经支持通过 crictl checkpoint 创建检查点。

要使用 CRI-O 配置集群,请按照文档中的说明安装它,或者使用上述存储库中的脚本(你应该在虚拟机而不是本地运行此脚本)。

另外,我们还需要为 CRI-O 启用 CRIU,这是在后台执行实际检查点的工具。要启用它,我们需要设置 --enable-criu-support=true 标志。上面的脚本可以为你做到这一点。

另外,如果你打算将其恢复到 Pod 中,还需要将 --drop-infra-ctr 设置为 false,否则您将收到 CreateContainerError 并显示如下消息:

kubelet  Error: pod level PID namespace requested for the container, ...
... but pod sandbox was not similarly configured, and does not have an infra container

在安装了 CRI-O 之后,我们还需要告诉 kubeadm 使用它的 sock 文件,下面的配置将会处理这个问题:

apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.56.2
  bindPort: 6443
nodeRegistration:
  criSocket: "unix:///var/run/crio/crio.sock"
---

然后我们就可以使用以下命令快速启动集群:

kubeadm init --cnotallow=.../kubeadm-config.yaml --upload-certs | tee kubeadm-init.out

这将给我们提供一个单节点集群,如下(注意容器运行时版本):

$ kubectl get nodes -o wide
NAME         STATUS   ROLES           AGE   VERSION  ...  OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
kubemaster   Ready    control-plane   82s   v1.25.4  ...  Ubuntu 20.04.5 LTS   5.4.0-125-generic   cri-o://1.25.0

Checkpointing

集群安装完成后,我们可以尝试创建一个检查点。在 Kubernetes 上通常可以使用 kubectl 或者运行 curl 命令来执行常规操作,访问集群 APIServer。然而,在这里这样做是行不通的,因为检查点 API 只暴露在每个集群节点上的 kubelet 上。因此,我们必须前往节点上并直接与 kubelet 交互:

$ vagrant ssh kubemaster
$ sudo su -

# Check if it's running...
$ systemctl status kubelet

kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
  Drop-In: /etc/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) since Sat 2022-11-12 10:25:29 UTC; 30s ago
     Docs: https://kubernetes.io/docs/home/
 Main PID: 29501 (kubelet)
    Tasks: 14 (limit: 2339)
   Memory: 34.7M
   CGroup: /system.slice/kubelet.service
           └─29501 /usr/bin/kubelet --bootstrap-kubecnotallow=... --kubecnotallow=...

为了创建检查点,我们还需要一个正在运行的 Pod。让我们在 default 命名空间中创建一个 Nginx Pod:

$ kubectl taint nodes --all node-role.kubernetes.io/control-plane-
$ kubectl run webserver --image=nginx -n default
$ kubectl get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP          NODE
webserver   1/1     Running   0          27s   10.85.0.4   kubemaster

这里我们从节点中删除了污点,这样即使它是控制平面,我们也可以在节点上调度工作负载。

接下来,让我们向 kubelet 发出一个示例 API 请求,来查看是否正常:

$ curl -skv -X GET  "https://localhost:10250/pods" \
  --key /etc/kubernetes/pki/apiserver-kubelet-client.key \
  --cacert /etc/kubernetes/pki/ca.crt \
  --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt

{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {},
  "items": [
    {
      "metadata": {
        "name": "webserver",
        "namespace": "default",
        ...
        }
    }
    ...
}

kubelet 默认运行在端口 10250 上,因此我们使用 curl 命令并请求其所有的 Pod。我们还需要指定 CA 证书、客户端证书和密钥进行身份验证。

接下来就可以创建一个检查点了:

$ curl -sk -X POST  "https://localhost:10250/checkpoint/default/webserver/webserver" \
  --key /etc/kubernetes/pki/apiserver-kubelet-client.key \
  --cacert /etc/kubernetes/pki/ca.crt \
  --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt

# Response:
# {"items":["/var/lib/kubelet/checkpoints/checkpoint-webserver_default-webserver-2022-11-12T10:28:13Z.tar"]}

# Check the directory:
$ ls -l /var/lib/kubelet/checkpoints/

total 3840
-rw------- 1 root root 3931136 Nov 12 10:28 checkpoint-webserver_default-webserver-2022-11-12T10:28:13Z.tar

# Verify that original container is still running:
$ crictl ps --name webserver
CONTAINER      IMAGE                               CREATED         STATE    NAME       ATTEMPT  POD ID         POD
880ee7ddff7f3  docker.io/library/nginx@sha256:...  48 seconds ago  Running  webserver  0        d584446dd8d5e  webserver

检查点 API 位于 .../checkpoint/${NAMESPACE}/${POD}/${CONTAINER},这里我们使用之前创建的 Pod,此请求在 /var/lib/kubelet/checkpoints/checkpoint-<pod>_<namespace>-<container>-<timestamp>.tar 中创建了一个存档。

运行上述 curl 后,您可能会收到如下错误:

checkpointing of default/webserver/webserver failed (CheckpointContainer is only supported in the CRI v1 runtime API)
# or
checkpointing of default/webserver/webserver failed (rpc error: code = Unknown desc = checkpoint/restore support not available)

这意味着您的容器运行时尚不支持检查点功能,或者未正确启用。

分析

我们现在有了一个检查点容器存档,所以让我们看看里面有什么:

$ cd /var/lib/kubelet/checkpoints/
# Rename because "tar" doesn't like ":" in names
$ mv "checkpoint-webserver_default-webserver-2022-11-12T10:28:13Z.tar" webserver.tar
# View contents:
$ tar --exclude="*/*" -tf webserver.tar

dump.log
checkpoint/
config.dump
spec.dump
rootfs-diff.tar
io.kubernetes.cri-o.LogPath

# Extract:
$ tar -xf checkpoint-webserver_default-webserver-2022-09-04T10:15:37Z.tar
$ ls checkpoint/
cgroup.img        fdinfo-4.img  ids-31.img        mountpoints-13.img       pages-2.img               tmpfs-dev-139.tar.gz.img
core-1.img        files.img     inventory.img     netns-10.img             pages-3.img               tmpfs-dev-140.tar.gz.img
core-30.img       fs-1.img      ipcns-var-11.img  pagemap-1.img            pages-4.img               tmpfs-dev-141.tar.gz.img
core-31.img       fs-30.img     memfd.img         pagemap-30.img           pstree.img                tmpfs-dev-142.tar.gz.img
descriptors.json  fs-31.img     mm-1.img          pagemap-31.img           seccomp.img               utsns-12.img
fdinfo-2.img      ids-1.img     mm-30.img         pagemap-shmem-94060.img  timens-0.img
fdinfo-3.img      ids-30.img    mm-31.img         pages-1.img              tmpfs-dev-136.tar.gz.img


$ cat config.dump
{
  "id": "880ee7ddff7f3ce11ee891bd89f8a7356c97b23eb44e0f4fbb51cb7b94ead540",
  "name": "k8s_webserver_webserver_default_91ad1757-424e-4195-9f73-349b332cbb7a_0",
  "rootfsImageName": "docker.io/library/nginx:latest",
  "runtime": "runc",
  "createdTime": "2022-11-12T10:27:56.460946241Z"
}

$ tar -tf rootfs-diff.tar
var/cache/nginx/proxy_temp/
var/cache/nginx/scgi_temp/
var/cache/nginx/uwsgi_temp/
var/cache/nginx/client_temp/
var/cache/nginx/fastcgi_temp/
etc/mtab
run/nginx.pid
run/secrets/kubernetes.io/
run/secrets/kubernetes.io/serviceaccount/

如果您不需要一个正在运行的 Pod/容器进行分析,那么提取并阅读上面显示的一些文件可能会为您提供必要的信息。

恢复

虽然 Checkpointing API 目前更加注重于调试分析,但它仍然可以用于从存档中恢复 Pod/容器。最简单的方法是从检查点存档创建一个镜像:

FROM scratch
# Need to use ADD because it extracts archives
ADD webserver.tar .

这里我们使用一个空(scratch)镜像,然后向其添加归档文件。这里需要使用 ADD 命令,因为它会自动解压缩归档文件。接下来,我们使用 docker 或 buildah 构建它。

$ cd /var/lib/kubelet/checkpoints/
# Or docker build ...
$ buildah bud \
  --annotatinotallow=io.kubernetes.cri-o.annotations.checkpoint.name=webserver \
  -t restore-webserver:latest \
  Dockerfile .

$ buildah push localhost/restore-webserver:latest docker.io/martinheinz/restore-webserver:latest

在上面,我们还添加了一个注解,描述了容器的原始可读名称,然后我们将其推送到一些仓库,以便 Kubernetes 可以拉取它。最后,我们创建一个Pod,指定之前推送的镜像。

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: restore-webserver
  labels:
    app: nginx
spec:
  containers:
  - name: webserver
    image: docker.io/martinheinz/restore-webserver:latest
  nodeName: kubemaster

为了测试是否成功,我们可以通过 Service 将 Pod 暴露出来,并使用 curl 命令访问其IP地址。

$ kubectl expose pod restore-webserver --port=80 --target-port=80
$ kubectl get svc

NAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes          ClusterIP   10.96.0.1      <none>        443/TCP   14m
restore-webserver   ClusterIP   10.104.30.90   <none>        80/TCP    17s

$ curl http://10.104.30.90

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

可以看到生效了,我们成功地在不停止它的情况下备份了并恢复一个正在运行的 Pod。

总结

Kubernetes 的检查点功能是增强容器化应用程序容错性和弹性的强大工具。通过实施良好规划的检查点策略,你可以将停机时间降至最低,改善资源利用情况,并简化应用程序迁移。

优点

  • 增强的容错性——检查点功能使应用程序能够在故障发生时从最后一个已知检查点恢复,减少停机时间,并确保应用程序保持高可用性。
  • 简化迁移——检查点功能使将正在运行的应用程序移动到不同主机变得更加容易。通过保存应用程序的状态,您可以将其迁移到不同的节点,而不会丢失进度或造成中断。如果您的应用程序需要很长时间的预热,您可以利用这个功能。这将大大减少应用程序的启动时间。
  • 改进的扩展性——通过检查点功能,您可以轻松地扩展应用程序以满足波动的需求。如果一个节点过载了,您可以将应用程序迁移到拥有更多资源的另一个节点,确保最佳性能。
  • 高效的资源使用——检查点功能允许您暂停长时间运行的应用程序,释放资源给其他任务使用。当再次需要应用程序时,可以从检查点恢复。

Kubernetes 检查点的最佳实践

  • 定期创建检查点——根据应用程序的要求,定期创建检查点,以最小化在故障发生时的数据丢失。
  • 监控和管理资源——检查点功能可能消耗大量系统资源,尤其是内存。监控集群的资源使用情况,并根据需要调整检查点策略,以避免性能问题。
  • 测试您的检查点策略——定期测试您的检查点过程,确保其按预期工作,并能在故障发生时恢复应用程序。
  • 自动化检查点管理——使用像 cron 作业或 Kubernetes Operator 这样的自动化工具,在预定的时间表上创建和管理检查点,确保您的应用程序始终受到保护。

参考文档

  • https://martinheinz.dev/blog/85。
  • https://faun.pub/kubernetes-checkpointing-a-definitive-guide-33dd1a0310f6。
  • https://github.com/containerd/containerd/pull/6965。
  • https://github.com/MartinHeinz/kubeadm-vagrant-playground/tree/container-checkpoint-api。
责任编辑:姜华 来源: k8s技术圈
相关推荐

2017-02-23 09:30:27

Windows SerHyper-V虚拟机

2022-08-05 08:48:33

KubernetesEtcd数据

2017-03-07 16:41:03

LXD 2.0Linux实时迁移

2013-05-16 15:12:47

在线备份快照备份

2022-03-25 08:00:00

Kubernetes备份集群

2021-11-26 11:10:40

Kubernetes容器存储命令

2015-08-26 15:11:41

Docker容器备份Docker容器迁移

2011-08-24 10:21:39

CHECKPOINT中文man

2022-03-18 08:48:35

Kubernetes临时容器运维

2015-08-07 10:10:18

LinuxDocker容器

2022-01-14 07:56:38

Checkpoint机制Flink

2011-08-15 09:19:22

2022-06-10 18:59:53

容器Kubernetes

2023-12-11 18:15:46

AnsibleMinikubeKubernetes

2015-10-21 14:07:17

Oracle备份Oracle恢复

2022-09-07 09:19:49

Docker健康检查

2021-12-03 11:06:01

VeleroKubernetesLinux

2020-03-19 11:12:21

云计算KubernetesDocker

2021-09-13 10:27:34

云备份云恢复云计算

2011-07-22 15:20:37

Active Dire备份
点赞
收藏

51CTO技术栈公众号