做者 | 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
重磅!雲原生計算交流羣成立
掃碼添加小助手便可申請加入,必定要備註:名字-公司/學校-地區,根據格式備註,才能經過且邀請進羣。。
瞭解更多微服務、雲原生技術的相關信息,請關注咱們的微信公衆號【雲原生計算】!