使用腾讯云GPU服务器实现边云协同推理

配置环境:

主机名

角色

IP

服务

VM-0-9-centos

云端

172.21.0.9(内网) 49.232.76.138(公网)

kuberbetes、docker、cloudcore

berbai02

边端

192.168.227.4

docker、edgecore

demo

边端

10.0.12.17

docker、edgecore

驱动安装

安装依赖包

代码语言:javascript
复制
# 安装dkms
sudo yum install -y dkms gcc kernel-devel yum-utils
​
# 检查是否已经安装dkms
rpm -qa | grep -i dkms
# 检查是否安装kernel-devel
rpm -qa | grep kernel-devel
# 检查是否安装GCC
rpm -qa | grep gcc
# 检查是否安装yum-utils
rpm -qa | grep yum-utils

如图1所示则表示已安装上述包。

图1 安装查询

下载驱动

访问http://www.nvidia.com/Download/Find.aspx,选择对应的驱动版本。下载页面如图2所示。

图2 下载驱动

## 复制驱动下载链接

复制过程如图3-1、图3-2所示。

图3-1 下载页面
图3-2 复制链接

下载驱动

通过wget在服务器上下载。有可以通过在本机下载驱动安装包再上传到服务器上。

代码语言:javascript
复制
wget https://us.download.nvidia.com/tesla/510.47.03/NVIDIA-Linux-x86_64-510.47.03.run

安装驱动

代码语言:javascript
复制
# 添加执行权限
chmod +x NVIDIA-Linux-x86_64-418.126.02.run
# 安装驱动
sudo sh  NVIDIA-Linux-x86_64-510.47.03.run

验证驱动安装情况

代码语言:javascript
复制
nvidia-smi
图6 驱动安装成功提示

KubeEdge安装

安装设置

  1. 关闭防火墙
代码语言:javascript
复制
# 停止防火墙
systemctl stop firewalld
# 关闭防火墙自启动
systemctl disable firewalld
图7 防火墙状态
  1. 禁用SELINUX

编辑文件/etc/selinux/config,内容修改如下:

代码语言:javascript
复制
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
图8 修改SELINUX配置
  1. 关闭swap

kubernetes安装需要关闭掉swap。修改/etc/fstab 文件中的 swap配置

代码语言:javascript
复制
sed -ri 's/.*swap.*/#&/' /etc/fstab  
图9 注释swap配置
  1. 重启系统,使修改生效
代码语言:javascript
复制
reboot

安装Docker

代码语言:javascript
复制
# 设置镜像仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 更新yum软件包索引
yum makecache fast
# 安装Docker CE
yum install docker-ce docker-ce-cli containerd.io
# 启动Docker
systemctl start docker
# 自启动
systemctl enable docker

测试docker安装情况

代码语言:javascript
复制
docker version
docker run hello-world
docker images
图10 Docker成功安装提示

部署Kubernetes

配置yum源

yum替换阿里云镜像源

代码语言:javascript
复制
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

安装kubeadm、kubectl

代码语言:javascript
复制
yum makecache
yum install -y kubelet kubeadm kubectl ipvsadm
# 指定版本安装
yum install kubelet-1.17.0-0.x86_64 kubeadm-1.17.0-0.x86_64 kubectl-1.17.0-0.x86_64

配置内核参数

代码语言:javascript
复制
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
vm.swappiness=0
EOF

加载所有的 sysctl 配置

sysctl --system
modprobe br_netfilter
sysctl -p /etc/sysctl.d/k8s.conf

加载ipvs相关内核模块

如果重新开机,需要重新加载(可以写在 /etc/rc.local 中开机自动加载)

modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack_ipv4

查看是否加载成功

lsmod | grep ip_vs

拉取镜像

查看kubeadm对应的k8s组件镜像版本,输出的镜像都是需要后续下载的。

代码语言:javascript
复制
[root@VM-0-9-centos ~]# kubeadm config images list
k8s.gcr.io/kube-apiserver:v1.23.5
k8s.gcr.io/kube-controller-manager:v1.23.5
k8s.gcr.io/kube-scheduler:v1.23.5
k8s.gcr.io/kube-proxy:v1.23.5
k8s.gcr.io/pause:3.6
k8s.gcr.io/etcd:3.5.1-0
k8s.gcr.io/coredns/coredns:v1.8.6

拉取上述镜像,国内机器大概率是不能从k8s.gcr.io拉取镜像的。

代码语言:javascript
复制
kubeadm config images pull

拉取完后查看镜像

代码语言:javascript
复制
[root@VM-0-9-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
k8s.gcr.io/kube-apiserver v1.23.5 3fc1d62d6587 4 weeks ago 135MB
k8s.gcr.io/kube-proxy v1.23.5 3c53fa8541f9 4 weeks ago 112MB
k8s.gcr.io/kube-controller-manager v1.23.5 b0c9e5e4dbb1 4 weeks ago 125MB
k8s.gcr.io/kube-scheduler v1.23.5 884d49d6d8c9 4 weeks ago 53.5MB
k8s.gcr.io/etcd 3.5.1-0 25f8c7f3da61 5 months ago 293MB
k8s.gcr.io/coredns 1.8.6 a4ca41631cc7 6 months ago 46.8MB
hello-world latest feb5d9fea6a5 6 months ago 13.3kB
k8s.gcr.io/pause 3.6 6270bb605e12 7 months ago 683kB

配置Kubelet(可选)

在云中心配置Kubelet主要是为了验证K8s集群的部署是否正确。

代码语言:javascript
复制
# 获取Docker的cgroups
DOCKER_CGROUPS=$(docker info | grep 'Cgroup' | cut -d' ' -f4)
echo $DOCKER_CGROUPS

配置kubelet的cgroups

cat >/etc/sysconfig/kubelet<<EOF
KUBELET_EXTRA_ARGS="--cgroup-driver=$DOCKER_CGROUPS --pod-infra-container-image=k8s.gcr.io/pause:3.1"
EOF

启动kubelet

systemctl daemon-reload
systemctl enable kubelet && systemctl start kubelet

特别说明:在这里使用systemctl status kubelet会发现报错误信息,这个错误在运行kubeadm init 生成CA证书后会被自动解决,此处可先忽略。

初始化集群

使用kudeadm init进行集群的初始化,初始化完成后需要记录下最后的输出——node节点添加到集群的命令。如果忘记该命令,可以使用kubeadm token create --print-join-command查看。

若采用云服务器可以去掉--apiserver-advertise-address配置

代码语言:javascript
复制
kubeadm init --kubernetes-version=v1.23.5 
--pod-network-cidr=10.244.0.0/16
--apiserver-advertise-address= 172.21.0.9
--ignore-preflight-errors=Swap

[root@VM-0-9-centos ~]# kubeadm init --kubernetes-version=v1.23.5
> --pod-network-cidr=10.244.0.0/16
> --ignore-preflight-errors=Swap
[init] Using Kubernetes version: v1.23.5

...

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown (id -u):(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.21.0.9:6443 --token 1tyany.dxr5ymxu2g3j0dzl
--discovery-token-ca-cert-hash sha256:a63bd724813ebe0c4aabadb8cc8c747b6c84c474b80d4104497542ec265ec36a

参数

说明

--apiserver-advertise-address

master 和 worker 间能互相通信的 IP

--kubernetes-version

指定版本

--token-ttl=0

token 永不过期

--apiserver-cert-extra-sans

节点验证证书阶段忽略错误

进一步配置kubectl

代码语言:javascript
复制
rm -rf $HOME/.kube
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown (id -u):(id -g) $HOME/.kube/config

到这一步,master节点安装完成。

查看node节点

代码语言:javascript
复制
[root@VM-0-9-centos ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
vm-0-9-centos NotReady control-plane,master 21m v1.23.5

配置网络插件 flannel(可选)

flannel Github地址:https://github.com/flannel-io/flannel

Kubernetes v1.17及以上 使用以下命令安装 flannel:

查看

代码语言:javascript
复制
[root@VM-0-9-centos ~]# kubectl get node -owide
NAME STATUS ROLES AGE VERSION
vm-0-9-centos NotReady control-plane,master 31m v1.23.5
[root@VM-0-9-centos ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-64897985d-9hfz2 0/1 Pending 0 31m
coredns-64897985d-9hr2z 0/1 Pending 0 31m
etcd-vm-0-9-centos 1/1 Running 0 31m
kube-apiserver-vm-0-9-centos 1/1 Running 0 31m
kube-controller-manager-vm-0-9-centos 1/1 Running 3 31m
kube-flannel-ds-t4k2w 0/1 Init:ImagePullBackOff 0 50s
kube-proxy-c6mck 1/1 Running 0 31m
kube-scheduler-vm-0-9-centos 1/1 Running 4 31m
[root@VM-0-9-centos ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 32m

注意:只有网络插件也安装配置完成之后,等待几分钟后,node才能会显示为ready状态。

配置 iptables 转发 IP

由于初始化时删除了 --apiserver-advertise-address 参数,返回的节点加入集群命令为内网IP,但几个云服务器内网不互通,所以我们需要使用 iptables 进行 IP 转发,将主节点公网IP转发至内网IP,由于node节点加入集群的命令是内网IP,因此还需要配置 node 节点将主节点的内网IP转发至主节点的公网IP。

代码语言:javascript
复制
# 在主节点 master
sudo iptables -t nat -A OUTPUT -d <主节点公网IP> -j DNAT --to-destination <主节点私有IP>

在 node 节点上

sudo iptables -t nat -A OUTPUT -d <主节点私有IP> -j DNAT --to-destination <主节点公网IP>

代码语言:javascript
复制
# cloud
sudo iptables -t nat -A OUTPUT -d 49.232.76.138 -j DNAT --to-destination 172.21.0.9

edge

sudo iptables -t nat -A OUTPUT -d 172.21.0.9 -j DNAT --to-destination 49.232.76.138

KubeEdge安装

Cloud配置

cloud端负责编译KubeEdge的相关组件与运行cloudcore。

安装必要环境
  1. 下载golang
代码语言:javascript
复制
wget https://golang.google.cn/dl/go1.18.1.linux-amd64.tar.gz
tar -zxvf go1.18.1.linux-amd64.tar.gz -C /usr/local
  1. 配置golang环境

/etc/profile文件末尾配置golang环境。

代码语言:javascript
复制
cat >> /etc/profile << EOF

golang env

export GOROOT=/usr/local/go
export GOPATH=/data/gopath
export PATH=PATH:GOROOT/bin:$GOPATH/bin
EOF

代码语言:javascript
复制
mkdir -p /data/gopath && cd /data/gopath
mkdir -p src pkg bin

使配置生效

source /etc/profile

  1. 下载KudeEdge源码
代码语言:javascript
复制
# 安装Git
yum install git

拉取源码

git clone https://github.com/kubeedge/kubeedge GOPATH/src/github.com/kubeedge/kubeedge</code></pre></div></div><h5 id="csim6" name="%E9%83%A8%E7%BD%B2cloudcore"><strong>部署cloudcore</strong></h5><ol class="ol-level-0"><li>编译kubeadm</li></ol><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">cd GOPATH/src/github.com/kubeedge/kubeedge
make all WHAT=keadm

说明:编译后的二进制文件在./_output/local/bin下

代码语言:javascript
复制
# 进入./_output/local/bin
cd ./_output/local/bin
  1. 创建cloud节点
代码语言:javascript
复制
[root@VM-0-9-centos kubeedge]# ./keadm init --advertise-address="172.21.0.9"
Kubernetes version verification passed, KubeEdge installation will start...

...

KubeEdge cloudcore is running, For logs visit: /var/log/kubeedge/cloudcore.log
CloudCore started

代码语言:javascript
复制
# 查看cloudcore状态
systemctl status cloudcore.service

Edge配置

edge端也可以通过keadm进行配置,可以将cloud端编译生成的二进制可执行文件通过scp命令复制到edge端。

安装必要环境
代码语言:javascript
复制
root@raspberrypi:~# uname -a
Linux raspberrypi 5.10.17-v7l+ #1414 SMP Fri Apr 30 13:20:47 BST 2021 armv7l GNU/Linux

树莓派需要安装ARMv6版本的golang环境。

代码语言:javascript
复制
wget https://golang.google.cn/dl/go1.18.1.linux-armv6l.tar.gz
tar -zxvf go1.18.1.linux-armv6l.tar.gz -C /usr/local

配置环境变量

代码语言:javascript
复制
cat >> /home/pi/.bashrc << EOF

golang env

export GOROOT=/usr/local/go
export GOPATH=/data/gopath
export PATH=PATH:GOROOT/bin:$GOPATH/bin
EOF

使配置生效

source /home/pi/.bashrc

下载kubeedge源码

代码语言:javascript
复制
# 安装Git
apt-get install git

拉取源码

git clone https://github.com/kubeedge/kubeedge $GOPATH/src/github.com/kubeedge/kubeedge

云端获取token令牌

token令牌在加入边缘节点时使用。

代码语言:javascript
复制
[root@VM-0-9-centos bin]# ./keadm gettoken
b6107885645ec34725a76e7cf3fd9d8bf130dfa5e6f37d4c51b6bc1bee49cd48.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTA2MjE0MDR9.ZMtQnF_oWYG4pijYO-SaxVtUYhHQSuCIauf5iWFkNMY
部署edgecore

编译keadm

代码语言:javascript
复制
cd $GOPATH/src/github.com/kubeedge/kubeedge
make all WHAT=keadm

进入./_output/local/bin

cd ./_output/local/bin

keadm join将安装edgecore和mqtt。它还提供了一个标志,通过它可以设置特定的版本。

代码语言:javascript
复制
./keadm join --cloudcore-ipport=172.21.0.9:10000 --token=9c71cbbb512afd65da8813fba9a48d19ab8602aa27555af7a07cd44b508858ae.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTA3MDgwNjN9.-S0YBgSSAz6loQsi0XaTgFeWyHsHDm8E2SAefluVTJA
Host has /usr/sbin/mosquitto already installed and running. Hence skipping the installation steps !!!

...

KubeEdge edgecore is running, For logs visit: journalctl -u edgecore.service -xe

注意:

  • --cloudcore-ipport 标志是强制性标志。
  • --token会自动为边缘节点应用证书。
  • 云和边缘端使用的kubeEdge版本应相同。

验证

边缘端在启动edgecore后,会与云端的cloudcore进行通信,K8s进而会将边缘端作为一个node纳入K8s的管控。

代码语言:javascript
复制
[root@VM-0-9-centos bin]# kubectl get node
NAME STATUS ROLES AGE VERSION
berbai02 Ready agent,edge 32m v1.22.6-kubeedge-v1.10.0
demo Ready agent,edge 34m v1.22.6-kubeedge-v1.10.0
vm-0-9-centos Ready control-plane,master 27h v1.23.5
[root@VM-0-9-centos bin]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-64897985d-9hfz2 1/1 Running 2 (69m ago) 27h
coredns-64897985d-9hr2z 1/1 Running 2 (69m ago) 27h
etcd-vm-0-9-centos 1/1 Running 2 (69m ago) 27h
kube-apiserver-vm-0-9-centos 1/1 Running 2 (69m ago) 27h
kube-controller-manager-vm-0-9-centos 1/1 Running 13 (69m ago) 27h
kube-flannel-ds-hsss5 0/1 Error 10 (2m23s ago) 34m
kube-flannel-ds-qp6xj 0/1 Error 9 (4m46s ago) 36m
kube-flannel-ds-t4k2w 1/1 Running 2 (69m ago) 27h
kube-proxy-6qcfb 0/1 ContainerCreating 0 34m
kube-proxy-c6mck 1/1 Running 2 (69m ago) 27h
kube-proxy-hvpz9 1/1 Running 0 36m
kube-scheduler-vm-0-9-centos 1/1 Running 14 (69m ago) 27h

说明:如果在K8s集群中配置过flannel网络插件,这里由于edge节点没有部署kubelet,所以调度到edge节点上的flannel pod会创建失败。这不影响KubeEdge的使用,可以先忽略这个问题。

云边协同实例

KubeEdge Counter Demo计数器是一个伪设备,用户无需任何额外的物理设备即可运行此演示。计数器在边缘侧运行,用户可以从云侧在Web中对其进行控制,也可以从云侧在Web中获得计数器值。

下载源码

代码语言:javascript
复制
git clone https://github.com/kubeedge/examples.git GOPATH/src/github.com/kubeedge/examples</code></pre></div></div><h4 id="36kih" name="%E5%88%9B%E5%BB%BAdevice-model"><strong>创建device model</strong></h4><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">cd GOPATH/src/github.com/kubeedge/examples/kubeedge-counter-demo/crds
kubectl create -f kubeedge-counter-model.yaml

创建device

根据你的实际情况修改matchExpressions:

代码语言:javascript
复制
cd $GOPATH/src/github.com/kubeedge/examples/kubeedge-counter-demo/crds

替换 "demo" 为你的 edge 节点名称

sed -i "s#edge-node#demo#" kubeedge-counter-instance.yaml
kubectl create -f kubeedge-counter-instance.yaml

部署云端应用

修改代码:云端应用web-controller-app用来控制边缘端的pi-counter-app应用,该程序默认监听的端口号为80,此处修改为8989。

代码语言:javascript
复制
cd $GOPATH/src/github.com/kubeedge/examples/kubeedge-counter-demo/web-controller-app
sed -i "s#80#8989#" main.go

构建镜像

注意:构建镜像时,如果开启了go mod请关闭。

代码语言:javascript
复制
make
make docker

部署web-controller-app

代码语言:javascript
复制
cd $GOPATH/src/github.com/kubeedge/examples/kubeedge-counter-demo/crds
kubectl create -f kubeedge-web-controller-app.yaml

部署边缘端应用

边缘端的pi-counter-app应用受云端应用控制,主要与mqtt服务器通信,进行简单的计数功能。

构建镜像

代码语言:javascript
复制
cd $GOPATH/src/github.com/kubeedge/examples/kubeedge-counter-demo/counter-mapper
make
make docker

部署Pi Counter App

代码语言:javascript
复制
cd $GOPATH/src/github.com/kubeedge/examples/kubeedge-counter-demo/crds
kubectl create -f kubeedge-pi-counter-app.yaml

说明:为了防止Pod的部署卡在ContainerCreating,这里直接通过docker save、scp和docker load命令将镜像发布到边缘端

代码语言:javascript
复制
docker save -o kubeedge-pi-counter.tar kubeedge/kubeedge-pi-counter:v1.0.0
scp kubeedge-pi-counter.tar root@10.0.12.17:/root
docker load -i kubeedge-pi-counter.tar

运行效果

现在,KubeEdge Demo的云端部分和边缘端的部分都已经部署完毕,如下:

代码语言:javascript
复制
[root@VM-0-9-centos crds]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kubeedge-counter-app-55848d84d9-545kh 1/1 Running 0 27m 172.21.0.9 vm-0-9-centos <none> <none>
kubeedge-pi-counter-54b7997965-t2bxr 1/1 Running 0 31m 10.0.12.17 demo <none> <none>

我们现在开始测试一下该Demo运行效果:

执行ON命令

在web页面上选择ON,并点击Execute,可以在edge节点上通过以下命令查看执行结果:

代码语言:javascript
复制
# 修改 counter-container-id 为kubeedge-pi-counter容器id
[root@demo kube]# docker logs -f counter-container-id
边端程序开启

查看counter STATUS

在web页面上选择STATUS,并点击Execute,会在Web页面上返回counter当前的status。

web app查看执行状态

执行OFF命令

在web页面上选择OFF,并点击Execute,可以再edge节点上通过以下命令查看执行结果。

边端程序关闭