百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Kubernetes暴力删除(rm -rf)与无影响恢复

nanshan 2024-10-17 11:14 19 浏览 0 评论

新钛云服 祝祥 翻译

介绍

Kubernetes(k8s)是Google开源的容器集群管理系统(谷歌内部:Borg)。在容器技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。

Kubernetes是一个完备的分布式系统支撑平台,具有完备的集群管理能力,多扩多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和发现机制、內建智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制以及多粒度的资源配额管理能力。同时Kubernetes提供完善的管理工具,涵盖了包括开发、部署测试、运维监控在内的各个环节。

Kubernetes是一个全新的基于容器技术的分布式架构领先方案,是最佳的容器编排平台。最近,Kubernetes在功能,安全性和弹性方面取得了长足的进步。Kubernetes体系架构使您可以轻松地从各种故障中快速安全的恢复。在本文中,我们也将进行集群的破坏性操作:人为损坏集群,删除证书,重新加入业务节点。最终的目的是为了通过这些破坏性操作,而不会造成已经正常运行的服务停机甚至数据丢失。

集群故障模式的一般性概述

下面是一个不完整的列表,列举了一些可能的出错场景,以及通过调整集群配置来解决相关问题的方法。

  • VM(s) 关机
  • 集群之间,或者集群和用户之间网络分裂
  • Kubernetes 软件本身崩溃
  • 数据丢失或者持久化存储不可用(如:GCE PD 或 AWS EBS 卷)
  • 操作错误,如:Kubernetes 或者应用程序配置错误

同时以下也列出了官网所给出的常规故障详情以及导致的后果:

  • API 服务器所在的 VM 关机或者 API 服务器崩溃结果不能停止、更新或者启动新的 Pod、服务或副本控制器现有的 Pod 和服务在不依赖 Kubernetes API 的情况下应该能继续正常工作
  • API 服务器的后端存储丢失结果API 服务器应该不能启动kubelet 将不能访问 API 服务器,但是能够继续运行之前的 Pod 和提供相同的服务代理在 API 服务器重启之前,需要手动恢复或者重建 API 服务器的状态
  • Kubernetes 服务组件(节点控制器、副本控制器管理器、调度器等)所在的 VM 关机或者崩溃当前,这些控制器是和 API 服务器在一起运行的,它们不可用的现象是与 API 服务器类似的将来,这些控制器也会复制为多份,并且可能不在运行于同一节点上它们没有自己的持久状态
  • 单个节点(VM 或者物理机)关机结果此节点上的所有 Pod 都停止运行
  • 网络分裂结果分区 A 认为分区 B 中所有的节点都已宕机;分区 B 认为 API 服务器宕机 (假定主控节点所在的 VM 位于分区 A 内)。
  • kubelet 软件故障结果崩溃的 kubelet 就不能在其所在的节点上启动新的 Podkubelet 可能删掉 Pod 或者不删节点被标识为非健康态副本控制器会在其它的节点上启动新的 Pod
  • 集群操作错误结果丢失 Pod 或服务等等丢失 API 服务器的后端存储用户无法读取API等等

Kubernetns破坏(rm -rf)

因此,现在让我们开始进行验证。Kubernetes主控制平面仅包含以下几个组件:

  • etcd —Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划
  • kube-apiserver — 作为Kubernetes系统的入口,其封装了核心对象的增删改查操作,以RESTful API接口方式提供给外部客户和内部组件调用。维护的REST对象持久化到Etcd中存储
  • kube-controller-manager —负责执行各种控制器,目前已经提供了很多控制器来保证Kubernetes的正常运行
  • kube-scheduler —为新建的Pod进行节点(node)选择(即分配机器),负责集群的资源调度。组件抽离,可以方便替换成其他调度器。
  • kubelet —负责管控容器,Kubelet会从Kubernetes API Server接收Pod的创建请求,启动和停止容器,监控容器运行状态并汇报给Kubernetes API Server
  • kube-proxy—负责为Pod创建代理服务,Kubernetes Proxy会从Kubernetes API Server获取所有的Service信息,并根据Service的信息创建代理服务,实现Service到Pod的请求路由和转发,从而实现Kubernetes层级的虚拟转发网络

