Skip to main content

One post tagged with "openyurt"

View All Tags

Edge LoadBalancer service support based on MetalLB

· 阅读需要 1 分钟
zzguang
Reviewer of OpenYurt

背景介绍

在云边协同场景下,虽然云端已经具备了较为全面的云原生能力,但边缘侧由于特定的网络环境及应用场景的限制,往往无法提供像云端一样丰富的能力,而实际上用户业务应用的主战场却在边缘侧, 这就导致边缘侧在使用云原生能力的时候或多或少存在一些gaps,而如何解决这些gaps也成为云边协同基础设施软件力求解决的关键问题。本文针对边缘侧服务暴露给集群外访问的场景,来探讨一下在 OpenYurt边缘侧解决上述问题的方法,希望能起到抛砖引玉的效果。

在原生Kubernetes集群中,如果想将服务暴露出来供集群外部访问,通常可以考虑以下几种方式:

  • HostNetwork
  • ExternalIPs
  • NodePort
  • LoadBalancer
  • Ingress

其中前三种方式,由于自身存在一定的局限性,在条件允许的情况下,通常用户更倾向于选择后两种方式。而对Ingress方式而言,云端Ingress功能通常会搭配云端SLB服务一起使用, SLB负责从用户请求到节点维度的负载均衡,而Ingress负责从节点到pod维度的负载均衡,这样就实现了从用户请求到应用pod的全链路的负载均衡功能。然而在云边协同场景下,由于边缘侧并不具备云端SLB服务的能力,边缘Ingress或边缘应用无法暴露LoadBalancer类型的服务供集群外访问,这也成为了边缘侧对外暴露服务的一大痛点。

为了解决上述痛点,目前在开源社区,有几个方案可供选择:MetalLB, PureLB和OpenELB。

关于三个项目之间的比较,可以从网上查到一些相关介绍,整体来说,它们实现的功能大同小异,从项目成熟度及流行度的角度考虑,我们选择以MetalLB为例,探讨一下如何通过MetalLB在OpenYurt 边缘侧实现对LoadBalancer类型service的支持。

Kubernetes与OpenYurt无缝转换(命令式)

· 阅读需要 1 分钟
adamzhoul
Member of OpenYurt

打开openYurt的README.md,在简单介绍之后就是Getting started:

 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

简单一行命令就可体验OpenYurt了,感觉非常方便。

稍等!为什么是 convert/revert 而不是 install/uninstall ?

这个命令对集群做了什么?

看来,在执行它之前有必要搞清楚它到底做了什么。

yurtctl convert 到底做了些什么?

核心流程

跟随openYurt源代码,梳理了convert的核心流程:

1. 检查
   1.1 检查所有node节点状态为ready
2. 组件部署
  2.1 给node节点打上相应的label。
  2.2 使用deployment部署yurt-controller-manager。
  2.3 使用deployment部署yurt-tunnel-server。
  2.4 使用daemonset部署yurt-tunnel-agent,部署在边缘节点上。
  2.5 使用deployment部署yurt-app-manager。
3. k8s组件修改
  3.1 修改kube-controller-manager.yaml,用来disable nodelifecycle controller
4. 节点转换
   4.1 写入yurthub.yaml到/etc/kubernetes/manifests,启动静态pod
   4.2 修改kubelet配置,使得kubelet访问yurthub而不是直连apiServer

可见1、2并没有什么特别,只是常规的服务部署

3,则是对原有k8s系统组件的操作,需要特别注意

4-节点转换看着也并不复杂,却对边缘至关重要。

disable nodelifecycle controller 做了什么?

工作内容:

  1. 查询控制面节点
  2. 创建job,通过 nodeName: {{.nodeName}} 确保job的pod调度到对应node上执行(通过nsenter的方式执行,修改宿主机上文件)。
  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的启动命令。

查看kube-controller-manager启动参数说明:

--controllers 代表需要开启的controller列表

可见,sed命令就是去掉了nodelifecycle这个controller。

那,nodelifecycle controller是做什么的?

简单来说:

  1. 不断监听,kubelet上报上来的node信息
  2. 如果某个node状态异常,或者说长时间没有上报等 2.1 驱逐这个node节点或者其他 ---> 导致上面的pod被重新调度

可见,对于处于弱网环境的边缘节点,很容易就命中异常状态,导致node被驱逐,pod被重新调度。

所以这里把它去掉了。使用yurt-controller-manager来代替它。

即使节点心跳丢失,处于自治模式的节点中的pod也不会从APIServer中驱逐。

注:这里自治模式的节点,指的就是边缘节点。我们通常会通过加annotation的方式把节点标记为自治节点。

节点转换是怎么实现的,云端节点和边缘节点有什么差异?

同样,是通过跑job的方式,在目标宿主机上下文中执行相关操作。

不过,相比于暴力使用nsenter,这里用了更加优雅的方式。通过将宿主机根路径 volume挂载到容器里的方式。

kubelet的修改

在文件/var/lib/kubelet/kubeadm-flags.env 中为KUBELET_KUBEADM_ARGS添加配置:

--kubeconfig=/var/lib/openyurt/kubelet.conf --bootstrap-kubeconfig=

作用:

  1. 参数:--kubeconfig , 给kubelet指定了访问apiServer的配置文件。
  2. 当--kubeconfig 文件存在,--bootstrap-kubeconfig为空时, kubelet启动就不需要通过bootstrap-token置换文件证书等过程,直接读取kubeconfig文件访问apiServer。
  3. 由于KUBELET_KUBEADM_ARGS 是kubelet启动参数的最后一部分,所以可以起到覆盖前面参数的作用。

其中/var/lib/openyurt/kubelet.conf内容如下,直接将流量指定到yurthub:

apiVersion: v1
clusters:
- cluster:
server: http://127.0.0.1:10261
name: default-cluster
contexts:
- context:
cluster: default-cluster
namespace: default
user: default-auth
name: default-context
current-context: default-context
kind: Config
preferences: {}
yurthub的启动细节

yurthub容器启动参数如下:

command:
- yurthub
- --v=2
- --server-addr=__kubernetes_service_addr__
- --node-name=$(NODE_NAME)
- --join-token=__join_token__
- --working-mode=__working_mode__

通过参数我们可看出:

  1. server-addr 指定了云端apiServer地址。注意这里的地址一定是公网可访问地址,否则异构网络下会有问题。
  2. join-token 就是加入节点的token,可使用kubeadm token create来创建。k8s提供机制,通过token置换出正常访问的kubeconf文件。
  3. working-mode: cloud/edge。这就是边缘节点和云端节点的差异。

我们都知道yurthub可以用来做缓存,是解决边缘自治的重要环节。那么云端为什么也需要部署?为什么还要区分edge或者cloud工作模式?

简单查看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 可了解:云端也可以利用yurthub提供的data-filtering能力来控制service的流量

当然,云端也不需要做cache等工作。

命令行参数

在执行过程中,有几个参数比较重要:

--cloud-nodes 用于标识哪些是云端节点,多个节点用逗号分隔:node1,node2

--deploy-yurttunnel 标记是否要部署yurttunnel

--kubeadm-conf-path 标记节点机器上kubeadm配置文件路径。默认:/etc/systemd/system/kubelet.service.d/10-kubeadm.conf

更多参数,可使用 yurtctl convert --help 来查看。

总结

简单来说,convert核心做了几个事情:

  1. disable k8s 的nodelifecontroller,用自己的yurtcontrollermanager来替换它的职责。
  2. 安装自己的各类组件,deployment、damenonset 等模式部署。(这类资源部署无需任何担心,因为搞不坏集群,也不太会出现问题。)
  3. 边缘节点:启动yurthub静态pod;将kubelet流量转发到yurthub。

可见,convert的事情还是比较可控的。执行yurtctl convert 也不用太担心。

当然,最后的担心也应该由 yurtctl revert 来彻底消除!

yurtctl revert 又干了些什么?

核心流程

  1. 检查 1.1 确保所有node都已经ready
  2. 删除自身部署组件 2.1 删除 yurt-controller-manager deployment以及相关资源 2.2 删除yurt-tunnel-agent以及相关资源 2.2 删除yurt-tunnel-server以及相关资源
    2.3 删除yurt-app-manager以及相关资源
  3. k8s组件修改 3.1 开启nodelifecontroller, 这个很好理解,就是把修改的命令通过sed命令改回来。
  4. 云端、边缘节点转换为原生节点 4.1 修改kubelet配置,直连apiServer 4.2 删除yurthub相关配置、目录

整个revert的过程就是convert的反向操作,还比较好理解。

需要注意的是。如果convert失败,比如job执行超时或者失败。job是不会被删除的。

即使yurtctl revert 也不会删除。目的是为了保留现场方便定位问题。

如果需要重新执行yurtctl convert, 需要手动删除job。

kubectl get job -n kube-system -A |grep convert
kubectl delete job -n kube-system < job-name>

总结

yurtctl convert/revert 命令是最快捷体验openYurt功能的方法之一。

在了解了这两个命令的实现原理,也就对openYurt的技术方案了解大半了。

执行命令也不担心了,so easy!

OpenYurt边缘流量闭环能力解析

· 阅读需要 1 分钟
Feng Zeng
Zhejiang University student, Member of OpenYurt

服务拓扑

服务拓扑(Service Topology)可以让一个服务根据集群的节点拓扑进行流量路由。 例如,一个服务可以指定流量被优先路由到和客户端 pod 相同的节点或者节点池上。

通过在原生的 Service 上添加 Annotation 实现流量的拓扑配置,相关参数如下所示:

annotation Keyannotation Value说明
openyurt.io/topologyKeyskubernetes.io/hostname流量被路由到相同的节点
openyurt.io/topologyKeysopenyurt.io/nodepool

kubernetes.io/zone
流量被路由到相同的节点池

下图为服务拓扑功能的一个例子。service-ud1 添加了注解 openyurt.io/topologyKeys: openyurt.io/nodepool , 当 pod6 访问 service-ud1 的时候,由于 pod6 位于 edge node2,也就是位于杭州节点池,因此其流量只会发往杭州节点池的 pod1pod2上,而不会跨节点池,所以 pod3pod4 收不到。从而实现了同一个节点池中的流量闭环。

service-topology

前提条件

  1. Kubernetes v1.18或以上版本,因为需要支持 EndpointSlice 资源。
  2. 集群中部署了 Yurt-app-manager。

使用方法演示

确保 Kubernetes 版本大于1.18。

$ kubectl get node
NAME                 STATUS   ROLES    AGE     VERSION
kind-control-plane   Ready    master   6m21s   v1.18.19
kind-worker          Ready    <none>   5m42s   v1.18.19
kind-worker2         Ready    <none>   5m42s   v1.18.19

确保集群中部署了 Yurt-app-manager。

$ kubectl get pod -n kube-system 
NAME                                         READY   STATUS    RESTARTS   AGE
coredns-66bff467f8-jxvnw                     1/1     Running   0          7m28s
coredns-66bff467f8-lk8v5                     1/1     Running   0          7m28s
etcd-kind-control-plane                      1/1     Running   0          7m39s
kindnet-5dpxt                                1/1     Running   0          7m28s
kindnet-ckz88                                1/1     Running   0          7m10s
kindnet-sqxs7                                1/1     Running   0          7m10s
kube-apiserver-kind-control-plane            1/1     Running   0          7m39s
kube-controller-manager-kind-control-plane   1/1     Running   0          5m38s
kube-proxy-ddgjt                             1/1     Running   0          7m28s
kube-proxy-j25kr                             1/1     Running   0          7m10s
kube-proxy-jt9cw                             1/1     Running   0          7m10s
kube-scheduler-kind-control-plane            1/1     Running   0          7m39s
yurt-app-manager-699ffdcb78-8m9sf            1/1     Running   0          37s
yurt-app-manager-699ffdcb78-fdqmq            1/1     Running   0          37s
yurt-controller-manager-6c95788bf-jrqts      1/1     Running   0          6m17s
yurt-hub-kind-control-plane                  1/1     Running   0          3m36s
yurt-hub-kind-worker                         1/1     Running   0          4m50s
yurt-hub-kind-worker2                        1/1     Running   0          4m50s

配置 kube-proxy

开启 kube-proxyEndpointSliceProxying 特性门控,并配置其连接 Yurthub

$ kubectl edit cm -n kube-system kube-proxy
apiVersion: v1
data:
  config.conf: |-
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    featureGates: # 1. enable EndpointSliceProxying feature gate.
      EndpointSliceProxying: true
    clientConnection:
      acceptContentTypes: ""
      burst: 0
      contentType: ""
      #kubeconfig: /var/lib/kube-proxy/kubeconfig.conf # 2. comment this line.
      qps: 0
    clusterCIDR: 10.244.0.0/16
    configSyncPeriod: 0s

重启 kube-proxy

$ kubectl delete pod --selector k8s-app=kube-proxy -n kube-system
pod "kube-proxy-cbsmj" deleted
pod "kube-proxy-cqwcs" deleted
pod "kube-proxy-m9dgk" deleted

创建节点池

  • 创建用于测试的节点池。
$ cat << EOF | kubectl apply -f -
apiVersion: apps.openyurt.io/v1alpha1
kind: NodePool
metadata:
  name: beijing
spec:
  type: Cloud

---

apiVersion: apps.openyurt.io/v1alpha1
kind: NodePool
metadata:
  name: hangzhou
spec:
  type: Edge
  annotations:
    apps.openyurt.io/example: test-hangzhou
  labels:
    apps.openyurt.io/example: test-hangzhou

---

apiVersion: apps.openyurt.io/v1alpha1
kind: NodePool
metadata:
  name: shanghai
spec:
  type: Edge
  annotations:
    apps.openyurt.io/example: test-shanghai
  labels:
    apps.openyurt.io/example: test-shanghai
EOF
  • 将主节点 kind-control-plane 加入到北京节点池,工作节点 kind-worker 加入到杭州节点池, kind-worker2 加入到上海节点池。
$ kubectl label node kind-control-plane apps.openyurt.io/desired-nodepool=beijing
node/kind-control-plane labeled

$ kubectl label node kind-worker apps.openyurt.io/desired-nodepool=hangzhou
node/kind-worker labeled

$ kubectl label node kind-worker2 apps.openyurt.io/desired-nodepool=shanghai
node/kind-worker2 labeled
  • 查看节点池信息。
$ kubectl get np
NAME       TYPE    READYNODES   NOTREADYNODES   AGE
beijing    Cloud   1            0               63s
hangzhou   Edge    1            0               63s
shanghai   Edge    1            0               63s

创建 UnitedDeployment

  • 创建 united-deployment1 用于测试。为了便于测试,我们使用 serve_hostname 镜像,当访问 9376 端口时,容器会返回它自己的主机名。
$ cat << EOF | kubectl apply -f -
apiVersion: apps.openyurt.io/v1alpha1
kind: UnitedDeployment
metadata:
  labels:
    controller-tools.k8s.io: "1.0"
  name: united-deployment1
spec:
  selector:
    matchLabels:
      app: united-deployment1
  workloadTemplate:
    deploymentTemplate:
      metadata:
        labels:
          app: united-deployment1
      spec:
        template:
          metadata:
            labels:
              app: united-deployment1
          spec:
            containers:
              - name: hostname
                image: mirrorgooglecontainers/serve_hostname
                ports:
                - containerPort: 9376
                  protocol: TCP
  topology:
    pools:
    - name: hangzhou
      nodeSelectorTerm:
        matchExpressions:
        - key: apps.openyurt.io/nodepool
          operator: In
          values:
          - hangzhou
      replicas: 2
    - name: shanghai
      nodeSelectorTerm:
        matchExpressions:
        - key: apps.openyurt.io/nodepool
          operator: In
          values:
          - shanghai
      replicas: 2
  revisionHistoryLimit: 5
EOF
  • 创建 united-deployment2 用于测试。这里我们使用nginx 镜像,用来访问由 united-deployment1 创建的 hostname pod。
$ cat << EOF | kubectl apply -f -
apiVersion: apps.openyurt.io/v1alpha1
kind: UnitedDeployment
metadata:
  labels:
    controller-tools.k8s.io: "1.0"
  name: united-deployment2
spec:
  selector:
    matchLabels:
      app: united-deployment2
  workloadTemplate:
    deploymentTemplate:
      metadata:
        labels:
          app: united-deployment2
      spec:
        template:
          metadata:
            labels:
              app: united-deployment2
          spec:
            containers:
              - name: nginx
                image: nginx:1.19.3
                ports:
                - containerPort: 80
                  protocol: TCP
  topology:
    pools:
    - name: hangzhou
      nodeSelectorTerm:
        matchExpressions:
        - key: apps.openyurt.io/nodepool
          operator: In
          values:
          - hangzhou
      replicas: 2
    - name: shanghai
      nodeSelectorTerm:
        matchExpressions:
        - key: apps.openyurt.io/nodepool
          operator: In
          values:
          - shanghai
      replicas: 2
  revisionHistoryLimit: 5
EOF
  • 查看由上述 unitedDeployment 创建出来的 pod 信息。
$ kubectl get pod -l "app in (united-deployment1,united-deployment2)" -o wide
NAME                                                 READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
united-deployment1-hangzhou-fv6th-66ff6fd958-f2694   1/1     Running   0          18m   10.244.2.3   kind-worker    <none>           <none>
united-deployment1-hangzhou-fv6th-66ff6fd958-twf95   1/1     Running   0          18m   10.244.2.2   kind-worker    <none>           <none>
united-deployment1-shanghai-5p8zk-84bdd476b6-hr6xt   1/1     Running   0          18m   10.244.1.3   kind-worker2   <none>           <none>
united-deployment1-shanghai-5p8zk-84bdd476b6-wjck2   1/1     Running   0          18m   10.244.1.2   kind-worker2   <none>           <none>
united-deployment2-hangzhou-lpkzg-6d958b67b6-gf847   1/1     Running   0          15m   10.244.2.4   kind-worker    <none>           <none>
united-deployment2-hangzhou-lpkzg-6d958b67b6-lbnwl   1/1     Running   0          15m   10.244.2.5   kind-worker    <none>           <none>
united-deployment2-shanghai-tqgd4-57f7555494-9jvjb   1/1     Running   0          15m   10.244.1.5   kind-worker2   <none>           <none>
united-deployment2-shanghai-tqgd4-57f7555494-rn8n8   1/1     Running   0          15m   10.244.1.4   kind-worker2   <none>           <none>

创建含有 openyurt.io/topologyKeys 注解的服务

$ cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: svc-ud1
  annotations:
    openyurt.io/topologyKeys: openyurt.io/nodepool
spec:
  selector:
    app: united-deployment1
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 9376
EOF

创建不含 openyurt.io/topologyKeys 注解的服务

$ cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: svc-ud1-without-topology
spec:
  selector:
    app: united-deployment1
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 9376
EOF

测试服务拓扑功能

通过使用上海节点池中的 pod 访问上述创建的两个服务来测试服务拓扑功能。当访问含有 openyurt.io/topologyKeys 注解的服务时,流量会被路由到位于上海节点池中的节点上。

为了进行比较,我们首先测试没有openyurt.io/topologyKeys注解的服务。结果如下,可以看到它的流量既可以被杭州节点池接收,也能被上海节点池接收,并不受节点池的限制。

$ kubectl exec -it united-deployment2-shanghai-tqgd4-57f7555494-9jvjb bash
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1-without-topology:80
united-deployment1-hangzhou-fv6th-66ff6fd958-twf95
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1-without-topology:80
united-deployment1-shanghai-5p8zk-84bdd476b6-hr6xt
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1-without-topology:80
united-deployment1-hangzhou-fv6th-66ff6fd958-twf95
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1-without-topology:80
united-deployment1-hangzhou-fv6th-66ff6fd958-f2694

然后我们测试含有openyurt.io/topologyKeys注解的服务。结果如下,可以看到其流量只能路由到上海节点池中的节点。

$ kubectl exec -it united-deployment2-shanghai-tqgd4-57f7555494-9jvjb bash
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1:80
united-deployment1-shanghai-5p8zk-84bdd476b6-wjck2
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1:80
united-deployment1-shanghai-5p8zk-84bdd476b6-hr6xt
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1:80
united-deployment1-shanghai-5p8zk-84bdd476b6-wjck2
root@united-deployment2-shanghai-tqgd4-57f7555494-9jvjb:/# curl svc-ud1:80
united-deployment1-shanghai-5p8zk-84bdd476b6-hr6xt

OpenYurt:在边缘场景无缝运行使用InClusterConfig的业务Pod

· 阅读需要 1 分钟
rambohe
Maintainer of OpenYurt

1.背景介绍

OpenYurt是业界首个非侵入的边缘计算云原生开源项目,通过边缘自治,云边协同,边缘单元化,边缘流量闭环等能力为用户提供云边一体化的使用体验。不少用户在使用OpenYurt的时候,经常需要把存量的使用InClusterConfig访问kube-apiserver的Pod通过OpenYurt迁移到边缘环境中。如下图所示:

在OpenYurt集群中,提供了使用InClusterConfig的业务Pod零修改就可以运行在边缘环境的能力。

2.面临挑战

使用InClusterConfig的业务Pod在边缘环境中运行,需要解决如下问题:

  • 问题一:Pod通过InClusterConfig地址访问kube-apiserver,节点上默认网络规则(iptables/ipvs)将会把请求转发到kube-apiserver的PodIP,同时云端与边缘位于不同网络平面,边缘是无法访问到云端的PodIP。所以边缘业务Pod无法通过InClusterConfig访问到kube-apiserver。

    Incluster2

  • 问题二:在解决问题一后,如果云边网络断开时业务Pod容器出现重启等状况,边缘Pod将无法从kube-apiserver获取到业务配置,这会影响到业务Pod的重启运行。

3.解决方案

从上述问题可以看出,我们需要无感知的调整边缘pod的访问地址,同时需要在边缘环境中缓存业务配置,保证云边断网时也可以利用边缘缓存业务配置,保证云边断网时也可以利用边缘缓存来获取业务Pod的配置信息。具体解决方案如下;

3.1边缘Pod访问的云端endpoint优化
  • Pod通过InClusterConfig访问kube-apiserver,源码如下:

    func InClusterConfig() (*Config, error) {
    const (
        tokenFile  = "/var/run/secrets/kubernetes.io/serviceaccount/token"
        rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
    // 通过Kuberentes service对应的环境变量来获取访问地址
    host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
    if len(host) == 0 || len(port) == 0 {
        return nil, ErrNotInCluster
    }
    
    // skip some code...
    
    return &Config{
        Host:            "https://" + net.JoinHostPort(host, port),
        TLSClientConfig: tlsClientConfig,
        BearerToken:     string(token),
        BearerTokenFile: tokenFile,
    }, nil
    }
    
  • 因此想无感知调整边缘Pod访问的云端endpoint,只需要无侵入修改Pod的KUBERNETES_SERVICE_HOST和KUBERNETE_SERVICE_PORT两个环境变量或者修改kubernetes service地址。解决方案如下:

    • 解决方案一:增加一个admission controller在边缘Pod创建时把kube-apiserver的公网地址自动注入到Pod的环境变量KUBERNETES_SERVICE_HOST和KUBERNETE_SERVICE_PORT

    • 解决方案二:边缘数据过滤框架中增加一个fillter yurthub的边缘数据过滤框架类似于admission controller ,专门用于边缘场景下在边缘应用无感知的状态下,无侵入的修改或者过滤云端返回的数据。目前支持的过滤器有:Masterservice,servicetopology,discardcloudservice等

    • 解决方案对比:

      解决方案一解决方案二
      实现方案增加一个admission controller边缘数据过滤框架中增加一个filter
      复杂度高(需要区别Pod运行在边缘还是云端)
      显示修改数据Pod中增加环境变量配置

综合实现复杂度,非侵入等设计理念,在OpenYurt中我们选择了解决方案二。如下图所示:

3.2业务Pod的边缘自治

在云边网络断开状态下,业务Pod重启时,将无法从云端kube-apiserver获取到业务配置信息,因此需要在边缘本地缓存Pod的业务数据。

说明1:业务Pod通过yurthub访问kube-apiserver,也意味着[3.1 边缘Pod访问的云端endpoint优化]章节中提到的KUBERNETES_SERVICE_HOST和KUBERNETE_SERVICE_PORT环境变量被修改为yurthub https endpoint(169.254.2.1:10268)。

说明2:如果业务Pod的大量list/watch操作导致大量本地cache,可能会造成本地磁盘压力,因此yurthub对业务Pod的缓存能力默认是关闭的,用户可以通过yurt-hub-cfg configmap的cache_agents字段中增加User-Agent信息来打开对应Pod的数据缓存。例如:

apiVersion: v1
kind: ConfigMap
metadata:
  name: yurt-hub-cfg
  namespace: kube-system
data:
  # 缓存边缘ingress-controller pod访问kube-apiserver的数据
  cache_agents: "ingress-controller"

4.总结

  • 如果存量Pod无需访问kube-apiserver或者InClusterConfig访问kube-apiserver,这些类型Pod可以零修改运行到OpenYurt集群的边缘环境上。通过其他方式访问kube-apiserver的业务Pod目前无法保证零修改运行到边缘环境。

  • 边缘业务Pod是否正常访问kube-apiserver,首先可以查看业务pod的环境变量是否正常:

    KUBERNETES_SERVICE_HOST=127.0.0.1或者169.254.2.1,KUBERNETES_SERVICE_PORT=10268。然后可以查看yurthub组件的日志是否有业务Pod相关的请求日志。当然也可以查询业务Pod的日志是否正常。最后可以确认/etc/kubernetes/cache目录是否有相关组件的缓存数据,如果没有可以再确认kube-system/yurt-hub-cfg configmap是否已经配置。

  • 使用InClusterConfig的Pod零修改运行到边缘环境的能力,整体实现由yurthub组件承载,没有给OpenYurt架构增加额外的负担,同时用户在使用过程中对该能力也基本无感知,对原生业务Pod无侵入。

参考链接:

1.Accessing the API from a Pod

2.data filtering framework on the edge

3.深度解读OpenYurt:边缘自治能力设计解析

在树莓派上玩转 OpenYurt

· 阅读需要 1 分钟
zyjhtangtang
Member of OpenYurt

image

随着边缘计算的快速发展,越来越多的数据需要到网络的边缘侧进行存储、处理和分析,边缘的设备和应用呈爆发式增长。如何高效的管理边缘侧的资源和应用是业界面临的一个主要问题。当前,采用云原生的方法,将云计算的能力下沉到边缘并在云端做统一调度、管控的云边端一体化架构得到了业界的广泛认可。

2020 年 5 月,阿里巴巴开源首个 Kubernetes 无侵入的边缘计算云原生项目 OpenYurt,并于同年 9 月份进入 CNCF SandBox。OpenYurt 针对边缘场景中网络不稳定、云边运维困难等问题,对原生 Kubernetes 无侵入地增强,重点提供了边缘节点自治、云边运维通道、边缘单元化的能力。

如图下所示, image

本文通过在云端部署 Kubernetes 集群的控制面,并将树莓派接入集群来搭建云管边场景。基于这个环境演示 OpenYurt 的核心能力,带大家快速上手 OpenYurt。

环境准备

1)基础环境介绍

在云端,购买 ENS 节点(ENS 节点具有公网 IP,方便通过公网对外暴露服务)来部署原生 K8s 集群的管控组件。其中系统采用 ubuntu18.04、hostname 为 master-node、docker 版本为 19.03.5。

在边缘,将树莓派 4 与本地的路由器连接,组成边缘私网环境,路由器通过 4G 网卡访问互联网。其中树莓派 4 预装系统为 ubuntu18.04、hostname为 edge-node、docker 版本为 19.03.5。 image

2)原生K8s集群搭建

本文演示环境基于社区1.16.6版本的K8s集群,并采用社区提供的kubeadm工具来搭建集群,具体操作如下:

  • 在云端节点和树莓派上分别执行如下命令安装 Kubernetes 组件。
curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt install -y kubelet=1.16.6-00 kubeadm=1.16.6-00 kubectl=1.16.6-00
  • 使用kubeadm 初始化云端节点(在云端节点上执行如下命令),部署过程中采用阿里云的镜像仓库,为了支持树莓派的接入,该仓库的镜像做了 manifest 列表,能够支持 amd64/arm64 两种不同的 CPU 架构。
# master-node
kubeadm init --image-repository=registry.cn-hangzhou.aliyuncs.com/edge-kubernetes --kubernetes-version=v1.16.6 --pod-network-cidr=10.244.0.0/16
  • 依据初始化完成之后的提示,拷贝 config 文件到 $HOME/.kube 中:
mkdir -p $HOME/.kube
 sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  • 树莓派接入云端集群依据第二步中初始化完成以后输出的节点接入信息,在树莓派上执行接入命令。
kubeadm join 183.195.233.42:6443 --token XXXX \
 --discovery-token-ca-cert-hash XXXX
  • 添加 cni 配置(云端管控节点和树莓派都需要配置),本文搭建的集群使用主机网络。创建 cni 配置文件 /etc/cni/net.d/0-loopback.conf,并将如下内容拷贝到该文件中。
{
 "cniVersion": "0.3.0",
 "name": "lo",
 "type": "loopback"
}
  • 在 master 节点上查看部署效果。
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
edge-node Ready <none>   74s    v1.16.6   192.168.0.100    <none>        Ubuntu 18.04.4 LTS   4.19.105-v8-28      docker://19.3.5
master-node   Ready    master   2m5s   v1.16.6   183.195.233.42   <none>        Ubuntu 18.04.2 LTS   4.15.0-52-generic   docker://19.3.5
  • 删除 CoreDNS(本文 Demo 中 CoreDNS 不需要使用),并将 master 节点的 taints 去掉(方便后续部署 OpenYurt 组件)。
kubectl delete deployment coredns -n kube-system
kubectl taint node master-node node-role.kubernetes.io/master-

原生 K8s 集群在边缘场景中的问题

基于上述环境,我们来测试一下原生 K8s 在云管边架构中对云边运维的支持和对云边网络断开时的反应。首先,我们从云端部署一个测试应用 nginx,在 master 节点上执行 kubectl apply -f nginx.yaml,具体的部署 yaml 如下。

注意:nodeSelector 选择 edge-node 节点,主机网络配置为 true,并配置 pod 的容忍时间为 5s(默认 5min, 此处配置便于演示 pod 驱逐)。

apiVersion: v1
kind: Pod
metadata:
 name: nginx
spec:
 tolerations:
 - key: "node.kubernetes.io/unreachable"
 operator: "Exists"
 effect: "NoExecute"
 tolerationSeconds: 5
 - key: "node.kubernetes.io/not-ready"
 operator: "Exists"
 effect: "NoExecute"
 tolerationSeconds: 5
 nodeSelector:
 kubernetes.io/hostname: edge-node
 containers:
 - name: nginx
 image: nginx
 hostNetwork: true

查看部署结果:


root@master-node:~# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 11s 192.168.0.100 edge-node <none> 

1)测试常用的集群运维指令,包括 logs、exec、port-forward

在 master 节点上运维边缘节点应用,执行 logs/exec/port-forward 等指令,查看结果。

root@master-node:~# kubectl logs nginx
Error from server: Get https://192.168.0.100:10250/containerLogs/default/nginx/nginx: dial tcp 192.168.0.100:10250: connect: connection refused

root@master-node:~# kubectl exec -it nginx sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
Error from server: error dialing backend: dial tcp 192.168.0.100:10250: connect: connection refused

root@master-node:~# kubectl port-forward pod/nginx 8888:80
error: error upgrading connection: error dialing backend: dial tcp 192.168.0.100:10250: connect: connection refused

从执行结果看,原生的k8s在云管边的场景中,无法提供从云端运维边缘应用的能力。这是因为边缘节点部署在用户的私网环境,从云端无法通过边缘节点的 IP 地址直接访问边缘节点。

2)测试边缘断网时对业务的影响

边缘节点与云端管控通过公网连接,经常会出现网络不稳定,云端断连的情况。这里我们将做两个断网相关的测试:

  • 断网 1 分钟->恢复网络

  • 断网 1 分钟->重启边缘节点->恢复网络

观察两个测试过程中节点和 Pod 的状态变化。本文 Demo 中的断网方式是将路由器的公网连接断开。

1.断网1分钟->恢复网络

断开网络,大约 40s 后,节点变成 NotReady(正常节点 10s 钟上报一次心跳,当 4 次没有上报心跳时,管控组件认为节点异常)。


root@master-node:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
edge-node NotReady <none>   5m13s   v1.16.6
master-node   Ready      master   6m4s    v1.16.6

继续等待 5s 之后(正常节点变为 NotReady 之后,5m 才开始驱逐 pod,此处为了测试效果,将 pod 的容忍时间配成了 5s),应用 pod 被驱逐,状态变为 Terminating。

root@master-node:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Terminating 0 3m45s

将网络恢复,观察节点及 pod 变化。

root@master-node:~# kubectl get pods
No resources found in default namespace.

网络恢复后,节点状态变成 ready,业务 pod 被清除,这是因为边缘节点的 Kubelet 获取到业务 Pod 的 Terminating 状态,对业务 Pod 做删除操作,并返回删除成功,云端也做了相应的清理。至此,业务 Pod 由于云边网络的不稳定而被驱逐,然而在断网期间,边缘节点其实是可以正常工作的。

重新创建应用 nginx,用于下面测试。

root@master-node:~# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4s 192.168.0.100 edge-node <none>           <none>

2.断网1分钟->重启边缘节点->恢复网络

接下来,我们测试在断网的情况下,边缘节点的重启对业务的影响。断网 1 分钟之后,Node 和 Pod 状态同上面测试结果,Node 变为 NotReady,Pod 的状态变为 Terminating。此时,切换到私有网络环境,登录到树莓派上,将树莓派重启,重启完成后等待大约 1 分钟,观察重启前后节点上的容器列表。

重启前边缘节点容器列表(此时云边端开,虽然在云端获取的 pod 是 Terminating 状态,但是边缘并未 Watch 到 Terminating 的操作,所以边缘的应用还正常运行)。

root@edge-node:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9671cbf28ca6 e86f991e5d10 "/docker-entrypoint.…" About a minute ago Up About a minute k8s_nginx_nginx_default_efdf11c6-a41c-4b95-8ac8-45e02c9e1f4d_0
6272a46f93ef registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 2 minutes ago Up About a minute k8s_POD_nginx_default_efdf11c6-a41c-4b95-8ac8-45e02c9e1f4d_0
698bb024c3db f9ea384ddb34 "/usr/local/bin/kube…" 8 minutes ago Up 8 minutes k8s_kube-proxy_kube-proxy-rjws7_kube-system_51576be4-2b6d-434d-b50b-b88e2d436fef_0
31952700c95b registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 8 minutes ago Up 8 minutes k8s_POD_kube-proxy-rjws7_kube-system_51576be4-2b6d-434d-b50b-b88e2d436fef_0

重启后节点容器列表,断网重启后,kubelet 无法从云端获取 Pod 信息,不会重建 Pod。

root@edge-node:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@edge-node:~#

从重启前后的对比看,边缘节点在断网重启之后,节点上的 Pod 全部无法恢复。这就会导致在云边断网时,一旦节点重启,应用将无法工作。

将网络恢复,观察节点及 pod 变化,同上面测试结果,网络恢复后,节点变为 Ready,业务 Pod 被清除。

root@master-node:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
edge-node Ready <none>   11m   v1.16.6
master-node   Ready    master   12m   v1.16.6
root@master-node:~# kubectl get pods
No resources found in default namespace.

接下来,再次部署业务 nginx,测试 OpenYurt 集群对云边运维的支持和对云边断网时的反应。


root@master-node:~# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 12s 192.168.0.100 edge-node <none>           <none>

原生 K8s 集群一键转换为 OpenYurt 集群

探究了原生 Kubernetes 在云边一体化架构中的不足之后,我们来看下 OpenYurt 集群是否能满足这种场景。现在,我们利用 OpenYurt 社区提供的集群转换工具 yurtctl,来将原生 K8s 集群转换成 OpenYurt 集群。在 master 节点上执行如下命令, 该命令指定了组件的镜像以及云端节点,并指定安装云边运维通道 yurt-tunnel。

yurtctl convert --yurt-controller-manager-image=registry.cn-hangzhou.aliyuncs.com/openyurt/yurt-controller-manager:v0.2.1 --yurt-tunnel-agent-image=registry.cn-hangzhou.aliyuncs.com/openyurt/yurt-tunnel-agent:v0.2.1 --yurt-tunnel-server-image=registry.cn-hangzhou.aliyuncs.com/openyurt/yurt-tunnel-server:v0.2.1 --yurtctl-servant-image=registry.cn-hangzhou.aliyuncs.com/openyurt/yurtctl-servant:v0.2.1 --yurthub-image=registry.cn-hangzhou.aliyuncs.com/openyurt/yurthub:v0.2.1 --cloud-nodes=master-node --deploy-yurttunnel

转换大概需要 2min,转换完成之后,观察业务 pod 的状态,可以看到转换过程中对业务 pod 无影响(也可以在转换过程中在新的终端使用 kubectl get pod -w 观察业务 pod 的状态)。

root@master-node:~# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 2m4s 192.168.0.100 edge-node <none>           <none>

执行完成之后的组件分布如下图 所示,其中橙色部分是 OpenYurt 相关的组件,蓝色部分是原生 K8s 组件。相应地,我们观察云端节点和边缘节点的 pod。

image

云端节点 yurt 相关的 pod:yurt-controller-manager 和 yurt-tunnel-server。

root@master-node:~# kubectl get pods --all-namespaces -owide | grep master | grep yurt
kube-system yurt-controller-manager-7d9db5bf85-6542h 1/1 Running 0 103s 183.195.233.42 master-node <none>           <none>
kube-system   yurt-tunnel-server-65784dfdf-pl5bn         1/1     Running   0          103s    183.195.233.42   master-node   <none>           <none>

边缘节点新增 yurt 相关的 pod: yurt-hub(static pod)和 yurt-tunnel-agent。

root@master-node:~# kubectl get pods --all-namespaces -owide | grep edge | grep yurt
kube-system yurt-hub-edge-node 1/1 Running 0 117s 192.168.0.100 edge-node <none>           <none>
kube-system   yurt-tunnel-agent-7l8nv                    1/1     Running   0          2m      192.168.0.100    edge-node     <none>           <none>

测试 OpenYurt 集群在边缘场景中的能力

1. 测试 logs/exec/port-forward 等运维指令,查看结果

root@master-node:~# kubectl logs nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Configuration complete; ready for start up


root@master-node:~# kubectl exec -it nginx sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# ls
bin dev docker-entrypoint.sh home media opt root sbin sys usr
boot docker-entrypoint.d etc lib mnt proc run srv tmp var
# exit


root@master-node:~# kubectl port-forward pod/nginx 8888:80
Forwarding from 127.0.0.1:8888 -> 80
Handling connection for 8888

测试 port-forward 时,在 master 节点上执行 curl 127.0.0.1:8888,可以访问 nginx 服务。

从演示结果看,OpenYurt 能够很好地支持常用的云边运维指令。

2. 测试边缘断网时对业务的影响

同样我们重复原生 K8s 中断网的两个测试,在测试之前我们先为边缘节点 edge-node 开启自治。在 OpenYurt 集群中,边缘节点的自治是通过一个 annotation 来标识的。

root@master-node:~# kubectl annotate node edge-node node.beta.alibabacloud.com/autonomy=true
node/edge-node annotated

1)断网 1 分钟->网络恢复

同样,将路由器公网断开,观察 Node 和 Pod 的状态。大约过了 40s,节点的状态变成 NotReady,而大约过 1min 以后,Pod 的状态一直是 Running,并不会被驱逐。

root@master-node:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
edge-node NotReady <none>   24m   v1.16.6
master-node   Ready      master   25m   v1.16.6
root@master-node:~# kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          5m7s

恢复网络,观察 Node 和 Pod 的状态,Node 状态变为 Ready,Pod 保持 Running。可见云边网络不稳定时,对边缘节点的业务 Pod 无影响。

root@master-node:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
edge-node Ready <none>   25m   v1.16.6
master-node   Ready    master   26m   v1.16.6
root@master-node:~# kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          6m30s

2)断网 1 分钟->重启边缘节点->恢复网络

接下来,我们测试在断网的情况下,边缘节点的重启对业务的影响。断网 1 分钟之后,Node 和 Pod 状态同上面测试结果,Node 变为 NotReady,Pod 保持 Running。同样,我们登录到树莓派上,将树莓派重启,观察重启前后节点上的容器列表。

重启前边缘节点容器列表:

root@edge-node:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
38727ec9270c 70bf6668c7eb "yurthub --v=2 --ser…" 7 minutes ago Up 7 minutes k8s_yurt-hub_yurt-hub-edge-node_kube-system_d75d122e752b90d436a71af44c0a53be_0
c403ace1d4ff registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 7 minutes ago Up 7 minutes k8s_POD_yurt-hub-edge-node_kube-system_d75d122e752b90d436a71af44c0a53be_0
de0d693e9e74 473ae979be68 "yurt-tunnel-agent -…" 7 minutes ago Up 7 minutes k8s_yurt-tunnel-agent_yurt-tunnel-agent-7l8nv_kube-system_75d28494-f577-43fa-9cac-6681a1215498_0
a0763f143f74 registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 7 minutes ago Up 7 minutes k8s_POD_yurt-tunnel-agent-7l8nv_kube-system_75d28494-f577-43fa-9cac-6681a1215498_0
80c247714402 e86f991e5d10 "/docker-entrypoint.…" 7 minutes ago Up 7 minutes k8s_nginx_nginx_default_b45baaac-eebc-466b-9199-2ca5c1ede9fd_0
01f7770cb0f7 registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 7 minutes ago Up 7 minutes k8s_POD_nginx_default_b45baaac-eebc-466b-9199-2ca5c1ede9fd_0
7e65f83090f6 f9ea384ddb34 "/usr/local/bin/kube…" 17 minutes ago Up 17 minutes k8s_kube-proxy_kube-proxy-rjws7_kube-system_51576be4-2b6d-434d-b50b-b88e2d436fef_1
c1ed142fc75b registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 17 minutes ago Up 17 minutes k8s_POD_kube-proxy-rjws7_kube-system_51576be4-2b6d-434d-b50b-b88e2d436fef_1

重启后边缘节点容器列表:

root@edge-node:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0c66b87066a0 473ae979be68 "yurt-tunnel-agent -…" 12 seconds ago Up 11 seconds k8s_yurt-tunnel-agent_yurt-tunnel-agent-7l8nv_kube-system_75d28494-f577-43fa-9cac-6681a1215498_2
a4fb3e4e8c8f e86f991e5d10 "/docker-entrypoint.…" 58 seconds ago Up 56 seconds k8s_nginx_nginx_default_b45baaac-eebc-466b-9199-2ca5c1ede9fd_1
fce730d64b32 f9ea384ddb34 "/usr/local/bin/kube…" 58 seconds ago Up 57 seconds k8s_kube-proxy_kube-proxy-rjws7_kube-system_51576be4-2b6d-434d-b50b-b88e2d436fef_2
c78166ea563f registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 59 seconds ago Up 57 seconds k8s_POD_yurt-tunnel-agent-7l8nv_kube-system_75d28494-f577-43fa-9cac-6681a1215498_1
799ad14bcd3b registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 59 seconds ago Up 57 seconds k8s_POD_nginx_default_b45baaac-eebc-466b-9199-2ca5c1ede9fd_1
627673da6a85 registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" 59 seconds ago Up 58 seconds k8s_POD_kube-proxy-rjws7_kube-system_51576be4-2b6d-434d-b50b-b88e2d436fef_2
04da705e4120 70bf6668c7eb "yurthub --v=2 --ser…" About a minute ago Up About a minute k8s_yurt-hub_yurt-hub-edge-node_kube-system_d75d122e752b90d436a71af44c0a53be_1
260057d935ee registry.cn-hangzhou.aliyuncs.com/edge-kubernetes/pause:3.1 "/pause" About a minute ago Up About a minute k8s_POD_yurt-hub-edge-node_kube-system_d75d122e752b90d436a71af44c0a53be_1

从重启前后的对比看,边缘节点在断网重启之后,节点上的 pod 能正常拉起,OpenYurt 的节点自治能力可以在断网下保证业务的稳定运行。

恢复网络,节点 Ready,观察业务 pod 的状态,网络恢复后,业务 pod 状态保持 running,有一次重启记录,符合预期。

root@master-node:~# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 1 11m 192.168.0.100 edge-node <none>           <none>

最后,我们从yurtctl的能力将OpenYurt集群,转换为原生K8s集群。同样,可以观察转换过程中对现有业务不会有影响。

yurtctl revert --yurtctl-servant-image=registry.cn-hangzhou.aliyuncs.com/openyurt/yurtctl-servant:v0.2.1

OpenYurt 作为阿里首个边缘云原生开源项目,基于商业化产品 ACK@Edge,在集团内部经历了长时间的打磨。已经应用在 CDN、IoT、盒马、ENS、菜鸟物流等众多场景。针对边缘场景,该项目坚持保持原生 K8s 的特性,以 Addon 的形式提供了边缘节点自治、云边端一体化运维通道等能力。最近在社区同学的一起努力下又开源了边缘单元化管理能力,同时后续还会继续开源更多的边缘管理能力,欢迎大家积极参与贡献。

原文链接

边缘计算云原生项目 OpenYurt

· 阅读需要 1 分钟
Fei Guo
Maintainer of OpenYurt
frank-huangyuqi
Maintainer of OpenYurt
rambohe
Maintainer of OpenYurt

image

导读:北京时间 5 月 29 日,在阿里云容器服务 ACK@Edge(边缘集群托管服务) 上线一周年之际,阿里巴巴正式宣布将其核心能力开源,并向社区贡献完整的边缘计算云原生项目 -- OpenYurt。

边缘云计算是基于云计算技术的核心和边缘计算的能力,构筑在边缘基础设施之上的新型计算平台,并正在成为行业的新焦点。OpenYurt 作为阿里巴巴首个边缘计算云原生开源项目,汇聚了阿里巴巴众多边缘计算业务团队的深厚技术积累,深度挖掘了边缘计算 + 云原生落地实施诉求。

两年前,OpenYurt 作为公共云服务 ACK@Edge 的核心框架,就已经应用于 CDN、音视频直播、物联网、物流、工业大脑、城市大脑等实际应用场景中,并服务于阿里云 LinkEdge、盒马、优酷、视频云(视频点播、视频直播、实时通信、视频监控、智能视觉)等多个业务或项目中。

阿里巴巴云原生开源负责人、云原生应用平台资深技术专家李响表示:“随着边缘计算的场景和需求不断增加,‘云边协同’、‘边缘云原生’正在逐渐成为新的技术焦点。OpenYurt 开源项目实践‘云边一体化’概念,依托原生 Kubernetes 强大的容器编排、调度能力,实现完全边缘计算云原生基础设施架构,帮助开发者轻松完成在海量边、端资源上的大规模应用的交付、运维、管控。我们希望 OpenYurt 开源能推动社区在云原生和边缘计算交叉领域的协同发展。”

什么是OpenYurt

image

使用 OpenYurt(Yurt,/jɜːrt/,蒙古包)作为本次开源项目名称,期望以其“形”来表示边缘计算侧重于创建一个集中管理但物理分布的基础设施,并支持自动/自治运行操作的含义。

OpenYurt 主打“云边一体化”概念,依托原生 Kubernetes 强大的容器编排、调度能力,通过众多边缘计算应用场景锤炼,实现了一整套对原生 Kubernetes“零”侵入的边缘云原生方案,提供诸如边缘自治、高效运维通道、边缘单元化管理、边缘流量拓扑管理,安全容器、边缘 Serverless/FaaS、异构资源支持等能力。OpenYurt 能帮用户解决在海量边、端资源上完成大规模应用交付、运维、管控的问题,并提供中心服务下沉通道,实现和边缘计算应用的无缝对接。

1)OpenYurt诞生背景

image 从 2017 年底开始,阿里云物联网(IoT)和 CDN (内容分发网络)服务作为典型的边缘计算业务正面临着产品规模的爆发式增长、运维复杂度急剧攀升、运维效率不高的“三难”境地,因此引入云原生理念、全面转型边缘应用的运维管理模式成为亟需解决的问题。

正是在这样的背景下,OpenYurt 诞生于阿里云容器服务团队,并在接下来的两年多时间内,作为公共云服务 ACK@Edge 的核心框架被广泛应用于 CDN、音视频直播、物联网、物流、工业大脑、城市大脑等实际应用场景中,并正在服务于阿里云 LinkEdge、盒马、优酷、视频云(视频点播,视频直播,实时通信,视频监控,智能视觉)等多个业务或项目中。

2)OpenYurt技术特点

OpenYurt沿用了目前业界流行的“中心管控、边缘自治”的边缘应用管理架构,将“云边端一体化协同”作为目标,赋能云原生能力向边缘端拓展。在技术实现上,OpenYurt贯彻了“Extending your native Kubernetes to Edge”的核心设计理念,其技术方案有如下特点:

  • 对原生Kubernetes“零”侵入,保证对原生k8s API的完全兼容。

OpenYurt通过proxy node network traffic,对 Kubernetes 节点应用生命周期管理加了一层新的封装,提供边缘计算所需要的核心管控能力;

  • 无缝转换,OpenYurt提供了工具将原生Kubernetes“一键式”转换成支持边缘计算能力的 Kubernetes 集群;

  • 低Overhead,OpenYurt参考了大量边缘计算场景的实际需求,在保证功能和可靠性的基础上,本着最小化,最简化的设计理念,严格限制新增组件的资源诉求。

3)OpenYurt核心能力

image

  • 边缘自治能力:

YurtHub作为节点上的临时配置中心,在网络连接中断的情况下,持续为节点上所有设备和客户业务提供数据配置服务。YurtHub 提供了对大量原生 Kubernetes API的支持,可以在节点和边缘单元维度提供“ShadowApiserver”的能力,在边缘计算弱网络链接场景的价值尤为突出;

  • 边缘运维通道

在边缘场景,由于大多数边缘节点没有暴露在公网之上,中心管控无缝和边缘节点主动建立网络链接,所有的Kubernetes原生应用运维APIs(logs/exec/metrics)会失去效力; YurtTunnel 通过在管控与边缘节点之间建立反向通道,并和节点的生命周期完整联动,承载原生运维 APIs 的流量;

  • 集群转换能力 Yurtctl作为OpenYurt官方命令行工具,提供原生Kubernetes集群支持边缘计算infrastructure的一键式切换。

其他更高级的功能比如边缘流量管理、单元化管理,部署、区域自治等将会逐步开源。

4)OpenYurt Roadmap

作为阿里云容器服务 ACK@Edge 的开源版本,OpenYurt 将采用全开源社区开发模式,每季度发布新版本更新,包含社区上游安全/关键 bug 修复和新特性、新能力,并逐步将产品完整能力开源。

主导这次开源的阿里巴巴云原生应用平台团队,目前已经开源 OAM、OpenKruise、Dragonfly、Apache RocketMQ、Apache Dubbo 等众多明星项目,是国内最资深的云原生开源贡献团队。OpenYurt 项目的开源,本着“Extending your native Kubernetes to Edge”的设计理念,让云原生技术在边缘计算领域的生态建设与普及前进了一大步,也为全球开发者拓展云原生边界贡献了一份力量。

原文链接