华为云原生之KubeEdge深度使用体验与Kubeflow应用开发实践

Posted ╰つ栺尖篴夢ゞ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了华为云原生之KubeEdge深度使用体验与Kubeflow应用开发实践相关的知识,希望对你有一定的参考价值。

一、KubeEdge 简介

① 什么是 KubeEdge ?

  • KubeEdge 是一个开源的系统,可将本机容器化应用编排和管理扩展到边缘端设备。它基于 Kubernetes 构建,为网络和应用程序提供核心基础架构支持,并在云端和边缘端部署应用,同步元数据。KubeEdge 还支持 MQTT 协议,允许开发人员编写客户逻辑,并在边缘端启用设备通信的资源约束。
  • KubeEdge 包含云端和边缘端两部分,使用 KubeEdge,可以很容易地将已有的复杂机器学习、图像识别、事件处理和其他高级应用程序部署到边缘端并进行使用。随着业务逻辑在边缘端上运行,可以在本地保护和处理大量数据。通过在边缘端处理数据,响应速度会显著提高,并且可以更好地保护数据隐私。
  • KubeEdge 是一个由 Cloud Native Computing Foundation (CNCF) 托管的孵化级项目,CNCF 是对 KubeEdge 的 孵化公告

② KubeEdge 的优势

  • Kubernetes 原生支持:使用 KubeEdge 用户可以在边缘节点上编排应用、管理设备并监控应用程序/设备状态,就如同在云端操作 Kubernetes 集群一样。
  • 云边可靠协作:在不稳定的云边网络上,可以保证消息传递的可靠性,不会丢失。
  • 边缘自治:当云边之间的网络不稳定或者边缘端离线或重启时,确保边缘节点可以自主运行,同时确保边缘端的应用正常运行。
  • 边缘设备管理:通过 Kubernetes 的原生 API,并由 CRD 来管理边缘设备。
  • 极致轻量的边缘代理:在资源有限的边缘端上运行的非常轻量级的边缘代理(EdgeCore)。

③ KubeEdge 的工作原理

  • KubeEdge 由云端和边缘端部分构成:

  • 云上部分:
    • CloudHub 是一个 Web Socket 服务端,负责监听云端的变化,缓存并发送消息到 EdgeHub;
    • EdgeController 是一个扩展的 Kubernetes 控制器,管理边缘节点和 Pods 的元数据确保数据能够传递到指定的边缘节点;
    • DeviceController 是一个扩展的 Kubernetes 控制器,管理边缘设备,确保设备信息、设备状态的云边同步。
  • 边缘部分:
    • EdgeHub 是一个 Web Socket 客户端,负责与边缘计算的云服务(例如 KubeEdge 架构图中的 Edge Controller)交互,包括同步云端资源更新、报告边缘主机和设备状态变化到云端等功能;
    • Edged 是运行在边缘节点的代理,用于管理容器化的应用程序;
    • EventBus 是一个与 MQTT 服务器 (mosquitto) 交互的 MQTT 客户端,为其他组件提供订阅和发布功能;
    • ServiceBus 是一个运行在边缘的 HTTP 客户端,接受来自云上服务的请求,与运行在边缘端的 HTTP 服务器交互,提供了云上服务通过 HTTP 协议访问边缘端 HTTP 服务器的能力;
    • DeviceTwin 负责存储设备状态并将设备状态同步到云,它还为应用程序提供查询接口;
    • MetaManager 是消息处理器,位于 Edged 和 Edgehub 之间,它负责向轻量级数据库 (SQLite) 存储/检索元数据。

④ 升级 KubeEdge

  • 在每个边缘节点上备份 edgecore 数据库:
$ mkdir -p /tmp/kubeedge_backup
$ cp /var/lib/kubeedge/edgecore.db /tmp/kubeedge_backup/
  • 您可以保留旧的配置,根据需要保存一些自定义更改。升级后,某些选项可能会被删除,而某些选项可能会被添加,请不要直接使用旧的配置。
  • 如果从 1.3 升级到 1.4,请注意会将设备 API 从 v1alpha1 升级到 v1alpha2,需要安装 Device v1alpha2DeviceModel v1alpha2,并将它们现有的自定义资源从 v1alpha1 手动转换为 v1alpha2,如果需要回滚,建议将 v1alpha1 CRD 和自定义资源保留在集群中或导出到某个位置。
  • 确保所有 Edgecore 进程均已停止后,一个一个停止 edgecore 的进程,然后停止 cloudcore。停止的方式取决于部署方式:
    • 使用二进制 or “keadm” 方式: 使用 kill;
    • 使用 “systemd”方式: 使用 systemctl。
  • 清理:
$ rm -rf /var/lib/kubeedge /etc/kubeedge
  • 在每个边缘节点还原数据库:
$ mkdir -p /var/lib/kubeedge
$ mv /tmp/kubeedge_backup/edgecore.db /var/lib/kubeedge/

二、KubeEdge 的部署

① 使用 Keadm 进行部署

  • Keadm 用于安装 KubeEdge 的云端和边缘端组件,它不负责 K8s 的安装和运行。可以参考 Kubernetes-compatibility 了解 Kubernetes 兼容性来确定安装哪个版本的 Kubernetes。
  • Keadm 目前支持 Ubuntu 和 CentOS OS,RaspberryPi 的支持正在进行中,并且需要超级用户权限(或 root 权限)才能运行。

(A)设置云端(KubeEdge 主节点)

  • keadm init:
    • keadm init 将安装 cloudcore,生成证书并安装 CRD(默认情况下边缘节点需要访问 cloudcore 中 10000、10002 端口),它还提供了一个命令行参数,通过它可以设置特定的版本。
    • 必须正确配置 kubeconfig 或 master 中的至少一个,以便可以将其用于验证 k8s 集群的版本和其他信息。
    • 请确保边缘节点可以使用云节点的本地 IP 连接云节点,或者需要使用 --advertise-address 标记指定云节点的公共 IP 。
    • –advertise-address(仅从 1.3 版本开始可用)是云端公开的地址(将添加到 CloudCore 证书的 SAN 中),默认值为本地 IP。
    • keadm init 将会使用二进制方式部署 cloudcore 为一个系统服务,如果想实现容器化部署,可以参考 keadm beta init。
    • keadm init 如下所示:
# keadm init --advertise-address="THE-EXPOSED-IP"(only work since 1.3 release)
    • 输出:
Kubernetes version verification passed, KubeEdge installation will start...
...
KubeEdge cloudcore is running, For logs visit:  /var/log/kubeedge/cloudcore.log
  • keadm beta init:
    • 现在可以使用 keadm beta init 进行云端组件安装:
# keadm beta init --advertise-address="THE-EXPOSED-IP" --set cloudcore-tag=v1.9.0 --kube-config=/root/.kube/config
    • 还可使用 --external-helm-root 安装外部的 helm chart 组件,如 edgemesh:
# keadm beta init --set server.advertiseAddress="THE-EXPOSED-IP" --set server.nodeName=allinone  --kube-config=/root/.kube/config --force --external-helm-root=/root/go/src/github.com/edgemesh/build/helm --profile=edgemesh
  • keadm beta manifest generate 可以帮助我们快速渲染生成期望的 manifests 文件,并输出在终端显示:
# keadm beta manifest generate --advertise-address="THE-EXPOSED-IP" --kube-config=/root/.kube/config > kubeedge-cloudcore.yaml

(B) 设置边缘端(KubeEdge 工作节点)

  • 从云端获取令牌:在云端运行 keadm gettoken 将返回token令牌,该令牌将在加入边缘节点时使用:
# keadm gettoken
27a37ef16159f7d3be8fae95d588b79b3adaaf92727b72659eb89758c66ffda2.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTAyMTYwNzd9.JBj8LLYWXwbbvHKffJBpPd5CyxqapRQYDIXtFZErgYE
  • keadm join 将安装 edgecore 和 mqtt。它还提供了一个命令行参数,通过它可以设置特定的版本:
# keadm join --cloudcore-ipport=192.168.20.50:10000 --token=27a37ef16159f7d3be8fae95d588b79b3adaaf92727b72659eb89758c66ffda2.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTAyMTYwNzd9.JBj8LLYWXwbbvHKffJBpPd5CyxqapRQYDIXtFZErgYE
  • 可以使用 keadm beta join 通过镜像下载所需资源,进行节点接:
# keadm beta join --cloudcore-ipport=192.168.20.50:10000 --token=27a37ef16159f7d3be8fae95d588b79b3adaaf92727b72659eb89758c66ffda2.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTAyMTYwNzd9.JBj8LLYWXwbbvHKffJBpPd5CyxqapRQYDIXtFZErgYE
# keadm beta join --cloudcore-ipport=192.168.20.50:10000 --runtimetype remote --remote-runtime-endpoint unix:///run/containerd/containerd.sock --token=27a37ef16159f7d3be8fae95d588b79b3adaaf92727b72659eb89758c66ffda2.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTAyMTYwNzd9.JBj8LLYWXwbbvHKffJBpPd5CyxqapRQYDIXtFZErgYE
  • 输出:
Host has mosquit+ already installed and running. Hence skipping the installation steps !!!
...
KubeEdge edgecore is running, For logs visit:  /var/log/kubeedge/edgecore.log
  • 说明:
    • –cloudcore-ipport 是必填参数;
    • 如果您需要的话,加上 --token 会自动为边缘节点生成证书;
    • 需要保证云和边缘端使用的 KubeEdge 版本相同;
    • 加上 --with-mqtt 会自动为边缘节点以容器运行的方式部署 mosquitto 服务。

(C)启用 kubectl logs 功能

  • kubectl logs 必须在使用 metrics-server 之前部署,通过以下操作激活功能:
  • 确保可以找到 Kubernetes 的 ca.crt 和 ca.key 文件,如果通过 kubeadm 安装 Kubernetes 集群,这些文件将位于 /etc/kubernetes/pki/ 目录中:
ls /etc/kubernetes/pki/
    • 设置 CLOUDCOREIPS 环境,环境变量设置为指定的 cloudcore 的 IP 地址,如果具有高可用的集群,则可以指定 VIP(即弹性 IP/虚拟 IP):
export CLOUDCOREIPS="192.168.0.139"
    • 使用以下命令检查环境变量:
