Kubernetes 是一个很牛很牛的平台,Kubernetes 的架构可让你轻松应对各类故障,今天咱们未来破坏咱们的集群、删除证书,而后再想办法恢复咱们的集群,进行这些危险的操做而不会对已经运行的服务形成宕机。html
若是你真的想要执行接下来的操做,仍是建议别在生产环境去折腾,虽然理论上不会形成服务宕机,可是若是出现了问题,可千万别骂我~~~node
咱们知道 Kubernetes 的控制平面是由几个组件组成的:git
-
etcd:做为整个集群的数据库使用github
-
kube-apiserver:集群的 API 服务web
-
kube-controller-manager:整个集群资源的控制操做docker
-
kube-scheduler:核心调度器数据库
-
kubelet:是运行在节点上用来真正管理容器的组件bootstrap
这些组件都由一套针对客户端和服务端的 TLS 证书保护,用于组件之间的认证和受权,大部分状况下它们并非直接存储在 Kubernetes 的数据库中的,而是以普通文件的形式存在。api
# 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 (我这里用 kubeadm 搭建的集群)的形式运行在 master 节点上,默认资源清单位于 /etc/kubernetes/manifests
目录下。一般来讲这些组件之间会进行互相通讯,基本流程以下所示:架构
组件之间为了通讯,他们须要使用到 TLS 证书。假设咱们已经有了一个部署好的集群,接下来让咱们开始咱们的破坏行为。
rm -rf /etc/kubernetes/
在 master 节点上,这个目录包含:
-
etcd 的一组证书和 CA(在
/etc/kubernetes/pki/etcd
目录下) -
一组 kubernetes 的证书和 CA(在
/etc/kubernetes/pki
目录下) -
还有 kube-controller-manager、kube-scheduler、cluster-admin 以及 kubelet 这些使用的 kubeconfig 文件
-
etcd、kube-apiserver、kube-scheduler 和 kube-controller-manager 的静态 Pod 资源清单文件(位于
/etc/kubernetes/manifests
目录)
如今咱们就上面这些全都删除了,若是是在生产环境作了这样的操做,可能你如今正瑟瑟发抖吧~
修复控制平面
首先我也确保下咱们的全部控制平面 Pod 已经中止了。
# 若是你用 docker 也是能够的 crictl rm `crictl ps -aq`
注意:kubeadm 默认不会覆盖现有的证书和 kubeconfigs,为了从新颁发证书,你必须先手动删除旧的证书。
接下来咱们首先恢复 etcd,执行下面的命令生成 etcd 集群的证书:
kubeadm init phase certs etcd-ca
上面的命令将为咱们的 etcd 集群生成一个新的 CA,因为全部其余证书都必须由它来签署,咱们也将把它和私钥复制到其余 master 节点(若是你是多 master)。
/etc/kubernetes/pki/etcd/ca.{key,crt}
接下来让咱们在全部 master 节点上为它从新生成其他的 etcd 证书和静态资源清单。
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 服务作一样的操做,在其中一个 master 节点上执行以下的命令:
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 服务的静态 Pods 清单和 kubeconfigs 文件。
若是你使用 kubeadm 加入 kubelet,你还须要更新 kube-public
命名空间中的 cluster-info 配置,由于它仍然包含你的旧 CA 的哈希值。
kubeadm init phase bootstrap-token
因为其余 master 节点上的全部证书也必须由单一 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,时间为2小时,因此你能够按如下方式注册 master 节点:
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 还有一个配置,它为 front-proxy
客户端持有 CA 证书,它用于验证从 apiserver 到 webhooks 和聚合层服务的请求。不过 kube-apiserver 会自动更新它。到在这个阶段,咱们已经有了一个完整的控制平面了。
修复工做节点
如今咱们可使用下面的命令列出集群的全部节点:
kubectl get nodes
固然正常如今全部节点的状态都是 NotReady,这是由于他们仍然还使用的是旧的证书,为了解决这个问题,咱们将使用 kubeadm 来执行从新加入集群节点。
systemctl stop kubelet rm -rf /var/lib/kubelet/pki/ /etc/kubernetes/kubelet.conf kubeadm init phase kubeconfig kubelet kubeadm init phase kubelet-start
但要加入工做节点,咱们必须生成一个新的 token。
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
注意:你不须要删除 master 节点上的
/etc/kubernetes/pki
目录,由于它已经包含了全部须要的证书。
上面的操做会把你全部的 kubelet 从新加入到集群中,它并不会影响任何已经运行在上面的容器,可是,若是集群中有多个节点而且不一样时进行,则可能会遇到一种状况,即 kube-controller-mananger 开始从 NotReady 节点从新建立容器,并尝试在活动节点上从新调度它们。
为了防止这种状况,咱们能够暂时停掉 master 节点上的 controller-manager。
rm /etc/kubernetes/manifests/kube-controller-manager.yaml
crictl rmp `crictl ps --name kube-controller-manager -q`
一旦集群中的全部节点都被加入,你就能够为 controller-manager 生成一个静态资源清单,在全部 master 节点上运行下面的命令。
kubeadm init phase control-plane controller-manager
若是 kubelet 被配置为请求由你的 CA 签署的证书(选项serverTLSBootstrap: true),你还须要批准来自 kubelet 的 CSR:
kubectl get csr kubectl certificate approve <csr>
修复 ServiceAccounts
由于咱们丢失了 /etc/kubernetes/pki/sa.key
,这个 key 用于为集群中全部 ServiceAccounts
签署 jwt tokens
,所以,咱们必须为每一个 sa 从新建立tokens。
这能够经过类型为 kubernetes.io/service-account-token
的 Secret 中删除 token 字段来完成。
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 会自动生成用新密钥签名的新令牌。不过须要注意的是并不是全部的微服务都能即时更新 tokens,所以极可能须要手动从新启动使用 tokens 的容器。
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"}'
例如,这个命令会生成一个命令列表,会将全部使用非默认的 serviceAccount 的 Pod 删除,我建议从 kube-system 命名空间执行,由于 kube-proxy 和 CNI 插件都安装在这个命名空间中,它们对于处理你的微服务之间的通讯相当重要。
到这里咱们的集群就恢复完成了。
参考连接:https://itnext.io/breaking-down-and-fixing-kubernetes-4df2f22f87c3
本文转载自:「开源世界」,原文:http://ym.baisou.ltd/post/534.html,版权归原做者全部。