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,版權歸原做者全部。