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

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

nanshan 2024-10-17 11:14 23 浏览 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/

相关推荐

Let’s Encrypt免费搭建HTTPS网站

HTTPS(全称:HyperTextTransferProtocoloverSecureSocketLayer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入...

使用Nginx配置TCP负载均衡(nginx tcp负载)

假设Kubernetes集群已经配置好,我们将基于CentOS为Nginx创建一个虚拟机。以下是实验种设置的详细信息:Nginx(CenOS8Minimal)-192.168.1.50Kube...

Nginx负载均衡及支持HTTPS与申请免费SSL证书

背景有两台minio文件服务器已做好集群配置,一台是192.168.56.41:9000;另一台是192.168.56.42:9000。应用程序通过Nginx负载均衡调用这两台minio服务,减轻单点...

HTTPS配置实战(https配置文件)

原因现在网站使用HTTPS是规范操作之一,前些日子买了腾讯云服务,同时申请了域名http://www.asap2me.top/,目前该域名只支持HTTP,想升级为HTTPS。关于HTTPS的链接过程大...

只有IP地址没有域名实现HTTPS访问方法

一般来说,要实现HTTPS,得有个注册好的域名才行。但有时候呢,咱只有服务器的IP地址,没注册域名,这种特殊情况下,也能照样实现HTTPS安全访问,按下面这些步骤来就行:第一步,先确认公网...

超详解:HTTPS及配置Django+HTTPS开发环境

众所周知HTTP协议是以TCP协议为基石诞生的一个用于传输Web内容的一个网络协议,在“网络分层模型”中属于“应用层协议”的一种。在这里我们并不研究该协议标准本身,而是从安全角度去探究使用该协议传输数...

Godaddy购买SSL之后Nginx配置流程以及各种错误的解决

完整流程:参考地址:https://sg.godaddy.com/zh/help/nginx-generate-csrs-certificate-signing-requests-3601生成NGI...

Nginx从安装到高可用,一篇搞定(nginx安装与配置详解)

一、Nginx安装1、去官网http://nginx.org/下载对应的nginx包,推荐使用稳定版本2、上传nginx到linux系统3、安装依赖环境(1)安装gcc环境yuminstallgc...

阿里云免费证书申请,配置安装,使用tomcat,支持http/https访问

参数说明商品类型默认已选择云盾证书服务(无需修改)。云盾证书服务类型SSL证书服务的类型。默认已选择云盾SSL证书(无需修改),表示付费版SSL证书。如果您需要免费领取或付费扩容DV单域名证书【免费试...

你试过两步实现Nginx的规范配置吗?极速生成Nginx配置小工具

NGINX是一款轻量级的Web服务器,最强大的功能之一是能够有效地提供HTML和媒体文件等静态内容。NGINX使用异步事件驱动模型,在负载下提供可预测的性能。是当下最受欢迎的高性能的Web...

从零开始搭建HTTPS服务(搭建https网站)

搭建HTTPS服务的最初目的是为了开发微信小程序,因为wx.request只允许发起HTTPS请求,并且还必须和指定的域名进行网络通信。要从零开始搭建一个HTTPS的服务需要下面4...

群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问

安全第一步,群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问【新手导向】NAS本质还是一个可以随时随地访问的个人数据存储中心,我们在外网访问的时候,特别是在公网IP下,其实会面临着很多安...

让网站快速升级HTTPS协议提高安全性

为什么用HTTPS网络安全越来越受到重视,很多互联网服务网站,都已经升级改造为https协议。https协议下数据包是ssl/tcl加密的,而http包是明文传输。如果请求一旦被拦截,数据就会泄露产生...

用Https方式访问Harbor-1.9版本(https访问流程)

我上周在头条号写过一篇原创文章《Docker-Harbor&Docker-kitematic史上最详细双系统配置手册》,这篇算是它的姊妹篇吧。这篇文章也将用到我在头条写的另一篇原创文章的...

如何启用 HTTPS 并配置免费的 SSL 证书

在Linux服务器上启用HTTPS并配置免费的SSL证书(以Let'sEncrypt为例)可以通过以下步骤完成:---###**一、准备工作**1.**确保域名已解析**...

取消回复欢迎 发表评论: