前言
superedge是騰訊推出的Kubernetes-native邊緣計算管理框架。相比openyurt以及kubeedge,superedge除了具備Kubernetes零侵入以及邊緣自治特性,還支持獨有的分布式健康檢查以及邊緣服務(wù)訪問控制等高級特性,極大地消減了云邊網(wǎng)絡(luò)不穩(wěn)定對服務(wù)的影響,同時也很大程度上方便了邊緣集群服務(wù)的發(fā)布與治理
特性
- Kubernetes-native:superedge在原生Kubernetes基礎(chǔ)上進行了擴展,增加了邊緣計算的某干組件,對Kubernetes完全無侵入;另外通過簡單部署superedge核心組件就可以使原生Kubernetes集群開啟邊緣計算功能;另外零侵入使得可以在邊緣集群上部署任何Kubernetes原生工作負載(deployment, statefulset, daemonset, and etc)
- 邊緣自治:superedge提供L3級別的邊緣自治能力,當(dāng)邊端節(jié)點與云端網(wǎng)絡(luò)不穩(wěn)定或者斷連時,邊緣節(jié)點依舊可以正常運行,不影響已經(jīng)部署的邊緣服務(wù)
- 分布式健康檢查:superedge提供邊端分布式健康檢查能力,每個邊緣節(jié)點會部署edge-health,同一個邊緣集群中的邊緣節(jié)點會相互進行健康檢查,對節(jié)點進行狀態(tài)投票。這樣即便云邊網(wǎng)絡(luò)存在問題,只要邊緣端節(jié)點之間的連接正常,就不會對該節(jié)點進行驅(qū)逐;另外,分布式健康檢查還支持分組,把集群節(jié)點分成多個組(同一個機房的節(jié)點分到同一個組中),每個組內(nèi)的節(jié)點之間相互檢查,這樣做的好處是避免集群規(guī)模增大后節(jié)點之間的數(shù)據(jù)交互特別大,難以達成一致;同時也適應(yīng)邊緣節(jié)點在網(wǎng)絡(luò)拓撲上天然就分組的情形。整個設(shè)計避免了由于云邊網(wǎng)絡(luò)不穩(wěn)定造成的大量的pod遷移和重建,保證了服務(wù)的穩(wěn)定
- 服務(wù)訪問控制:superedge自研了ServiceGroup實現(xiàn)了基于邊緣計算的服務(wù)訪問控制?;谠撎匦灾恍铇?gòu)建DeploymentGrid以及ServiceGrid兩種Custom Resource,就可以便捷地在共屬同一個集群的不同機房或區(qū)域中各自部署一組服務(wù),并且使得各個服務(wù)間的請求在本機房或本地域內(nèi)部即可完成(閉環(huán)),避免了服務(wù)跨地域訪問。利用該特性可以極大地方便邊緣集群服務(wù)的發(fā)布與治理
- 云邊隧道:superedge支持自建隧道(目前支持TCP, HTTP and HTTPS)打通不同網(wǎng)絡(luò)環(huán)境下的云邊連接問題。實現(xiàn)對無公網(wǎng)IP邊緣節(jié)點的統(tǒng)一操作和維護
整體架構(gòu)

組件功能總結(jié)如下:
云端組件
云端除了邊緣集群部署的原生Kubernetes master組件(cloud-kube-apiserver,cloud-kube-controller以及cloud-kube-scheduler)外,主要管控組件還包括:
- tunnel-cloud:負責(zé)維持與邊緣節(jié)點tunnel-edge的網(wǎng)絡(luò)隧道,目前支持TCP/HTTP/HTTPS協(xié)議
- application-grid controller:服務(wù)訪問控制ServiceGroup對應(yīng)的Kubernetes Controller,負責(zé)管理DeploymentGrids以及ServiceGrids CRDs,并由這兩種CR生成對應(yīng)的Kubernetes deployment以及service,同時自研實現(xiàn)服務(wù)拓撲感知,使得服務(wù)閉環(huán)訪問
- edge-admission:通過邊端節(jié)點分布式健康檢查的狀態(tài)報告決定節(jié)點是否健康,并協(xié)助cloud-kube-controller執(zhí)行相關(guān)處理動作(打taint)
邊緣組件
邊端除了原生Kubernetes worker節(jié)點需要部署的kubelet,kube-proxy外,還添加了如下邊緣計算組件:
- lite-apiserver:邊緣自治的核心組件,是cloud-kube-apiserver的代理服務(wù),緩存了邊緣節(jié)點組件對apiserver的某些請求,當(dāng)遇到這些請求而且與cloud-kube-apiserver網(wǎng)絡(luò)存在問題的時候會直接返回給client端
- edge-health:邊端分布式健康檢查服務(wù),負責(zé)執(zhí)行具體的監(jiān)控和探測操作,并進行投票選舉判斷節(jié)點是否健康
- tunnel-edge:負責(zé)建立與云端邊緣集群tunnel-cloud的網(wǎng)絡(luò)隧道,并接受API請求,轉(zhuǎn)發(fā)給邊緣節(jié)點組件(kubelet)
- application-grid wrapper:與application-grid controller結(jié)合完成ServiceGrid內(nèi)的閉環(huán)服務(wù)訪問(服務(wù)拓撲感知)
功能概述
應(yīng)用部署&服務(wù)訪問控制
superedge可以支持原生Kubernetes的所有工作負載的應(yīng)用部署,包括:
- deployment
- statefulset
- daemonset
- job
- cronjob
而對于邊緣計算應(yīng)用來說,具備如下獨特點:
- 邊緣計算場景中,往往會在同一個集群中管理多個邊緣站點,每個邊緣站點內(nèi)有一個或多個計算節(jié)點
- 同時希望在每個站點中都運行一組有業(yè)務(wù)邏輯聯(lián)系的服務(wù),每個站點內(nèi)的服務(wù)是一套完整的功能,可以為用戶提供服務(wù)
- 由于受到網(wǎng)絡(luò)限制,有業(yè)務(wù)聯(lián)系的服務(wù)之間不希望或者不能跨站點訪問
為了解決上述問題,superedge創(chuàng)新性地構(gòu)建了ServiceGroup概念,方便用戶便捷地在共屬同一個集群的不同機房或區(qū)域中各自部署一組服務(wù),并且使得各個服務(wù)間的請求在本機房或本地域內(nèi)部即可完成(閉環(huán)),避免了服務(wù)跨地域訪問
ServiceGroup中涉及幾個關(guān)鍵概念:

NodeUnit
- NodeUnit通常是位于同一邊緣站點內(nèi)的一個或多個計算資源實例,需要保證同一NodeUnit中的節(jié)點內(nèi)網(wǎng)是通的
- ServiceGroup組中的服務(wù)運行在一個NodeUnit之內(nèi)
- ServiceGroup允許用戶設(shè)置服務(wù)在一個NodeUnit中運行的pod(belongs to deployment)數(shù)量
- ServiceGroup能夠把服務(wù)之間的調(diào)用限制在本NodeUnit內(nèi)
NodeGroup
- NodeGroup包含一個或者多個 NodeUnit
- 保證在集合中每個NodeUnit上均部署ServiceGroup中的服務(wù)
- 當(dāng)集群中增加NodeUnit時會自動將ServiceGroup中的服務(wù)部署到新增NodeUnit
ServiceGroup
- ServiceGroup包含一個或者多個業(yè)務(wù)服務(wù)
- 適用場景:
- 業(yè)務(wù)需要打包部署;
- 需要在每一個NodeUnit中均運行起來并且保證pod數(shù)量
- 需要將服務(wù)之間的調(diào)用控制在同一個 NodeUnit 中,不能將流量轉(zhuǎn)發(fā)到其他NodeUnit上
- 注意:ServiceGroup是一種抽象資源概念,一個集群中可以創(chuàng)建多個ServiceGroup
下面以一個具體例子說明ServiceGroup功能:
# step1: labels edge nodes
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
node0 Ready <none> 16d v1.16.7
node1 Ready <none> 16d v1.16.7
node2 Ready <none> 16d v1.16.7
# nodeunit1(nodegroup and servicegroup zone1)
$ kubectl --kubeconfig config label nodes node0 zone1=nodeunit1
# nodeunit2(nodegroup and servicegroup zone1)
$ kubectl --kubeconfig config label nodes node1 zone1=nodeunit2
$ kubectl --kubeconfig config label nodes node2 zone1=nodeunit2
# step2: deploy echo DeploymentGrid
$ cat <<EOF | kubectl --kubeconfig config apply -f -
apiVersion: superedge.io/v1
kind: DeploymentGrid
metadata:
name: deploymentgrid-demo
namespace: default
spec:
gridUniqKey: zone1
template:
replicas: 2
selector:
matchLabels:
appGrid: echo
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
appGrid: echo
spec:
containers:
- image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
name: echo
ports:
- containerPort: 8080
protocol: TCP
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
resources: {}
EOF
deploymentgrid.superedge.io/deploymentgrid-demo created
# note that there are two deployments generated and deployed into both nodeunit1 and nodeunit2
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
deploymentgrid-demo-nodeunit1 2/2 2 2 5m50s
deploymentgrid-demo-nodeunit2 2/2 2 2 5m50s
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploymentgrid-demo-nodeunit1-65bbb7c6bb-6lcmt 1/1 Running 0 5m34s 172.16.0.16 node0 <none> <none>
deploymentgrid-demo-nodeunit1-65bbb7c6bb-hvmlg 1/1 Running 0 6m10s 172.16.0.15 node0 <none> <none>
deploymentgrid-demo-nodeunit2-56dd647d7-fh2bm 1/1 Running 0 5m34s 172.16.1.12 node1 <none> <none>
deploymentgrid-demo-nodeunit2-56dd647d7-gb2j8 1/1 Running 0 6m10s 172.16.2.9 node2 <none> <none>
# step3: deploy echo ServiceGrid
$ cat <<EOF | kubectl --kubeconfig config apply -f -
apiVersion: superedge.io/v1
kind: ServiceGrid
metadata:
name: servicegrid-demo
namespace: default
spec:
gridUniqKey: zone1
template:
selector:
appGrid: echo
ports:
- protocol: TCP
port: 80
targetPort: 8080
EOF
servicegrid.superedge.io/servicegrid-demo created
# note that there is only one relevant service generated
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 192.168.0.1 <none> 443/TCP 16d
servicegrid-demo-svc ClusterIP 192.168.6.139 <none> 80/TCP 10m
# step4: access servicegrid-demo-svc(service topology and closed-looped)
# execute on onde0
$ curl 192.168.6.139|grep "node name"
node name: node0
# execute on node1 and node2
$ curl 192.168.6.139|grep "node name"
node name: node2
$ curl 192.168.6.139|grep "node name"
node name: node1
通過上面的例子總結(jié)ServiceGroup如下:
- NodeUnit和NodeGroup以及ServiceGroup都是一種概念,具體來說實際使用中對應(yīng)關(guān)系如下:
- NodeUnit是具有相同label key以及value的一組邊緣節(jié)點
- NodeGroup是具有相同label key的一組NodeUnit(不同value)
- ServiceGroup具體由兩種CRD構(gòu)成:DepolymentGrid以及ServiceGrid,具備相同的gridUniqKey
- gridUniqKey值與NodeGroup的label key對應(yīng),也即ServiceGroup是與NodeGroup一一對應(yīng),而NodeGroup對應(yīng)多個NodeUnit,同時NodeGroup中的每一個NodeUnit都會部署ServiceGroup對應(yīng)deployment,這些deployment(deploymentgridName-NodeUnit命名)通過nodeSelector親和性固定某個NodeUnit上,并通過服務(wù)拓撲感知限制在該NodeUnit內(nèi)訪問
分布式健康檢查
邊緣計算場景下,邊緣節(jié)點與云端的網(wǎng)絡(luò)環(huán)境十分復(fù)雜,連接并不可靠,在原生Kubernetes集群中,會造成apiserver和節(jié)點連接的中斷,節(jié)點狀態(tài)的異常,最終導(dǎo)致pod的驅(qū)逐和endpoint的缺失,造成服務(wù)的中斷和波動,具體來說原生Kubernetes處理如下:
- 失聯(lián)的節(jié)點被置為ConditionUnknown狀態(tài),并被添加NoSchedule和NoExecute的taints
- 失聯(lián)的節(jié)點上的pod被驅(qū)逐,并在其他節(jié)點上進行重建
- 失聯(lián)的節(jié)點上的pod從Service的Endpoint列表中移除
因此,邊緣計算場景僅僅依賴邊端和apiserver的連接情況是不足以判斷節(jié)點是否異常的,會因為網(wǎng)絡(luò)的不可靠造成誤判,影響正常服務(wù)。而相較于云端和邊緣端的連接,顯然邊端節(jié)點之間的連接更為穩(wěn)定,具有一定的參考價值,因此superedge提出了邊緣分布式健康檢查機制。該機制中節(jié)點狀態(tài)判定除了要考慮apiserver的因素外,還引入了節(jié)點的評估因素,進而對節(jié)點進行更為全面的狀態(tài)判斷。通過這個功能,能夠避免由于云邊網(wǎng)絡(luò)不可靠造成的大量的pod遷移和重建,保證服務(wù)的穩(wěn)定
具體來說,主要通過如下三個層面增強節(jié)點狀態(tài)判斷的準確性:
- 每個節(jié)點定期探測其他節(jié)點健康狀態(tài)
- 集群內(nèi)所有節(jié)點定期投票決定各節(jié)點的狀態(tài)
- 云端和邊端節(jié)點共同決定節(jié)點狀態(tài)
而分布式健康檢查最終的判斷處理如下:
節(jié)點最終狀態(tài) |
云端判定正常 |
云端判定異常 |
節(jié)點內(nèi)部判定正常 |
正常 |
不再調(diào)度新的pod到該節(jié)點(NoSchedule taint) |
節(jié)點內(nèi)部判定異常 |
正常 |
驅(qū)逐存量pod;從Endpoint列表摘除pod;不再調(diào)度新的pod到該節(jié)點 |
邊緣自治
對于邊緣計算的用戶來說,他們除了想要享受Kubernetes自身帶來的管理運維的便捷之外,同時也想具備弱網(wǎng)環(huán)境下的容災(zāi)能力,具體來說,如下:
- 節(jié)點即使和master失聯(lián),節(jié)點上的業(yè)務(wù)能繼續(xù)運行
- 保證如果業(yè)務(wù)容器異常退出或者掛掉,kubelet 能繼續(xù)拉起
- 還要保證節(jié)點重啟后,業(yè)務(wù)能繼續(xù)重新被拉起來
- 用戶在廠房內(nèi)部署的是微服務(wù),需要保證節(jié)點重啟后,同一個廠房內(nèi)的微服務(wù)可以訪問
而對于標準的Kubernentes,如果節(jié)點斷網(wǎng)失聯(lián)并且發(fā)生異常重啟的行為后,現(xiàn)象如下:
- 失聯(lián)的節(jié)點狀態(tài)置為ConditionUnknown狀態(tài)
- 失聯(lián)的節(jié)點上的業(yè)務(wù)進程異常退出后,容器可以被拉起
- 失聯(lián)的節(jié)點上的 Pod IP 從 Endpoint 列表中摘除
- 失聯(lián)的節(jié)點發(fā)生重啟后,容器全部消失不會被拉起
superedge自研的邊緣自治就是為了解決上述問題的,具體來說邊緣自治能達到如下效果:
- 節(jié)點會被置為ConditionUnknown狀態(tài),但是服務(wù)依舊可用(pod不會被驅(qū)逐以及從endpoint列表中剔除)
- 多節(jié)點斷網(wǎng)情況下,Pod 業(yè)務(wù)正常運行,微服務(wù)能力正常提供
- 多節(jié)點斷網(wǎng)情況下并重啟后,Pod 會被重新拉起并正常運行
- 多節(jié)點斷網(wǎng)情況下并重啟后,所有的微服務(wù)可以被正常訪問
其中,對于前兩點來說可以通過上述介紹的分布式健康檢查機制來實現(xiàn),而后續(xù)兩點可以通過lite-apiserver,網(wǎng)絡(luò)快照以及DNS解決方案實現(xiàn),如下:
lite-apiserver機制
superedge通過在邊端加了一層鏡像lite-apiserver組件,使得所有邊端節(jié)點對于云端kube-apiserver的請求,都會指向lite-apiserver組件:

