Kubernetes 與 OpenYurt 無(wú)縫轉(zhuǎn)換(命令式)
yurtctl convert --provider [minikube|kubeadm|kind] // To convert an existing Kubernetes cluster to an OpenYurt cluster yurtctl revert // To uninstall and revert back to the original cluster settings
簡(jiǎn)單一行命令就可體驗(yàn) OpenYurt 了,感覺非常方便。
稍等!為什么是 convert/revert 而不是 install/uninstall ?
這個(gè)命令對(duì)集群做了什么?
看來,在執(zhí)行它之前有必要搞清楚它到底做了什么。
01
yurtctl convert 到底做了些什么?
Cloud Native
1核心流程
跟隨 openYurt 源代碼(詳情請(qǐng)見文末相關(guān)鏈接),梳理了 convert 的核心流程:
1. 檢查
1.1 檢查所有 node 節(jié)點(diǎn)狀態(tài)為 ready
2. 組件部署
2.1 給 node節(jié)點(diǎn)打上相應(yīng)的 label。
2.2 使用 deployment 部署 yurt-controller-manager。
2.3 使用 deployment 部署 yurt-tunnel-server。
2.4 使用 daemonset 部署 yurt-tunnel-agent,部署在邊緣節(jié)點(diǎn)上。
2.5 使用 deployment 部署 yurt-app-manager。
3. k8s 組件修改
3.1 修改 kube-controller-manager.yaml,用來disable nodelifecycle controller
4. 節(jié)點(diǎn)轉(zhuǎn)換
4.1 寫入 yurthub.yaml 到 /etc/kubernetes/manifests,啟動(dòng)靜態(tài) pod
4.2 修改 kubelet 配置,使得 kubelet 訪問 yurthub 而不是直連 apiServer
3,則是對(duì)原有 k8s 系統(tǒng)組件的操作,需要特別注意。
4,節(jié)點(diǎn)轉(zhuǎn)換看著也并不復(fù)雜,卻對(duì)邊緣至關(guān)重要。
2
disable nodelifecycle controller 做了什么
工作內(nèi)容:
1. 查詢控制面節(jié)點(diǎn)2. 創(chuàng)建 job,通過` nodeName: {{.nodeName}}` 確保 job 的 pod 調(diào)度到對(duì)應(yīng) node 上執(zhí)行(通過 nsenter 的方式執(zhí)行,修改宿主機(jī)上文件)。3. sed -i 's/--controllers=/--controllers=-nodelifecycle,/g' /etc/kubernetes/manifests/kube-controller-manager.yaml
查看 kube-controller-manager.yaml
...containers:- command:- kube-controller-manager- --allocate-node-cidrs=true ...- --controllers=-nodelifecycle,*,bootstrapsigner,tokencleaner...
可見,上面的一系列操作最終就是修改了 kube-controller-manager 的啟動(dòng)命令。
查看 kube-controller-manager 啟動(dòng)參數(shù)說明:
--controllers 代表需要開啟的controller列表可見,sed 命令就是去掉了 nodelifecycle 這個(gè) controller。
那,nodelifecycle controller 是做什么的?
簡(jiǎn)單來說:
1. 不斷監(jiān)聽,kubelet 上報(bào)上來的 node 信息
2. 如果某個(gè) node 狀態(tài)異常,或者說長(zhǎng)時(shí)間沒有上報(bào)等
2.1 驅(qū)逐這個(gè) node 節(jié)點(diǎn)或者其他 ---> 導(dǎo)致上面的 pod 被重新調(diào)度
可見,對(duì)于處于弱網(wǎng)環(huán)境的邊緣節(jié)點(diǎn),很容易就命中異常狀態(tài),導(dǎo)致 node 被驅(qū)逐,pod 被重新調(diào)度。
所以這里把它去掉了。使用 yurt-controller-manager 來代替它。
即使節(jié)點(diǎn)心跳丟失,處于自治模式的節(jié)點(diǎn)中的 pod 也不會(huì)從 APIServer 中驅(qū)逐。
注:這里自治模式的節(jié)點(diǎn),指的就是邊緣節(jié)點(diǎn)。我們通常會(huì)通過加 annotation 的方式把節(jié)點(diǎn)標(biāo)記為自治節(jié)點(diǎn)。
3
節(jié)點(diǎn)轉(zhuǎn)換是怎么實(shí)現(xiàn)的,云端節(jié)點(diǎn)和邊緣節(jié)點(diǎn)有什么差異?
同樣,是通過跑 job 的方式,在目標(biāo)宿主機(jī)上下文中執(zhí)行相關(guān)操作。
不過,相比于暴力使用 nsenter,這里用了更加優(yōu)雅的方式。通過將宿主機(jī)根路徑 volume 掛載到容器里的方式。
kubelet 的修改
在文件/var/lib/kubelet/kubeadm-flags.env 中為 KUBELET_KUBEADM_ARGS 添加配置:
--kubeconfig=/var/lib/openyurt/kubelet.conf --bootstrap-kubeconfig=
作用:
1. 參數(shù):--kubeconfig , 給kubelet指定了訪問apiServer的配置文件。2. 當(dāng)--kubeconfig 文件存在,--bootstrap-kubeconfig為空時(shí), kubelet 啟動(dòng)就不需要通過 bootstrap-token 置換文件證書等過程,直接讀取 kubeconfig 文件訪問 apiServer。3. 由于 KUBELET_KUBEADM_ARGS 是 kubelet 啟動(dòng)參數(shù)的最后一部分,所以可以起到覆蓋前面參數(shù)的作用。
其中 /var/lib/openyurt/kubelet.conf 內(nèi)容如下,直接將流量指定到 yurthub:
apiVersion: v1clusters:- cluster:server: http://127.0.0.1:10261name: default-clustercontexts:- context:cluster: default-clusternamespace: defaultuser: default-authname: default-contextcurrent-context: default-contextkind: Configpreferences: {}
yurthub 的啟動(dòng)細(xì)節(jié)
yurthub 容器啟動(dòng)參數(shù)如下:
command:- yurthub- --v=2- --server-addr=__kubernetes_service_addr__- --node-name=$(NODE_NAME)- --join-token=__join_token__- --working-mode=__working_mode__
通過參數(shù)我們可看出:
1. server-addr 指定了云端 apiServer 地址。注意這里的地址一定是公網(wǎng)可訪問地址,否則異構(gòu)網(wǎng)絡(luò)下會(huì)有問題。
2. join-token 就是加入節(jié)點(diǎn)的 token,可使用`kubeadm token create`來創(chuàng)建。k8s 提供機(jī)制,通過 token 置換出正常訪問的 kubeconf 文件。
3. working-mode:cloud/edge。這就是邊緣節(jié)點(diǎn)和云端節(jié)點(diǎn)的差異。
簡(jiǎn)單查看 yurthub 源代碼 cmd/yurthub/app/start.go:
if cfg.WorkingMode == util.WorkingModeEdge { cacheMgr, err = cachemanager.NewCacheManager(cfg.StorageWrapper, cfg.SerializerManager, cfg.RESTMapperManager, cfg.SharedFactory) ...} else { klog.Infof("%d. disable cache manager for node %s because it is a cloud node", trace, cfg.NodeName)}if cfg.WorkingMode == util.WorkingModeEdge { ... gcMgr, err := gc.NewGCManager(cfg, restConfigMgr, stopCh)} else { klog.Infof("%d. disable gc manager for node %s because it is a cloud node", trace, cfg.NodeName)}
可見,云端 yurthub,少做了 cache、GC 的工作。
查看 issue(詳情請(qǐng)見文末相關(guān)鏈接)可了解:云端也可以利用 yurthub 提供的 data-filtering 能力來控制 service 的流量
當(dāng)然,云端也不需要做 cache 等工作。
4 命令行參數(shù)
--cloud-nodes 用于標(biāo)識(shí)哪些是云端節(jié)點(diǎn),多個(gè)節(jié)點(diǎn)用逗號(hào)分隔:node1,node2
--deploy-yurttunnel 標(biāo)記是否要部署 yurttunnel
--kubeadm-conf-path 標(biāo)記節(jié)點(diǎn)機(jī)器上 kubeadm 配置文件路徑。默認(rèn):/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
更多參數(shù),可使用 yurtctl convert --help 來查看。
總結(jié)
簡(jiǎn)單來說,convert 核心做了幾個(gè)事情:
可見,convert 的事情還是比較可控的。執(zhí)行 yurtctl convert 也不用太擔(dān)心。
當(dāng)然,最后的擔(dān)心也應(yīng)該由 yurtctl revert 來徹底消除!
02
yurtctl revert 又干了些什么?
Cloud Native
1核心流程
1. 檢查
1.1 確保所有 node 都已經(jīng) ready
2. 刪除自身部署組件
2.1 刪除 yurt-controller-manager deployment 以及相關(guān)資源
2.2 刪除 yurt-tunnel-agent 以及相關(guān)資源
2.2 刪除 yurt-tunnel-server 以及相關(guān)資源
2.3 刪除 yurt-app-manager 以及相關(guān)資源
3. K8s 組件修改
3.1 開啟 nodelifecontroller, 這個(gè)很好理解,就是把修改的命令通過 sed 命令改回來。
4. 云端、邊緣節(jié)點(diǎn)轉(zhuǎn)換為原生節(jié)點(diǎn)
4.1 修改 kubelet 配置,直連 apiServer
4.2 刪除 yurthub 相關(guān)配置、目錄
需要注意的是。如果 convert 失敗,比如 job 執(zhí)行超時(shí)或者失敗。job 是不會(huì)被刪除的。
即使 yurtctl revert 也不會(huì)刪除。目的是為了保留現(xiàn)場(chǎng)方便定位問題。
如果需要重新執(zhí)行 yurtctl convert, 需要手動(dòng)刪除 job。
kubectl get job -n kube-system -A |grep convertkubectl delete job -n kube-system < job-name>
總結(jié)
yurtctl convert/revert 命令是最快捷體驗(yàn) OpenYurt 功能的方法之一。
在了解了這兩個(gè)命令的實(shí)現(xiàn)原理,也就對(duì) OpenYurt 的技術(shù)方案了解大半了。
執(zhí)行命令也不擔(dān)心了,so easy!
03
相關(guān)鏈接
Cloud Native
1)源代碼:https://github.com/openyurtio/openyurt/blob/5063752a9f6645270e3177e39a46df8c23145af2/pkg/yurtctl/cmd/convert/convert.go#L300