这些组件中的每一个都受到一组针对客户端和服务器的TLS证书的保护。它们用于对彼此之间的组件进行身份验证和授权。除某些情况外,它们并没有存储在Kubernetes数据库中,而是以常规文件的形式进行保存:

# tree /etc/kubernetes/pki/
/etc/kubernetes/pki/
├── apiserver.crt
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
├── apiserver.key
├── apiserver-kubelet-client.crt
├── apiserver-kubelet-client.key
├── ca.crt
├── ca.key
├── CTNCA.pem
├── etcd
│   ├── ca.crt
│   ├── ca.key
│   ├── healthcheck-client.crt
│   ├── healthcheck-client.key
│   ├── peer.crt
│   ├── peer.key
│   ├── server.crt
│   └── server.key
├── front-proxy-ca.crt
├── front-proxy-ca.key
├── front-proxy-client.crt
├── front-proxy-client.key
├── sa.key
└── sa.pub

静态 Pod 直接由特定节点上的kubelet进程来管理,不通过 master节点上的apiserver。无法与我们常用的控制器Deployment或者DaemonSet进行关联,它由kubelet进程自己来监控,当pod崩溃时重启该pod,kubelete也无法对他们进行健康检查。静态pod 始终绑定在某一个kubelet,并且始终运行在同一个节点上。 kubelet会自动为每一个静态 pod 在 Kubernetes 的apiserver 上创建一个镜像 Pod(Mirror Pod),因此我们可以在 apiserver 中查询到该 pod,但是不能通过apiserver 进行控制(例如不能删除)。 创建静态 Pod 有两种方式:配置文件和 HTTP 两种方式。而kubernetns的静态 Pod 清单的路径是/etc/kubernetes/manifests。正常安装的kubernetns集群,相关组件的静态Pod清单已经包含在该目录,故可自动运行。

关于这一点,本处我们不做详细介绍,因为这是额外的话题,且内容很多,如果需要详细了解,可以查看官网文档(https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/)。在我们的案例中,我们主要对集群的配置管理,组件管理以及相关的其他组件管理感兴趣。但是首先,让我们稍微聚焦一下,假设我们拥有上述正常运行的Kubernetes所有组件,并且它们以某种方式相互交互通信。

通常,kubernetns组件交互方式如下所示:

对于通信,它们都需要TLS证书,因此,可以将TLS证书提取出,然后单独讨论。本处,我们依赖您的部署工具,它可以是kubeadm、kubespray或其适用的工具。在本文中,我们将使用kubeadm,因为它是最常见的Kubernetes部署工具。kubeadm 是一个工具包,可帮助您以简单,合理安全和可扩展的方式引导最佳实践Kubernetes群集。它还支持为您管理Bootstrap Tokens并升级/降级群集。

假设我们已经有一个已部署的集群。现在,让我们从最有趣的地方开始:

rm -rf /etc/kubernetes/