而lite-apiserver其實就是個代理,緩存了一些kube-apiserver請求,當(dāng)遇到這些請求而且與apiserver不通的時候就直接返回給client:

總的來說:對于邊緣節(jié)點的組件,lite-apiserver提供的功能就是kube-apiserver,但是一方面lite-apiserver只對本節(jié)點有效,另一方面資源占用很少。在網(wǎng)絡(luò)通暢的情況下,lite-apiserver組件對于節(jié)點組件來說是透明的;而當(dāng)網(wǎng)絡(luò)異常情況,lite-apiserver組件會把本節(jié)點需要的數(shù)據(jù)返回給節(jié)點上組件,保證節(jié)點組件不會受網(wǎng)絡(luò)異常情況影響
網(wǎng)絡(luò)快照
通過lite-apiserver可以實現(xiàn)邊緣節(jié)點斷網(wǎng)情況下重啟后pod可以被正常拉起,但是根據(jù)原生Kubernetes原理,拉起后的pod ip會發(fā)生改變,這在某些情況下是不能允許的,為此superedge設(shè)計了網(wǎng)絡(luò)快照機制保障邊緣節(jié)點重啟,pod拉起后ip保存不變。具體來說就是將節(jié)點上組件的網(wǎng)絡(luò)信息定期快照,并在節(jié)點重啟后進行恢復(fù)
本地DNS解決方案
通過lite-apiserver以及網(wǎng)絡(luò)快照機制可以保障邊緣節(jié)點斷網(wǎng)情況下重啟后,Pod會被重新拉起并正常運行,同時微服務(wù)也運行正常。而服務(wù)之間相互訪問就會涉及一個域名解析的問題:通常來說在集群內(nèi)部我們使用coredns來做域名解析,且一般部署為Deployment形式,但是在邊緣計算情況下,節(jié)點之間可能是不在一個局域網(wǎng),很可能是跨可用區(qū)的,這個時候coredns服務(wù)就可能訪問不通。為了保障dns訪問始終正常,superedge設(shè)計了專門的本地dns解決方案,如下:

本地dns采用DaemonSet方式部署coredns,保證每個節(jié)點都有可用的coredns,同時修改每個節(jié)點上kubelet的啟動參數(shù)--cluster-dns ,將其指向本機私有IP(每個節(jié)點都相同)。這樣就保證了即使在斷網(wǎng)的情況下也能進行域名解析。
總的來說,superedge是以lite-apiserver機制為基礎(chǔ),并結(jié)合分布式健康檢查機制、網(wǎng)絡(luò)快照以及本地coredns,保證了邊緣容器集群在弱網(wǎng)環(huán)境下的網(wǎng)絡(luò)可靠性。另外隨著邊緣自治的級別越高,所需要的組件會越來越多
云邊隧道
最后介紹一下superedge的云邊隧道,云邊隧道主要用于:代理云端訪問邊緣節(jié)點組件的請求,解決云端無法直接訪問邊緣節(jié)點的問題(邊緣節(jié)點沒有暴露在公網(wǎng)中)
架構(gòu)圖如下所示:

實現(xiàn)原理為:
- 邊緣節(jié)點上tunnel-edge主動連接云端tunnel-cloud service,tunnel-cloud service根據(jù)負載均衡策略將請求轉(zhuǎn)到tunnel-cloud的具體pod上
- tunnel-edge與tunnel-cloud建立grpc連接后,tunnel-cloud會把自身的podIp和tunnel-edge所在節(jié)點的nodeName的映射寫入DNS(tunnel dns)。grpc連接斷開之后,tunnel-cloud會刪除相關(guān)podIp和節(jié)點名的映射
而整個請求的代理轉(zhuǎn)發(fā)流程如下:
- apiserver或者其它云端的應(yīng)用訪問邊緣節(jié)點上的kubelet或者其它應(yīng)用時,tunnel-dns通過DNS劫持(將host中的節(jié)點名解析為tunnel-cloud的podIp)把請求轉(zhuǎn)發(fā)到tunnel-cloud的pod上
- tunnel-cloud根據(jù)節(jié)點名把請求信息轉(zhuǎn)發(fā)到節(jié)點名對應(yīng)的與tunnel-edge建立的grpc連接上
- tunnel-edge根據(jù)接收的請求信息請求邊緣節(jié)點上的應(yīng)用
總結(jié)
本文依次介紹了開源邊緣計算框架SuperEdge的特性,整體架構(gòu)以及主要功能和原理。其中分布式健康檢查以及邊緣集群服務(wù)訪問控制ServiceGroup是SuperEdge獨有的特性功能。分布式健康檢查很大程度避免了由于云邊網(wǎng)絡(luò)不可靠造成的大量pod遷移和重建,保證了服務(wù)的穩(wěn)定;而ServiceGroup則極大地方便了用戶在共屬同一個集群的不同機房或區(qū)域中各自部署一組服務(wù),并且使得各個服務(wù)間的請求在本機房或本地域內(nèi)部即可完成(閉環(huán)),避免了服務(wù)跨地域訪問。除此之外還有邊緣自治以及云邊隧道等功能。
整體來說,SuperEdge采用無侵入的方式構(gòu)建邊緣集群,在原有Kubernetes組件保留不變的基礎(chǔ)上新增了一些組件完成邊緣計算的功能,既保留了Kubernetes強大的編排系統(tǒng),同時也具備完善的邊緣計算能力。
|