English | 简体中文
EdgeMesh 作为 KubeEdge 的一部分,为边缘场景下的服务互访提供了简单的网络方案。
KubeEdge基于Kubernetes构建,将云原生容器化应用程序编排能力延伸到了边缘。但是,在边缘计算场景下,网络拓扑较为复杂,不同区域中的边缘节点往往网络不互通,并且应用之间流量的互通是业务的首要需求,而EdgeMesh正是对此提供了一套解决方案。
EdgeMesh作为KubeEdge集群的数据面组件,为KubeEdge集群中的应用程序提供了简单的服务发现与流量代理功能,从而屏蔽了边缘场景下复杂的网络结构。
EdgeMesh 满足边缘场景下的新需求(如边缘资源有限,边云网络不稳定等),即实现了高可用性,高可靠性和极致轻量化:
- 高可用性
- 利用 KubeEdge 中的边云通道,来打通边缘节点间的网络
- 将边缘节点间的通信分为局域网内和跨局域网
- 局域网内的通信:直接访问
- 跨局域网的通信:通过云端转发
- 高可靠性 (离线场景)
- 控制面和数据面流量都通过边云通道下发
- EdgeMesh 内部实现轻量级的 DNS 服务器,不再访问云端 DNS
- 极致轻量化
- 每个节点有且仅有一个 EdgeMesh,节省边缘资源
- 对于资源受限的边缘设备,EdgeMesh 提供了一个轻量化且具有高集成度的服务发现软件
- 在现场边缘的场景下,相对于 coredns + kube-proxy + cni 这一套服务发现机制,用户只需要简单地部署一个 EdgeMesh 就能完成目标
功能 | 子功能 | 实现度 |
---|---|---|
服务发现 | / | ✓ |
流量治理 | HTTP | ✓ |
TCP | ✓ | |
Websocket | ✓ | |
HTTPS | ✓ | |
负载均衡 | 随机 | ✓ |
轮询 | ✓ | |
会话保持 | ✓ | |
外部访问 | / | ✓ |
多网卡监听 | / | ✓ |
跨子网通信 | 跨边云通信 | + |
跨局域网边边通信 | + | |
边缘CNI | 跨子网Pod通信 | + |
注:
✓
EdgeMesh 版本所支持的功能+
EdgeMesh 版本不具备的功能,但在后续版本中会支持-
EdgeMesh 版本不具备的功能,或已弃用的功能
目前, EdgeMesh 的功能实现依赖于主机网络的连通性。未来, EdgeMesh 将会实现 CNI 插件的能力,以兼容主流 CNI 插件(例如 flannel / calico 等)的方式实现边缘节点和云上节点、跨局域网边缘节点之间的 Pod 网络连通。最终, EdgeMesh 甚至可以将部分自身组件替换成云原生组件(例如替换 kube-proxy 实现 Cluster IP 层的能力、替换 node local dns cache 实现节点级 dns 的能力、替换 envoy 实现 mesh 层的能力)。
为了保证一些低版本内核、低版本 iptables 边缘设备的服务发现能力,EdgeMesh 在流量代理的实现上采用了 userspace 模式,除此之外还自带了一个轻量级的DNS解析器。如图所示,EdgeMesh的核心组件包括:
- Proxier: 负责配置内核的iptables规则,将请求拦截到EdgeMesh进程内
- DNS: 内置的DNS解析器,将节点内的域名请求解析成一个服务的集群IP
- Traffic: 基于Go-chassis框架的流量转发模块,负责转发应用间的流量
- Controller: 通过KubeEdge的边缘侧list-watch能力获取Service、Endpoints、Pod等元数据
- EdgeMesh 通过 KubeEdge 边缘侧 list-watch 的能力,监听Service、Endpoints等元数据的增删改,再根据 Service、EndPoints 的信息创建iptables规则
- EdgeMesh 使用与 K8s Service 相同的 Cluster IP 和域名的方式来访问服务
- 当 client 访问服务的请求到达带有EdgeMesh的节点后,它首先会进入内核的 iptables
- EdgeMesh 之前配置的 iptables 规则会将请求重定向,全部转发到 EdgeMesh 进程的40001端口里(数据包从内核态->用户态)
- 请求进入 EdgeMesh 进程后,由 EdgeMesh 进程完成后端 Pod 的选择(负载均衡在这里发生),然后将请求发到这个 Pod 所在的主机上
在使用edgemesh之前,您需要先了解以下预备知识:
- 使用 EdgeMesh 能力时,必须要求 Pod 要开启一个 HostPort,例子可看 /examples/ 目录下面的文件
- 使用 DestinationRule 时,要求 DestinationRule 的名字与相应的 Service 的名字要一致,EdgeMesh 会根据 Service 的名字来确定同命名空间下面的DestinationRule
- Service 的端口必须命名。端口名键值对必须按以下格式:name: <protocol>[-<suffix>]
在边缘节点,关闭 edgemesh,打开 metaserver,并重启 edgecore
$ vim /etc/kubeedge/config/edgecore.yaml
modules:
..
edgeMesh:
enable: false
metaManager:
metaServer:
enable: true
..
$ systemctl restart edgecore
在云端,开启 dynamic controller 模块,并重启 cloudcore
$ vim /etc/kubeedge/config/cloudcore.yaml
modules:
..
dynamicController:
enable: true
..
在边缘节点,查看 list-watch 是否开启
$ curl 127.0.0.1:10550/api/v1/services
{"apiVersion":"v1","items":[{"apiVersion":"v1","kind":"Service","metadata":{"creationTimestamp":"2021-04-14T06:30:05Z","labels":{"component":"apiserver","provider":"kubernetes"},"name":"kubernetes","namespace":"default","resourceVersion":"147","selfLink":"default/services/kubernetes","uid":"55eeebea-08cf-4d1a-8b04-e85f8ae112a9"},"spec":{"clusterIP":"10.96.0.1","ports":[{"name":"https","port":443,"protocol":"TCP","targetPort":6443}],"sessionAffinity":"None","type":"ClusterIP"},"status":{"loadBalancer":{}}},{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"prometheus.io/port":"9153","prometheus.io/scrape":"true"},"creationTimestamp":"2021-04-14T06:30:07Z","labels":{"k8s-app":"kube-dns","kubernetes.io/cluster-service":"true","kubernetes.io/name":"KubeDNS"},"name":"kube-dns","namespace":"kube-system","resourceVersion":"203","selfLink":"kube-system/services/kube-dns","uid":"c221ac20-cbfa-406b-812a-c44b9d82d6dc"},"spec":{"clusterIP":"10.96.0.10","ports":[{"name":"dns","port":53,"protocol":"UDP","targetPort":53},{"name":"dns-tcp","port":53,"protocol":"TCP","targetPort":53},{"name":"metrics","port":9153,"protocol":"TCP","targetPort":9153}],"selector":{"k8s-app":"kube-dns"},"sessionAffinity":"None","type":"ClusterIP"},"status":{"loadBalancer":{}}}],"kind":"ServiceList","metadata":{"resourceVersion":"377360","selfLink":"/api/v1/services"}}
构建 edgemesh 容器镜像 (非必须)
# 在项目目录下执行如下操作
$ docker build -t edgemesh:0.1 -f build/Dockerfile .
部署 edgemesh 组件
# 请将03-configmap.yaml里面的subNet配置成kube-apiserver的service-cluster-ip-range的值
# 你可以在k8s master节点上的/etc/kubernetes/manifests/kube-apiserver.yaml文件中找到这个配置项的值
$ kubectl apply -f build/kubernetes/edgemesh/03-configmap.yaml
configmap/edgemesh-cfg created
$ kubectl apply -f build/kubernetes/edgemesh/04-daemonset.yaml
daemonset.apps/edgemesh created
HTTP协议
在边缘节点上,部署支持 http 协议的容器应用和相关服务
$ kubectl apply -f example/hostname.yaml
到边缘节点上,使用 curl 去访问相关服务,打印出容器的 hostname
$ curl hostname-lb-svc.edgemesh-test:12345
TCP协议
在边缘节点1,部署支持 tcp 协议的容器应用和相关服务
$ kubectl apply -f example/tcp-echo-service.yaml
在边缘节点2,使用 telnet 去访问相关服务
$ telnet tcp-echo-service.edgemesh-test 2701
Websocket协议
在边缘节点1,部署支持 websocket 协议的容器应用和相关服务
$ kubectl apply -f example/websocket-pod-svc.yaml
进入 websocket 的容器环境,并使用 client 去访问相关服务
$ docker exec -it 2a6ae1a490ae bash
$ ./client --addr ws-svc.edgemesh-test:12348
负载均衡
负载均衡功能需要添加 DestinationRule 用户自定义资源
$ kubectl apply -f build/istio/destinationrule-crd.yaml
customresourcedefinition.apiextensions.k8s.io/destinationrules.networking.istio.io created
使用 DestinationRule 中的 loadBalancer 属性来选择不同的负载均衡模式
$ vim example/hostname-lb-random.yaml
spec
..
trafficPolicy:
loadBalancer:
simple: RANDOM
..
EdgeMesh ingress gateway 提供了外部访问集群里服务的能力。
创建 Gateway 和 VirtualService 用户自定义资源
$ kubectl apply -f build/istio/gateway-crd.yaml
customresourcedefinition.apiextensions.k8s.io/gateways.networking.istio.io created
$ kubectl apply -f build/istio/virtualservice-crd.yaml
customresourcedefinition.apiextensions.k8s.io/virtualservices.networking.istio.io created
部署 edgemesh-gateway
$ kubectl apply -f build/kubernetes/edgemesh-gateway/03-configmap.yaml
configmap/edgemesh-gateway-cfg created
$ kubectl apply -f build/kubernetes/edgemesh-gateway/04-deployment.yaml
deployment.apps/edgemesh-gateway created
创建 gateway 资源对象和路由规则 VirtualService
$ kubectl apply -f example/hostname-lb-random-gateway.yaml
pod/hostname-lb-edge2 created
pod/hostname-lb-edge3 created
service/hostname-lb-svc created
gateway.networking.istio.io/edgemesh-gateway configured
destinationrule.networking.istio.io/hostname-lb-edge created
virtualservice.networking.istio.io/edgemesh-gateway-svc created
查看 edgemesh-gateway 是否部署成功
$ kubectl get gw -n edgemesh-test
NAME AGE
edgemesh-gateway 3m30s
最后,使用 IP 和 VirtualService 暴露的端口来进行访问
$ curl 192.168.0.211:12345
创建测试密钥文件
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=kubeedge.io"
Generating a RSA private key
............+++++
.......................................................................................+++++
writing new private key to 'tls.key'
-----
根据密钥文件创建 Secret 资源对象
$ kubectl create secret tls gw-secret --key tls.key --cert tls.crt -n edgemesh-test
secret/gw-secret created
创建绑定了 Secret 的 Gateway 资源对象和路由规则 VirtualService
$ kubectl apply -f example/hostname-lb-random-gateway-tls.yaml
pod/hostname-lb-edge2 created
pod/hostname-lb-edge3 created
service/hostname-lb-svc created
gateway.networking.istio.io/edgemesh-gateway configured
destinationrule.networking.istio.io/hostname-lb-edge created
virtualservice.networking.istio.io/edgemesh-gateway-svc created
最后,使用证书进行 HTTPS 访问
$ curl -k --cert ./tls.crt --key ./tls.key https://192.168.0.129:12345
如果您需要支持,请从 '操作指导' 开始,然后按照我们概述的流程进行操作。
如果您有任何疑问,请通过 KubeEdge官网 推荐的联系方式与我们联系