當 Kubernetes 集羣證書被所有刪除後,你該如何修復它?


 

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


 

相關文章
相關標籤/搜索