在主节点上,此目录包含:

  • 一组用于etcd的证书和CA(位于/etc/kubernetes/pki/etcd
  • 一组Kubernetes的证书和CA(位于/etc/kubernetes/pki
  • 用于cluster-admin,kube-controller-manager,kube-scheduler和kubelet的Kubeconfigs(有针对我们的集群的base64编码的CA证书/etc/kubernetes/*.conf
  • 一组用于etcd,kube-apiserver,kube-scheduler和kube-controller-manager的静态pod的配置清单(位于/etc/kubernetes/manifests

本次假设的就是因意外故障或者误操作,导致我们丢失了所有相关的配置。

修复控制平面

为避免混淆,我们还要确保所有kubernetns控制平面pod也都已经停止:

crictl rm `crictl ps -aq`

注意:默认情况下,kubeadm不会覆盖现有证书和kubeconfigs,要重新发行它们,必须首先手动删除旧证书和kubeconfigs。crictl 是 CRI 兼容的容器运行时命令行接口。 你可以使用它来检查和调试 Kubernetes 节点上的容器运行时和应用程序。 crictl 和它的源代码在 cri-tools(https://github.com/kubernetes-sigs/cri-tools) 代码库。

让我们从恢复etcd开始。如果您有一个etcd仲裁节点(etcd拥有3个或更多主节点),那么直到大多数etcd节点都联机后,服务才能正常访问etcd群集。

kubeadm init phase certs etcd-ca

上面的命令将为我们的etcd集群生成一个新的CA。由于所有的证书都必须由它签名,因此,我们还需要将其和私钥复制到其他主节点:

/etc/kubernetes/pki/etcd/ca.{key,crt}

现在,让我们在所有控制平面节点上为其重新生成其余的etcd证书和静态pod清单:

kubeadm init phase certs etcd-healthcheck-client
kubeadm init phase certs etcd-peer
kubeadm init phase certs etcd-server
kubeadm init phase etcd local

在这个阶段,您应该已经有一个可以正常工作的etcd集群:

# crictl ps
CONTAINER ID        IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID
ac82b4ed5d83a       0369cf4303ffd       2 seconds ago       Running             etcd                0                   bc8b4d568751b

现在,我们继续执行相同的任务。对于Kubernetes服务而言,在其中一个主节点上执行:

kubeadm init phase certs all
kubeadm init phase kubeconfig all
kubeadm init phase control-plane all
cp -f /etc/kubernetes/admin.conf ~/.kube/config

上面的命令将为Kubernetes生成所有SSL证书,以及为Kubernetes服务生成的静态Pod清单和kubeconfigs。

如果您使用kubeadm来连接kubeletes,则还需要更新kube-public名称空间中的cluster-info配置,因为它仍然包含旧CA的哈希。

kubeadm init phase bootstrap-token 

由于其他实例上的所有证书也必须由单个CA签名,因此我们将其复制到其他控制平面节点,并对每个证书重复上述命令。

/etc/kubernetes/pki/{ca,front-proxy-ca}.{key,crt}
/etc/kubernetes/pki/sa.{key,pub}

顺便说一下,作为手动复制证书的替代方法,您还可以使用Kubernetes API,例如以下命令:

kubeadm init phase upload-certs --upload-certs

加密证书并将证书上传到Kubernetes,因此您可以按以下步骤注册主服务器:

kubeadm join phase control-plane-prepare all kubernetes-apiserver:6443 --control-plane --token cs0etm.ua7fbmwuf1jz946l     --discovery-token-ca-cert-hash sha256:555f6ececd4721fed0269d27a5c7f1c6d7ef4614157a18e56ed9a1fd031a3ab8 --certificate-key 385655ee0ab98d2441ba8038b4e8d03184df1806733eac131511891d1096be73
kubeadm join phase control-plane-join all

请注意,Kubernetes API有另一个配置,用于保存前代理客户端的CA证书。它用于验证从apiserver到webhooks和聚合层服务的请求。幸运的是,kube-apiserver会自动更新它。

但是,您可能需要手动从旧证书中清除它:

kubectl get cm -n kube-system extension-apiserver-authentication -o yaml

无论如何,在这个阶段,我们已经有一个可以正常工作的控制平面。

修复worker节点

该命令将列出集群的所有节点,尽管当前所有节点的状态均为NotReady

kubectl get node

这是因为它们仍然使用旧证书,并一直在等待来自由旧CA签名的apiserver的请求。为了解决这个问题,我们将使用kubeadm,对集群worker节点执行重新加入命令。

当主节点可以访问主CA时,它们就可以在本地加入:

systemctl stop kubelet
rm -rf /var/lib/kubelet/pki/ /etc/kubernetes/kubelet.conf
kubeadm init phase kubeconfig kubelet
kubeadm init phase kubelet-start

但是要加入worker-node,我们必须生成一个新令牌:

kubeadm token create --print-join-command

并分别对它们运行以下命令:

systemctl stop kubelet
rm -rf /var/lib/kubelet/pki/ /etc/kubernetes/pki/ /etc/kubernetes/kubelet.conf 
kubeadm join phase kubelet-start kubernetes-apiserver:6443  --token cs0etm.ua7fbmwuf1jz946l     --discovery-token-ca-cert-hash sha256:555f6ececd4721fed0269d27a5c7f1c6d7ef4614157a18e56ed9a1fd031a3ab8

注意:您不需要删除/etc/kubernetes/pki/主节点上的目录,因为该目录已经包含所有必需的证书。

以上步骤将把所有kubelets重新加入集群。它不应该影响已经在上面运行的任何容器。但是,如果集群中有多个节点,并且没有同时执行此操作,则可能会遇到这样的情况:controller-manager开始从NotReady节点重新创建容器,并尝试在正常节点上重新调度它们。

为了防止这种情况,我们可以暂时停止主机上的controller-manager容器:

rm /etc/kubernetes/manifests/kube-controller-manager.yaml
crictl rmp `crictl ps --name kube-controller-manager -q`

仅需要最后一条命令即可确保控制器管理器已真正停止。一旦所有节点正常加入了集群,就可以为controller-manager生成一个静态清单。

为此,请在所有masters-nodes上运行以下命令:

kubeadm init phase control-plane controller-manager

请注意,您需要在已经生成连接令牌的阶段执行这些步骤。否则,连接过程将挂起,尝试从cluster-info configmap中读取令牌。

如果将kubelets配置为请求由您的CA签名的证书(选项serverTLSBootstrap: true),则还需要从kubelets中批准CSR。

kubectl get csr
kubectl certificate approve <csr>

修复ServiceAccounts

由于我们丢失了/etc/kubernetes/pki/sa.key。此密钥用于为群集中的所有ServiceAccounts签名jwt令牌。因此,我们必须为其重新创建令牌。

通过匹配kubernetes.io/service-account-token字段,可以非常简单的从所有的secret中删除令牌字段:

kubectl get secret --all-namespaces | awk '/kubernetes.io\/service-account-token/ { print "kubectl patch secret -n " $1 " " $2 " -p {\\\"data\\\":{\\\"token\\\":null}}"}' | sh -x

之后,kube-controller-manager将自动生成使用新密钥签名的新令牌。

有一点需要注意,并非所有的微服务都能即时更新令牌,因此很可能需要手动重新启动所有使用令牌的容器。

kubectl get pod --field-selector 'spec.serviceAccountName!=default' --no-headers --all-namespaces | awk '{print "kubectl delete pod -n " $1 " " $2 " --wait=false --grace-period=0"}'

以上命令将生成一个命令列表,以删除所有serviceAccountName不是default的pod。推荐从kube-system namespace开始,因为该namespace中安装了kube-proxy和CNI插件。它们对于处理微服务之间的通信至关重要。

至此,Kubernetns集群已经恢复完成,且工作正常。

参考:

  1. https://itnext.io/breaking-down-and-fixing-kubernetes-4df2f22f87c3
  2. https://kubernetes.io/docs/tasks/debug-application-cluster/debug-cluster/

相关推荐

F5负载均衡器如何通过irules实现应用的灵活转发?

F5是非常强大的商业负载均衡器。除了处理性能强劲,以及高稳定性之外,F5还可以通过irules编写强大灵活的转发规则,实现web业务的灵活应用。irules是基于TCL语法的,每个iRules必须包含...

映射域名到NAS

前面介绍已经将域名映射到家庭路由器上,现在只需要在路由器上设置一下端口转发即可。假设NAS在内网的IP是192.168.1.100,NAS管理端口2000.你的域名是www.xxx.com,配置外部端...

转发(Forward)和重定向(Redirect)的区别

转发是服务器行为,重定向是客户端行为。转发(Forward)通过RequestDispatcher对象的forward(HttpServletRequestrequest,HttpServletRe...

SpringBoot应用中使用拦截器实现路由转发

1、背景项目中有一个SpringBoot开发的微服务,经过业务多年的演进,代码已经累积到令人恐怖的规模,亟需重构,将之拆解成多个微服务。该微服务的接口庞大,调用关系非常复杂,且实施重构的人员大部分不是...

公司想搭建个网站,网站如何进行域名解析?

域名解析是将域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务。IP地址是网络上标识站点的数字地址,为方便记忆,采用域名来代替IP地址标识站点地址。域名解析就是域名到IP地址的转...

域名和IP地址什么关系?如何通过域名解析IP?

一般情况下,访客通过域名和IP地址都能访问到网站,那么两者之间有什么关系吗?本文中科三方针对域名和IP地址的关系和区别,以及如何实现域名与IP的绑定做下介绍。域名与IP地址之间的关系IP地址是计算机的...

分享网站域名301重定向的知识

网站域名做301重定向操作时,一般需要由专业的技术来协助完成,如果用户自己在维护,可以按照相应的说明进行操作。好了,下面说说重点,域名301重定向的操作步骤。首先,根据HTTP协议,在客户端向服务器发...

NAS外网到底安全吗?一文看懂HTTP/HTTPS和SSL证书

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:可爱的小cherry搭好了NAS,但是不懂做好网络加密,那么隐私泄露也会随时发生!大家好,这里是Cherry,喜爱折腾、玩数码,热衷于分享数...

ForwardEmail免费、开源、加密的邮件转发服务

ForwardEmail是一款免费、加密和开源的邮件转发服务,设置简单只需4步即可正常使用,通过测试来看也要比ImprovMX好得多,转发近乎秒到且未进入垃圾箱(仅以Mailbox.org发送、Out...

使用CloudFlare进行域名重定向

当网站变更域名的时候,经常会使用域名重定向的方式,将老域名指向到新域名,这通常叫做:URL转发(URLFORWARDING),善于使用URL转发,对SEO来说非常有用,因为用这种方式能明确告知搜索引...

要将端口5002和5003通过Nginx代理到一个域名上的操作笔记

要将端口5002和5003通过Nginx代理到域名www.4rvi.cn的不同路径下,请按照以下步骤配置Nginx:步骤说明创建或编辑Nginx配置文件通常配置文件位于/etc/nginx/sites...

SEO浅谈:网站域名重定向的三种方式

在大多数情况下,我们输入网站访问网站的时候,很难发现www.***.com和***.com的区别,因为一般的网站主,都会把这两个域名指向到同一网站。但是对于网站运营和优化来说,www.***.com和...

花生壳出现诊断域名与转发服务器ip不一致的解决办法

出现诊断域名与转发服务器ip不一致您可以:1、更改客户端所处主机的drs为223.5.5.5备用dns为119.29.29.29;2、在windows上进入命令提示符输入ipconfig/flush...

涨知识了!带你认识什么是域名

1、什么是域名从技术角度来看,域名是在Internet上解决IP地址对应的一种方法。一个完整的域名由两个或两个以上部分组成,各部分之间用英文的句号“.”来分隔。如“abc.com”。其中“com”称...

域名被跳转到其他网站是怎么回事

当你输入域名时被跳转到另一个网站,这可能是由几种原因造成的:一、域名可能配置了域名转发服务。无论何时有人访问域名,比如.com、.top等,都会自动重定向到另一个指定的URL,这通常是在域名注册商设...

取消回复欢迎 发表评论: