做者 | Andrei Kvapilhtml
编译 | 云原生计算编辑部node
原文连接:https://itnext.io/breaking-down-and-fixing-kubernetes-4df2f22f87c3web
Kubernetes 是当下最流行的容器编排平台,不论是生产环境的采用率,仍是云原生生态都很强大。最近,Kubernetes 在功能,安全性和弹性方面取得了长足的进步,Kubernetes 架构使您能够轻松地应对各类故障并始终保持正常运行。数据库
不相信它这么顽强?下面,咱们将破坏集群,删除证书......一块儿来看看这些破坏性的动做会不会让运行的服务宕机。bootstrap
在 Kubernetes 控制平面(主)节点上仅包含如下几个组件:
etcd —用做数据库
kube-apiserver — 提供集群所的API服务,负责在Kubernetes节点和Kubernetes主组件之间创建通讯。
kube-controller-manager —对Kubernetes资源执行操做
kube-scheduler —主调度程序
kubelet —负责容器的建立与起停api
以上每一个组件都受到一组针对客户端和服务器的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 在 master 节点上运行,资源清单在/ etc / kubernetes / manifests目录下。服务器
关于这一点,咱们将不作详细介绍, 在本案例中,咱们主要对如何从全部这些组件中得到一个有效运行的集群感兴趣。 首先,假设咱们拥有上述 Kubernetes 组件,它们以某种方式相互通讯。
一般以下所示:微信
(箭头表示客户端到服务器的链接)架构
为了进行通讯,他们须要TLS证书,部署工具能够是 kubeadm,kubespray 或其余任何工具。 在本文中,咱们将使用kubeadm,由于它是最多见的 Kubernetes 部署工具,而且常常在其余解决方案中使用。
假设咱们已经有一个部署好的集群。 让咱们开始破坏行动吧:
rm -rf /etc/kubernetes/
在 master节点上,此目录包含:
-etcd的一组证书和CA(在/ etc / kubernetes / pki / etcd中)
-Kubernetes 的一组证书和CA(在/ etc / kubernetes / pki中)
-用于cluster-admin,kube-controller-manager,kube-scheduler和kubelet使用的Kubeconfig文件(每一个文件在/etc/kubernetes/*.conf中都有针对咱们集群的base64编码的CA证书)
-etcd,kube-apiserver,kube-scheduler和kube-controller-manager使用的static manifest文件(在/ etc / kubernetes / manifests中)
假设咱们一会儿把什么都删了......
修复控制平面
为避免混淆,咱们还要确保全部control-plane pods 也已中止:
crictl rm $(crictl ps -aq)
注意:默认状况下,kubeadm 不会覆盖现有证书和 kubeconfig,要从新发布它们,必须首先手动删除旧证书和 kubeconfig。
接下来,让咱们从恢复 etcd开始。 若是您有一个 quorum (3个或更多主节点),则直到大多数节点都联机后,才能访问 etcd群集。
kubeadm init phase certs etcd-ca
上面的命令将为咱们的 etcd 集群生成一个新的CA。 因为全部其余证书都必须由它签名,所以,咱们还将其和私钥复制到其余 master节点:
/etc/kubernetes/pki/etcd/ca.{key,crt}
如今,让咱们在全部控制平面节点上为其从新生成其他的 etcd 证书和 static-manifest:
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
若是您使用 kubeadm 来链接 kubeletes,则还须要更新kube-public namespace中的 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 须要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 cm -n kube-system extension-apiserver-authentication -o yaml
不管如何,在这个阶段,咱们已经有一个能够正常工做的控制平面。
修复工做节点
该命令将列出集群的全部节点,尽管当前全部节点的状态均为“NotReady”:
kubectl get node
这是由于它们仍然使用旧证书,并指望来自由旧CA签名的 apiserver 的请求。 为了解决这个问题,咱们将使用 kubeadm,并对群集执行从新加入节点。
当主节点能够访问主CA时,它们能够在本地加入:
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
注意:您不须要删除主节点上的/ etc / kubernetes / pki /目录,由于它已经包含全部须要的证书。
上面的操做会将您的全部 kubelet 从新加入集群。 它不会影响已经在其上运行的任何容器。 可是,若是集群中有多个节点而且不一样时进行,则可能会遇到一种状况,即controller-manager开始从NotReady节点从新建立容器,并尝试在alive的节点上从新调度它们。
为了防止这种状况,咱们能够暂时中止 master上的controller-manager pod:
rm /etc/kubernetes/manifests/kube-controller-manager.yaml crictl rmp $(crictl ps --name kube-controller-manager -q)
仅须要最后一条命令便可确保controller-manager已真正中止。 一旦集群中的全部节点被加入,就能够为controller-manager生成一个static-manifest 。
为此,请在全部 master节点上运行如下命令:
kubeadm init phase control-plane controller-manager
请注意,您须要在已经生成join token的阶段执行这些步骤。 不然,join过程将继续尝试从cluster-info configmap读取token。
若是将kubelet配置为请求由您的CA签名的证书(选项serverTLSBootstrap:true),则还须要批准来自kubelet的CSR请求。
kubectl get csr kubectl certificate approve <csr>
修复ServiceAccounts
还有一件事,由于咱们丢失了/etc/kubernetes/pki/sa.key。 该密钥用于为群集中全部 ServiceAccounts 的jwt令牌签名。 所以,咱们必须为其从新建立token。
经过从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将自动生成使用新密钥签名的新token。
不幸的是,并不是全部的微服务都能即时更新token,所以极可能须要手动从新启动全部使用token的容器。
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的namespace开始,由于在那里安装了kube-proxy和CNI插件。 它们对于处理微服务之间的通讯相当重要。
此时,集群恢复就算完成了。
Kubernetes 在生产环境如何落地?
目前,Kubernetes 技术已然成为了容器编排领域的事实标准。百度从 2010 年开始探索容器和集群管理技术,2016年自主研发的 Matrix 集群管理系统已经管理了数十万台机器和服务。随着 Kubernetes 技术的成熟,百度看到了开源技术强大的生命力,从 2018 年开始尝试向 Kubernetes 架构演化。试点成功以后,启动了大规模 Kubernetes 架构融合项目。一方面保留百度在 Matrix 上积累的核心技术能力,另外一方面让存量业务能够更低成本的迁移到 Kubernetes 之上。
百度于 2020 年得到 InfoQ 十大云原生创新技术方案,对百度云原生来讲仅仅是个开始。目前大规模 Kubernetes 融合架构的业务正在百度云原生各产品技术架构中稳定运行并持续增加,百度云原生团队也将会在继续服务好客户的同时,利用Kubernetes技术实践经验不断优化产品,更好地助力各行各业的客户实现基于云原生架构的数字化转型。
百度智能云云原平生台,为客户建设容器化和无服务器化的基础设施,提供企业级的微服务治理能力,同时集成源自百度自身多年实践的DevOps工具链。保障开发者享受到高效、灵活、弹性的开发与运维体验,助力企业更高效率低风险地构建云原生应用,普遍应用于金融、互联网、制造等各行各业的云原生转型阶段。
了解更多百度云原生产品请访问:
https://cloud.baidu.com/product/cnap.html
重磅!云原生计算交流群成立
扫码添加小助手便可申请加入,必定要备注:名字-公司/学校-地区,根据格式备注,才能经过且邀请进群。。
了解更多微服务、云原生技术的相关信息,请关注咱们的微信公众号【云原生计算】!