echo $CLOUDCOREIPS
    • 在云端节点上为 CloudStream 生成证书,但是生成的文件不在 /etc/kubeedge/ 中,需要从GitHub的存储库中拷贝一份。
    • 将用户更改为 root:
```shell
sudo su
  • 从原始克隆的存储库中拷贝证书:shell cp $GOPATH/src/github.com/kubeedge/kubeedge/build/tools/certgen.sh /etc/kubeedge/ 将目录更改为 kubeedge 目录:shell cd /etc/kubeedge/ 从 certgen.sh 生成证书 bash /etc/kubeedge/certgen.sh stream。
  • 需要在主机上设置 iptables,此命令应该在每个 apiserver 部署的节点上执行,在这种情况下,须在 master 节点上执行,并由 root 用户执行此命令,在运行每个 apiserver 的主机上运行以下命令:
bash
iptables -t nat -A OUTPUT -p tcp --dport 10350 -j DNAT --to $CLOUDCOREIPS:10003
  • 如果不确定是否设置了 iptables,并且希望清除所有这些表(如果错误地设置 iptables,它将阻止使用 kubectl logs 功能),可以使用以下命令清理 iptables 规则:
shell iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
  • /etc/kubeedge/config/cloudcore.yaml 和 /etc/kubeedge/config/edgecore.yaml 上 cloudcore 和 edgecore 都要 修改,将 cloudStream 和 edgeStream 设置为 enable: true,将服务器 IP 更改为 cloudcore IP(与 $ CLOUDCOREIPS 相同),打开 YAML 文件:
shell
sudo nano /etc/kubeedge/config/cloudcore.yaml
  • 在以下文件中修改( enable: true )内容:
yaml cloudStream: enable: true streamPort: 10003 tlsStreamCAFile: /etc/kubeedge/ca/streamCA.crt tlsStreamCertFile: /etc/kubeedge/certs/stream.crt tlsStreamPrivateKeyFile: /etc/kubeedge/certs/stream.key tlsTunnelCAFile: /etc/kubeedge/ca/rootCA.crt tlsTunnelCertFile: /etc/kubeedge/certs/server.crt tlsTunnelPrivateKeyFile: /etc/kubeedge/certs/server.key tunnelPort: 10004
  • 在 edgecore 中打开 YAML 文件:
shell sudo nano /etc/kubeedge/config/edgecore.yaml
  • 修改以下部分中的文件 (enable: true), (server: 192.168.0.193:10004):
yaml
edgeStream:
  enable: true
  handshakeTimeout: 30
  readDeadline: 15
  server: 192.168.0.139:10004
  tlsTunnelCAFile: /etc/kubeedge/ca/rootCA.crt
  tlsTunnelCertFile: /etc/kubeedge/certs/server.crt
  tlsTunnelPrivateKeyFile: /etc/kubeedge/certs/server.key
  writeDeadline: 15
  • 重新启动所有 cloudcore 和 edgecore:
sudo su

pkill cloudcore
nohup cloudcore > cloudcore.log 2>&1 &

kubectl -n kubeedge rollout restart deployment cloudcore

systemctl restart edgecore.service
  • 可以考虑避免 kube-proxy 部署在 edgenode 上,有两种方法:
// 1.通过调用 `kubectl edit daemonsets.apps -n kube-system kube-proxy` 添加以下设置:
yaml
affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: node-role.kubernetes.io/edge
                operator: DoesNotExist
                
// 2.如果您仍然要运行 `kube-proxy`,请通过在以下位置添加 `edgecore.service` 中的 env 变量来要求 **edgecore** 不进行检查edgecore.service:
shell
    sudo vi /etc/kubeedge/edgecore.service
    
// 将以下行添加到 **edgecore.service** 文件:
shell
    Environment="CHECK_EDGECORE_ENVIRONMENT=false"
    
// 最终文件应如下所示:
Description=edgecore.service

    [Service]
    Type=simple
    ExecStart=/root/cmd/ke/edgecore --logtostderr=false --log-file=/root/cmd/ke/edgecore.log
    Environment="CHECK_EDGECORE_ENVIRONMENT=false"

    [Install]
    WantedBy=multi-user.target

(D) 在云端支持 Metrics-server

  • 实现该功能点的是重复使用 cloudstream 和 edgestream 模块,因此还需要执行启用 kubectl logs 功能的所有步骤。
  • 由于边缘节点和云节点的 kubelet 端口不同,故当前版本的 metrics-server(0.3.x)不支持自动端口识别(这是 0.4.0 功能),因此现在需要手动编译从 master 分支拉取的镜像。
  • Git clone 最新的 metrics server 代码仓:
bash
git clone https://github.com/kubernetes-sigs/metrics-server.git
  • 转到 metrics server 目录:
bash
cd metrics-server
  • 制作 docker 容器:
bash
make container
  • 检查您是否有此 docker 镜像:
bash
docker images
  • 确保使用镜像 ID 来对镜像标签进行变更,以使其与 yaml 文件中的镜像名称一致:
bash
docker tag a24f71249d69 metrics-server-kubeedge:latest
  • 需要通过以下命令使主节点可调度:
shell
kubectl taint nodes --all node-role.kubernetes.io/master-
  • 需要将这些设置写入部署 yaml(metrics-server-deployment.yaml)文件中,如下所示:
yaml
      volumes:
      # mount in tmp so we can safely use from-scratch images and/or read-only containers
      - name: tmp-dir
        emptyDir: 
      hostNetwork: true                          #Add this line to enable hostnetwork mode
      containers:
      - name: metrics-server
        image: metrics-server-kubeedge:latest    #Make sure that the REPOSITORY and TAG are correct
        # Modified args to include --kubelet-insecure-tls for Docker Desktop (don't use this flag with a real k8s cluster!!)
        imagePullPolicy: Never                   #Make sure that the deployment uses the image you built up
        args:
          - --cert-dir=/tmp
          - --secure-port=4443
          - --v=2
          - --kubelet-insecure-tls
          - --kubelet-preferred-address-types=InternalDNS,InternalIP,ExternalIP,Hostname
          - --kubelet-use-node-status-port       #Enable the feature of --kubelet-use-node-status-port for Metrics-server
        ports:
        - name: main-port
          containerPort: 4443
          protocol: TCP

(E) 重置 KubeEdge master 节点和工作节点

  • keadm reset 将停止 cloudcore 并从 Kubernetes master 中删除与KubeEdge相关的资源,如 kubeedge 命名空间,它不会卸载/删除任何先决条件。
  • 它为用户提供了一个标志,以指定 kubeconfig 路径,默认路径为 /root/.kube/config:
# keadm reset --kube-config=$HOME/.kube/config

② 使用二进制部署

(A)设置云端(KubeEdge 主节点)

  • 创建 CRD:
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/master/build/crds/devices/devices_v1alpha2_device.yaml
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/master/build/crds/devices/devices_v1alpha2_devicemodel.yaml
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/master/build/crds/reliablesyncs/cluster_objectsync_v1alpha1.yaml
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/master/build/crds/reliablesyncs/objectsync_v1alpha1.yaml
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/master/build/crds/router/router_v1_ruleEndpoint.yaml
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/master/build/crds/router/router_v1_rule.yaml
  • 准备配置文件:
# cloudcore --minconfig > cloudcore.yaml
  • 运行:
# cloudcore --config cloudcore.yaml

(B) 设置边缘端(KubeEdge 工作节点)

  • 生成配置文件:
# edgecore --minconfig > edgecore.yaml
  • 在云端获取 token 值:
# kubectl get secret -nkubeedge tokensecret -o=jsonpath='.data.tokendata' | base64 -d
  • 更新 edgecore 配置文件中的 token 值:
# sed -i -e "s|token: .*|token: $token|g" edgecore.yaml
  • 如果要在同一主机上运行 cloudcore 和 edgecore ,请首先运行以下命令:
# export CHECK_EDGECORE_ENVIRONMENT="false"
  • 运行 edgecore:
# edgecore --config edgecore.yaml
  • 运行 edgecore -h 以获取帮助信息,并在需要时添加选项。

© 局限性

  • 需要超级用户权限(或 root 权限)才能运行。
  • 使用二进制部署 KubeEdge 进行测试,切勿在生产环境中使用这种方式。

三、配置 CloudCore 和 EdgeCore

① 配置云端(KubeEdge Master 节点)

(A)修改配置文件

  • Cloudcore 要求更改 cloudcore.yaml 配置文件,创建并设置 cloudcore 配置文件,创建 /etc/kubeedge/config 文件夹:
# the default configuration file path is '/etc/kubeedge/config/cloudcore.yaml'
# also you can specify it anywhere with '--config'
mkdir -p /etc/kubeedge/config/
  • 使用 ~/kubeedge/cloudcore --minconfig 命令获取最小配置模板:
~/kubeedge/cloudcore --minconfig > /etc/kubeedge/config/cloudcore.yaml
  • 或使用 ~/kubeedge/cloudcore --defaultconfig 命令获取完整配置模板:
~/kubeedge/cloudcore --defaultconfig > /etc/kubeedge/config/cloudcore.yaml
  • 编辑配置文件:
vim /etc/kubeedge/config/cloudcore.yaml

(B) 修改 cloudcore.yaml

  • 无论是 kubeAPIConfig.kubeConfig 或 kubeAPIConfig.master,都可能 kubeconfig 文件的路径,同时它也可能是:
/root/.kube/config

// 或者

/home/<your_username>/.kube/config
  • 在安装 kubernetes 的地方执行以下步骤:
要开始使用集群,您需要以普通用户身份运行以下命令

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
  • 默认情况下,cloudcore 使用 https 连接到 Kubernetes apiserver。如果 master 和 kubeConfig 都进行了配置,master 将覆盖 kubeconfig 中的对应值。
  • 在 advertiseAddress 中配置所有暴露给边缘节点(如动态 IP)的 CloudCore 的 IP 地址,这些 IP 地址将添加到 CloudCore 证书中的 SAN 中。
modules:
  cloudHub:
    advertiseAddress:
    - 10.1.11.85

© 在云端(KubeEdge master 节点)添加边缘节点(KubeEdge 工作节点)

  • 如果 edgecore 的配置中的 modules.edged.registerNode 设置为 true,Edge 节点则会自动注册:
modules:
  edged:
    registerNode: true
  • 复制 $GOPATH/src/github.com/kubeedge/kubeedge/build/node.json 到您的工作目录并更改 metadata.name 为边缘节点的名称:
mkdir -p ~/kubeedge/yaml
cp $GOPATH/src/github.com/kubeedge/kubeedge/build/node.json ~/kubeedge/yaml

② 配置边缘端(KubeEdge 工作节点)

(A)创建并设置 Edgecore 配置文件

  • 创建 /etc/kubeedge/config 文件夹:
# the default configration file path is '/etc/kubeedge/config/edgecore.yaml'
# also you can specify it anywhere with '--config'
    mkdir -p /etc/kubeedge/config/
  • 使用 ~/kubeedge/edgecore --minconfig 命令创建最简配置:
~/kubeedge/edgecore --minconfig > /etc/kubeedge/config/edgecore.yaml
  • 或使用 ~/kubeedge/edgecore --defaultconfig 命令创建完整配置:
~/kubeedge/edgecore --defaultconfig > /etc/kubeedge/config/edgecore.yaml
  • 编辑配置文件:
vim /etc/kubeedge/config/edgecore.yaml

(B) 修改 edgecore.yaml

  • 检查 modules.edged.podSandboxImage,请运行以下命令:
shell
getconf LONG_BIT

+ `kubeedge/pause-arm:3.1` for arm arch
+ `kubeedge/pause-arm64:3.1` for arm64 arch
+ `kubeedge/pause:3.1` for x86 arch
  • KubeEdge v1.3之前的版本:检查 modules.edgehub.tlsCaFile 、modules.edgehub.tlsCertFile 和 modules.edgehub.tlsPrivateKeyFile 的证书文件是否存在。如果这些文件不存在,需要从云端拷贝它们。
  • KubeEdge v1.3之后的版本:仅跳过以上有关证书文件的检查,但是如果手动配置 Edgecore 证书,则必须检查证书的路径是否正确。
  • 在 modules.edgehub.websocket.server 和 modules.edgehub.quic.server 字段中更新 KubeEdge CloudCore 的 IP 地址和端口,需要设置 cloudcore 的 IP 地址。
  • 配置 docker 或 remote 作为所需的 runtime 的容器(对于所有基于 CRI 的runtime(包括容器))。如果未指定此参数,则默认情况下将使用 docker 作为 runtime 的容器:
runtimeType: docker
// 或者
runtimeType: remote
  • 如果运行类型是 remote,请遵循 KubeEdge CRI 配置指南来设置基于 remote/CRI 的运行时的 KubeEdge。
  • 在用于申请证书的 modules.edgehub.httpServer 中配置 KubeEdge cloudcore 的 IP 地址和端口,例如:
modules:
  edgeHub:
    httpServer: https://10.1.11.85:10002
  • 配置 token:
kubectl get secret tokensecret -n kubeedge -oyaml
  • 将获得如下内容:
apiVersion: v1
data:
  tokendata: ODEzNTZjY2MwODIzMmIxMTU0Y2ExYmI5MmRlZjY4YWQwMGQ3ZDcwOTIzYmU3YjcyZWZmOTVlMTdiZTk5MzdkNS5leUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKbGVIQWlPakUxT0RreE5qRTVPRGw5LmpxNENXNk1WNHlUVkpVOWdBUzFqNkRCdE5qeVhQT3gxOHF5RnFfOWQ4WFkK
kind: Secret
metadata:
  creationTimestamp: "2020-05-10T01:53:10Z"
  name: tokensecret
  namespace: kubeedge
  resourceVersion: "19124039"
  selfLink: /api/v1/namespaces/kubeedge/secrets/tokensecret
  uid: 48429ce1-2d5a-4f0e-9ff1-f0f1455a12b4
type: Opaque
  • 通过 base64 解码 tokendata 字段:
echo ODEzNTZjY2MwODIzMmIxMTU0Y2ExYmI5MmRlZjY4YWQwMGQ3ZDcwOTIzYmU3YjcyZWZmOTVlMTdiZTk5MzdkNS5leUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKbGVIQWlPakUxT0RreE5qRTVPRGw5LmpxNENXNk1WNHlUVkpVOWdBUzFqNkRCdE5qeVhQT3gxOHF5RnFfOWQ4WFkK |base64 -d
# then we get:
81356ccc08232b1154ca1bb92def68ad00d7d70923be7b72eff95e17be9937d5.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODkxNjE5ODl9.jq4CW6MV4yTVJU9gAS1j6DBtNjyXPOx18qyFq_9d8XY
  • 将解码后的字符串复制到 edgecore.yaml 中,如下所示:
modules:
  edgeHub:
    token: 81356ccc08232b1154ca1bb92def68ad00d7d70923be7b72eff95e17be9937d5.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODkxNjE5ODl9.jq4CW6MV4yTVJU9gAS1j6DBtNjyXPOx18qyFq_9d8XY

四、使用 CRI 设置不同的 container runtime

① containerd

  • Docker 18.09 及更高版本自带 containerd ,因此无需手动安装,如果没有 containerd ,可以通过运行以下命令进行安装:
# Install containerd
apt-get update && apt-get install -y containerd.io

# Configure containerd
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml

# Restart containerd
systemctl restart containerd
  • 使用 Docker 自带的 containerd 时,默认情况下 cri 插件是不可使用的,需要更新 containerd 的配置,来使 KubeEdge 能够 containerd 作为它的 runtime:
# Configure containerd
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
  • 更新 edgecore 配置文件 edgecore.yaml,为被作为 runtime 的 containerd 指定以下参数:
remoteRuntimeEndpoint: unix:///var/run/containerd/containerd.sock
remoteImageEndpoint: unix:///var/run/containerd/containerd.sock
runtimeRequestTimeout: 2
podSandboxImage: k8s.gcr.io/pause:3.2
runtimeType: remote
  • 默认情况下,cri 的 cgroup 驱动程序配置为 cgroupfs,如果不是这种情况,可以在中 edgecore.yaml 手动切换成 systemd:
modules:
  edged:
    cgroupDriver: systemd
  • 设置 containerd 的配置文件(/etc/containerd/config.toml)中的 systemd_cgroup 为 true ,然后重新启动 containerd:
# /etc/containerd/config.toml
systemd_cgroup = true

# Restart containerd
systemctl restart containerd
  • 创建 nginx 应用程序,检查该服务容器含有 containerd 并位于边缘端:
kubectl apply -f $GOPATH/src/github.com/kubeedge/kubeedge/build/deployment.yaml
deployment.apps/nginx-deployment created

ctr --namespace=k8s.io container ls
CONTAINER                                                           IMAGE                              RUNTIME
41c1a07fe7bf7425094a9b3be285c312127961c158f30fc308fd6a3b7376eab2    docker.io/library/nginx:1.15.12    io.containerd.runtime.v1.linux
  • cri 不支持 multi-tenancy 但是 containerd 支持,因此默认情况下,容器的命名空间需要设置为 “k8s.io”。

② CRI-O

  • 请遵循 CRI-O安装指南 来设置 CRI-O,如果边缘节点需要在 ARM 平台上运行,而发行版是 ubuntu18.04,那么可能需要构建二进制形式的源文件然后进行安装,因为 Kubic 存储库中没有针对此组合的 CRI-O 软件包:
git clone https://github.com/cri-o/cri-o
cd cri-o
make
sudo make install
# generate and install configuration files
sudo make install.config
  • 遵循以下指导来配置 CNI 网络,设置 CNI,更新 edgecore 配置文件,为 CRI-O-based runtime 指定以下参数:
remoteRuntimeEndpoint: unix:///var/run/crio/crio.sock
remoteImageEndpoint: unix:var/run/crio/crio.sock
runtimeRequestTimeout: 2
podSandboxImage: k8s.gcr.io/pause:3.2
runtimeType: remote
  • 默认情况下 CRI-O 使用 cgroupfs 作为一个 cgroup 的程序管理器,如果想替换成 systemd,请更新 CRI-O 配置文件(/etc/crio/crio.conf.d/00-default.conf):
# Cgroup management implementation used for the runtime.
cgroup_manager = "systemd"
  • 如果在 ARM 平台上使用 pause 镜像,并且 pause 镜像不是 multi-arch 镜像,应该更新 pause 镜像,要配置 pause 镜像,更新 CRI-O 配置文件:
pause_image = "k8s.gcr.io/pause-arm64:3.1"
  • 同时更新 edgecore.yaml 里面的 cgroup driver manager:
modules:
  edged:
    cgroupDriver: systemd
  • 启动 CRI-O 和 edgecore 服务(假设两项服务均由 systemd 负责):
sudo systemctl daemon-reload
sudo systemctl enable crio
sudo systemctl start crio
sudo systemctl start edgecore
  • 创建应用程序,并检查 CRI-O 容器是在边缘端创建:
kubectl apply -f $GOPATH/src/github.com/kubeedge/kubeedge/build/deployment.yaml
deployment.apps/nginx-deployment created

# crictl ps
CONTAINER ID        IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID
41c1a07fe7bf7       f6d22dec9931b       2 days ago          Running             nginx               0                   51f727498b06f

③ Kata Containers

  • Kata Containers 是一个 container runtime,旨在解决多租户、不受信任的云环境中的安全挑战。但是多租户支持仍在 KubeEdge 的 backlog 中,如果下游定制 KubeEdge 已经支持多租户,那么 Kata Containers 是轻量级且安全的 container runtime 的理想选择。
  • 按照 安装指南 安装和配置容器和 Kata Containers。如果安装了“kata-runtime”,请运行以下命令以检查主机系统是否可以运行并创建 Kata 容器:
kata-runtime kata-check
  • RuntimeClass 是一项功能,用于选择自 containerdv1.2.0 以来受支持的container runtime配置,以用于运行 Pod 的容器。如果 containerd 版本高于 v1.2.0,则有两种选择来配置 containerd 以使用 Kata 容器:
    • Kata Containers 作为 RuntimeClass;
    • Kata Containers 作为不受信任的工作负载的 runtime。
  • 假设您已将 Kata Containers 配置为不受信任的工作负载的 runtime,为了验证它是否可以在边缘节点上运行,可以运行:
cat nginx-untrusted.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-untrusted
  annotations:
    io.kubernetes.cri.untrusted-workload: "true"
spec:
  containers:
  - name: nginx
    image: nginx
    
    
kubectl create -f nginx-untrusted.yaml

# verify the container is running with qemu hypervisor on edge side,
ps aux | grep qemu
root      3941  3.0  1.0 2971576 174648 ?      Sl   17:38   0:02 /usr/bin/qemu-system-aarch64

crictl pods
POD ID              CREATED              STATE               NAME                NAMESPACE           ATTEMPT
b1c0911644cb9       About a minute ago   Ready               nginx-untrusted     default             0

④ Virtlet

  • 下载 CNI 插件安装包并解压它:
$ wget https://github.com/containernetworking/plugins/releases/download/v0.8.2/cni-plugins-linux-amd64-v0.8.2.tgz

# Extract the tarball
$ mkdir cni
$ tar -zxvf v0.2.0.tar.gz -C cni

$ mkdir -p /opt/cni/bin
$ cp ./cni/* /opt/cni/bin/
  • 配置 CNI 插件:
$ mkdir -p /etc/cni/net.d/

$ cat >/etc/cni/net.d/bridge.conf <<EOF

  "cniVersion": "0.3.1",
  "name": "containerd-net",
  "type": "bridge",
  "bridge": "cni0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": 
    "type": "host-local",
    "subnet": "10.88.0.0/16",
    "routes": [
       "dst": "0.0.0.0/0" 
    ]
  

EOF
  • 设置 VM runtime,使用 hack/setup-vmruntime.sh 脚本来设置 VM runtime,它利用 Arktos Runtime 安装包来启动三个容器:
vmruntime_vms
vmruntime_libvirt
vmruntime_virtlet

五、使用 Kubeflow 和 Volcano 实现典型 AI 训练任务

① Kubeflow 的诞生背景和运行 AI 计算任务面临的问题

  • Kubernetes 已经成为云原生应用编排、管理的事实标准,越来越多的应用选择向 Kubernetes 迁移。人工智能和机器学习领域天然的包含大量的计算密集型任务,开发者非常愿意基于 Kubernetes 构建 AI 平台,充分利用 Kubernetes 提供的资源管理、应用编排、运维监控能力。
  • 然而基于 Kubernetes 构建一个端到端的 AI 计算平台是非常复杂和繁琐的过程,它需要处理很多个环节。如下所示,除了熟知的模型训练环节之外还包括数据收集、预处理、资源管理、特性提取、数据验证、模型的管理、模型发布、监控等环节,对于一个 AI 算法工程师来讲,要做模型训练,就不得不搭建一套 AI 计算平台,这个过程耗时费力,而且需要很多的知识积累:

  • Kubeflow 诞生于 2017 年,Kubeflow 项目是基于容器和 Kubernetes 构建,旨在为数据科学家、机器学习工程师、系统运维人员提供面向机器学习业务的敏捷部署、开发、训练、发布和管理平台。它利用了云原生技术的优势,让用户更快速、方便的部署、使用和管理当前最流行的机器学习软件。
  • 目前 Kubeflow 1.0 版本已经发布,包含开发、构建、训练、部署四个环节,可全面支持企业用户的机器学习、深度学习完整使用过程,如下所示:

  • 通过 Kubeflow 1.0,用户可以使用 Jupyter 开发模型,然后使用 fairing(SDK)等工具构建容器,并创建 Kubernetes 资源训练其模型。模型训练完成后,用户还可以使用 KFServing 创建和部署用于推理的服务器,再结合 pipeline(流水线)功能可实现端到端机器学习系统的自动化敏捷构建,实现 AI 领域的 DevOps。

② Kubernetes 存在的问题

  • 既然有了 Kubeflow,是不是在 Kubernetes 上进行机器学习、深度学习就一帆风顺了呢?答案是否定的。我们知道 Kubeflow 在调度环境使用的是 kubernetes 的默认调度器,而 Kubernetes 默认调度器最初主要是为长服务设计的,对于 AI、大数据等批量和弹性调度方面还有很多的不足。
  • 主要存在以下问题:
    • 资源争抢问题:TensorFlow 的作业包含 Ps 和 Worker 两种不同的角色,这两种角色的 Pod 要配合起来完成整个作业,如果只是运行一种角色 Pod,整个作业是无法正常执行的,而默认调度器对于 Pod 调度是逐个进行的,对于 Kubeflow 作业 TFJob 的 Ps 和 Worker 是不感知的。在集群高负载(资源不足)的情况下,会出现多个作业各自分配到部分资源运行一部分 Pod,而又无法正执行完成的状况,从而造成资源浪费。以下为例,集群有 4 块 GPU 卡,TFJob1 和 TFJob2 作业各自有 4 个 Worker,TFJob1 和 TFJob2 各自分配到 2 个 GPU,但是 TFJob1 和 TFJob2 均需要 4 块 GPU 卡才能运行起来,这样 TFJob1 和 TFJob2 处于互相等待对方释放资源,这种死锁情况造成了 GPU 资源的浪费:

    • 亲和调度问题:分布式训练中,Ps 和 Worker 存在很频繁的数据交互,所以 Ps 和 Worker 之间的带宽直接影响了训练的效率。Kubernetes 默认调度器并不考虑 Ps 和 Worker 的这种逻辑关系,Ps 和 Worker 是被随机调度的。如下图所示,2 个 TFJob(1 个 Ps + 2 Worker),使用默认调度器,有可能会出现(a)、(b)、(c)三种情况的任意一种情况,我们知道(c)才是最想要的调度结果。因为在©中,Ps 和 Worker 可以利用本机网络提供传输效率,缩短训练时间:

③ Volcano 批量调度系统加速 AI 计算的利器

  • Volcano是一款构建于 Kubernetes 之上的增强型高性能计算任务批量处理系统。作为一个面向高性能计算场景的平台,它弥补了 kubernetes 在机器学习、深度学习、HPC、大数据计算等场景下的基本能力缺失,其中包括 gang-schedule 的调度能力、计算任务队列管理、task-topology 和 GPU 亲和性调度。另外,Volcano 在原生 kubernetes 能力基础上对计算任务的批量创建及生命周期管理、fair-share、binpack 调度等方面做了增强,Volcano 充分解决了上文提到的 Kubeflow 分布式训练面临的问题:

④ Volcano 在华为云的应用:实现典型分布式 AI 训练任务

  • Kubeflow 和 Volcano 两个开源项目的结合充分简化和加速 Kubernetes 上 AI 计算进程,当前已经成为越来越多用户的最佳选择,应用于生产环境。Volcano 目前已经应用于华为云 CCE、CCI 产品以及容器批量计算解决方案。未来 Volcano 会持续迭代演进,优化算法、增强调度能力如智能调度的支持,在推理场景增加 GPU Share 等特性的支持,进一步提升 kubeflow 批量训练和推理的效率。
  • 登录 CCE 控制台,创建一个 CCE 集群,详情请参见购买 CCE 集群
  • 在 CCE 集群上部署 Volcano 环境,单击左侧栏目树中的“插件管理”,在“插件市场”页签下单击 Volcano 插件下方的“安装插件”,在安装插件页面的“基本信息”步骤中选择要安装的集群和 Volcano 插件版本,单击“下一步:规格配置”:

  • Volcano 插件无可配置参数,直接单击“安装”,等待安装任务完成。
  • 安装 kfctl 工具并设置环境变量,环境变量设置如下:
export KF_NAME=<your choice of name for the Kubeflow deployment>
export BASE_DIR=<path to a base directory>
export KF_DIR=$BASE_DIR/$KF_NAME
export CONFIG_URI="https://raw.githubusercontent.com/kubeflow/manifests/v1.0-branch/kfdef/kfctl_k8s_istio.v1.0.2.yaml"
tar -xvf kfctl_v1.0.2_<platform>.tar.gz
chmod +x kfctl
mv kfctl /usr/local/bin/
  • 部署 kubeflow:
mkdir -p $KF_DIR
cd $KF_DIR
kfctl apply -V -f $CONFIG_URI 
  • 下载 kubeflow/examples 到本地并根据环境选择指南,命令如下:
yum install git
git clone https://github.com/kubeflow/examples.git
  • 安装 python3:
wget https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tgz
tar -zxvf Python-3.6.8.tgz
cd Python-3.6.8 ./configure
make make install
  • 安装完成后执行如下命令检查是否安装成功:
python3 -V 
pip3 -V
  • 安装 jupyter notebook 并启动,命令如下:
pip3 install jupyter notebook
jupyter notebook --allow-root
  • Putty 设置 tunnel,远程连接 notebook,连接成功后浏览器输入 localhost:8000,登录 notebook。

  • 根据 jupyter 的指引,创建分布式训练作业,通过简单的设置 schedulerName 字段的值为“volcano”,启用 Volcano 调度器:
kind: TFJob
metadata:
  name: train_name  
spec:
  schedulerName: volcano
  tfReplicaSpecs:
    Ps:
      replicas: num_ps
      template:
        metadata:
          annotations:
            sidecar.istio.io/inject: "false"
        spec:
          serviceAccount: default-editor
          containers:
          - name: tensorflow
            command:
            ...
            env:
            ...
            image: image
            workingDir: /opt
          restartPolicy: OnFailure
    Worker:
      replicas: 1
      template:
        metadata:
          annotations:
            sidecar.istio.io/inject: "false"
        spec:
          serviceAccount: default-editor
          containers:
          - name: tensorflow
            command:
            ...
            env:
            ...
            image: image
            workingDir: /opt
          restartPolicy: OnFailure
  • 提交作业,开始训练:
kubectl apply -f mnist.yaml
  • 等待训练作业完成,通过 Kubeflow 的 UI 可以查询训练结果信息。至此就完成了一次简单的分布式训练任务,Kubeflow 的借助 TFJob 简化了作业的配置。
  • Volcano 通过简单的增加一行配置就可以让用户启动组调度、Task-topology 等功能来解决死锁、亲和性等问题,在大规模分布式训练情况下,可以有效的缩短整体训练时间。

以上是关于华为云原生之KubeEdge深度使用体验与Kubeflow应用开发实践的主要内容,如果未能解决你的问题,请参考以下文章

深度解析KubeEdge EdgeMesh 高可用架构

KubeEdge:下一代云原生边缘设备管理标准DMI的设计与实现

深度解密:Kubernetes从中心走向边缘

深度揭秘华为边缘计算系统设计的六大核心原则

人工智能之华为云ModelArts的深度使用体验与AI Gallery应用开发实践

云原生2.0到来,生态伙伴的破浪成长之策