Kubernetes + Docker 从零部署一个yolov5检测服务,服务基于PaddlePaddle/FastDeploy的服务化部署;所有软件从零安装。
文章目录
- 1.说明
- 2.环境
- 3.安装过程
- · 3.1安装 Docker
- · 3.2安装 minikube
- · 3.3安装 Kubectl
- 4.部署过程
- · 4.1 Docker相关
- · 4.2 k8s相关
- · 4.3 启动服务
- · 4.4 客户端测试
- 五.总结
- 六.引用
1.说明
- 基于k8s的minikube部署一个单节点服务,重了解在部署流程和细节。
- 服务基于CPU部署。
2.环境
WSL2 Ubuntu 18.04
kubernetes v1.23.8
Docker 23.0.0
PaddlePaddle/FastDeploy
3.安装过程
· 3.1安装 Docker
#1. 新软件列表和允许使用https
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
#2.添加阿里源的GPG
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
#3.设置阿里源的docker仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
#4.安装docker:
#4.1更新apt-get
sudo apt-get update
#4.2安装最新的docker版本
sudo apt-get install docker-ce docker-ce-cli containerd.io
#4.3启动docker
sudo service docker start
#4.4查看docker服务状态
sudo service docker status
· 3.2安装 minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
- 这里启动大约要5分钟
#启动k8s,使用docker为引擎.
minikube start --force --driver=docker --kubernetes-version=v1.23.8
- 验证minikube启动情况
minikube kubectl get ns
#显示一下说明成功
root@DESKTOP-4J64IFF:~# minikube kubectl get ns
NAME STATUS AGE
default Active 8d
kube-node-lease Active 8d
kube-public Active 8d
kube-system Active 8d
kubernetes-dashboard Active 8d
· 3.3安装 Kubectl
- 安装
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
kubectl version --client
- 测试
kubectl get pod -A
4.部署过程
· 4.1 Docker相关
- 下载CPU镜像,仅支持Paddle/ONNX模型在CPU上进行服务化部署,支持的推理后端包括OpenVINO、Paddle Inference和ONNX Runtime。
docker pull registry.baidubce.com/paddlepaddle/fastdeploy:1.0.2-cpu-only-21.10
- 下载部署代码,及模型等
#下载部署示例代码
git clone https://github.com/PaddlePaddle/FastDeploy.git
cd FastDeploy/examples/vision/detection/yolov5/serving/
#下载yolov5模型文件和测试图片
wget https://gitee.com/paddlepaddle/PaddleDetection/raw/release/2.4/demo/000000014439.jpg
wget https://bj.bcebos.com/paddlehub/fastdeploy/yolov5s.onnx
# 将模型放入 models/runtime/1目录下, 并重命名为model.onnx
mv yolov5s.onnx models/runtime/1/model.onnx
- 启动docker测试服务(可跳过)
######################### 服务端 ##############################
cd FastDeploy/examples/vision/detection/yolov5/serving/
# 手动启动docker
docker run -it --net=host --name fd_serving -v `pwd`/:/yolov5_serving registry.baidubce.com/paddlepaddle/fastdeploy:x.y.z-cpu-only-21.10 bash
#启动服务
fastdeployserver --model-repository=/yolov5_serving/models --backend-config=python,shm-default-byte-size=10485760
#服务启动成功后, 会有以下输出:
#I0928 04:51:15.784517 206 grpc_server.cc:4117] Started GRPCInferenceService at 0.0.0.0:8001
#I0928 04:51:15.785177 206 http_server.cc:2815] Started HTTPService at 0.0.0.0:8000
#I0928 04:51:15.826578 206 http_server.cc:167] Started Metrics Service at 0.0.0.0:8002
######################### 客户端 ##############################
cd FastDeploy/examples/vision/detection/yolov5/serving/
#安装端依赖
python3 -m pip install tritonclient[all]
# 发送请求
python3 yolov5_grpc_client.py
#发送请求成功后,会返回json格式的检测结果并打印输出:
#output_name: detction_result
#{'boxes': [[268.48028564453125, 81.05305480957031, 298.69476318359375, 169.43902587890625], [104.73116302490234, 45.66197204589844, 127.58382415771484, 93.44938659667969], [378.9093933105469, 39.75013732910156, 395.6086120605469, 84.24342346191406], [158.552978515625, 80.36149597167969, 199.18576049804688, 168.18191528320312], [414.37530517578125, 90.94805908203125, 506.3218994140625, 280.40521240234375], [364.00341796875, 56.608917236328125, 381.97857666015625, 115.96823120117188], [351.7251281738281, 42.635345458984375, 366.9103088378906, 98.04837036132812], [505.8882751464844, 114.36674499511719, 593.1248779296875, 275.99530029296875], [327.7086181640625, 38.36369323730469, 346.84991455078125, 80.89302062988281], [583.493408203125, 114.53289794921875, 612.3546142578125, 175.87353515625], [186.4706573486328, 44.941375732421875, 199.6645050048828, 61.037628173828125], [169.6158905029297, 48.01460266113281, 178.1415557861328, 60.88859558105469], [25.81019401550293, 117.19969177246094, 59.88878631591797, 152.85012817382812], [352.1452941894531, 46.71272277832031, 381.9460754394531, 106.75212097167969], [1.875, 150.734375, 37.96875, 173.78125], [464.65728759765625, 15.901412963867188, 472.512939453125, 34.11640930175781], [64.625, 135.171875, 84.5, 154.40625], [57.8125, 151.234375, 103.0, 174.15625], [165.890625, 88.609375, 527.90625, 339.953125], [101.40625, 152.5625, 118.890625, 169.140625]], 'scores': [0.8965693116188049, 0.8695310950279236, 0.8684297800064087, 0.8429877758026123, 0.8358422517776489, 0.8151364326477051, 0.8089362382888794, 0.801361083984375, 0.7947245836257935, 0.7606497406959534, 0.6325908303260803, 0.6139386892318726, 0.5906146764755249, 0.505328893661499, 0.40457233786582947, 0.3460320234298706, 0.33283042907714844, 0.3325657248497009, 0.2594234347343445, 0.25389009714126587], 'label_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 24, 24, 33, 24], 'masks': [], 'contain_masks': False}
- 编写Dockerfile
FROM registry.baidubce.com/paddlepaddle/fastdeploy:1.0.2-cpu-only-21.10
## 编写人
MAINTAINER xxx
# 在docker容器构建时拷贝程序
ADD ./FastDeploy-develop /opt/FastDeploy-develop
# 容器暴露的端口号,需要在容器中运行使用端口号一致
EXPOSE 8000
EXPOSE 8001
# 容器启动之后执行的命令, java -jar ROOT.jar
CMD ["cd /opt/FastDeploy-develop/examples/vision/detection/yolov5/serving"]
CMD ["fastdeployserver","--model-repository=/opt/FastDeploy-develop/examples/vision/detection/yolov5/serving/models","--backend-config=python,shm-default-byte-size=10485760"]
- 打包images
docker build -t k8s_yolo_demo:latest .
· 4.2 k8s相关
- 生成Deployment yaml
kubectl create deployment demo --image=k8s_yolo_demo:latest -o yaml --dry-run=client > demo.yaml
#在本地路径下会生成demo.yaml
- 修改demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: demo
name: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: demo
spec:
containers:
- image: k8s_yolo_demo
imagePullPolicy: IfNotPresent
name: k8s_yolo_demo
resources: {}
ports:
- containerPort: 8001
status: {}
- 编写server yaml
apiVersion: v1
kind: Service
metadata:
name: demo
spec:
type: NodePort #这里代表是NodePort类型的,另外还有ingress,LoadBalancer(这里映射到本机IP)
ports:
- port: 8001 #这里的端口和clusterIP(kubectl describe service service-hello中的IP的port)对应,即在集群中所有机>器上curl 10.98.166.242:80可访问发布的应用服务。
targetPort: 8001 #端口一定要和container暴露出来的端口对应,nodejs暴露出来的端口是8081,所以这里也应是8081
nodePort: 31111 # 所有的节点都会开放此端口30000--32767,此端口供外部调用。
selector:
app: demo #这里选择器一定要选择容器的标签,之前写name:kube-node是错的。
· 4.3 启动服务
# 首先启动
kubectl apply -f demo.yaml
# 可能会报错 获取不到images
# 这里demo.yaml 中添加 imagePullPolicy: IfNotPresent (已添加过了)
# 这里使用cache方式获取images
# 1.添加环境变量 使得k8s 使用docker
eval $(minikube docker-env)
# 2.把images添加到k8s的cache中去
minikube cache add k8s_yolo_demo
# 3.从新加载启动
kubectl apply -f demo.yaml
# 4.查看启动的pod 是否running
kubectl get pods
# 5.把images从k8s的cache中删掉
minikube cache delete k8s_yolo_demo
# 6.启动server
kubectl apply -f demo_server.yaml
如图这里看到pod和server都正常启动了:
· 4.4 客户端测试
# 查看本机IP
ifconfig
#修改客户端代码中的url
url = "192.168.49.1:31111"
python3 yolov5_grpc_client.py
#发送请求成功后,会返回json格式的检测结果并打印输出:
#output_name: detction_result
#{'boxes': [[268.48028564453125, 81.05305480957031, 298.69476318359375, 169.43902587890625], [104.73116302490234, 45.66197204589844, 127.58382415771484, 93.44938659667969], [378.9093933105469, 39.75013732910156, 395.6086120605469, 84.24342346191406], [158.552978515625, 80.36149597167969, 199.18576049804688, 168.18191528320312], [414.37530517578125, 90.94805908203125, 506.3218994140625, 280.40521240234375], [364.00341796875, 56.608917236328125, 381.97857666015625, 115.96823120117188], [351.7251281738281, 42.635345458984375, 366.9103088378906, 98.04837036132812], [505.8882751464844, 114.36674499511719, 593.1248779296875, 275.99530029296875], [327.7086181640625, 38.36369323730469, 346.84991455078125, 80.89302062988281], [583.493408203125, 114.53289794921875, 612.3546142578125, 175.87353515625], [186.4706573486328, 44.941375732421875, 199.6645050048828, 61.037628173828125], [169.6158905029297, 48.01460266113281, 178.1415557861328, 60.88859558105469], [25.81019401550293, 117.19969177246094, 59.88878631591797, 152.85012817382812], [352.1452941894531, 46.71272277832031, 381.9460754394531, 106.75212097167969], [1.875, 150.734375, 37.96875, 173.78125], [464.65728759765625, 15.901412963867188, 472.512939453125, 34.11640930175781], [64.625, 135.171875, 84.5, 154.40625], [57.8125, 151.234375, 103.0, 174.15625], [165.890625, 88.609375, 527.90625, 339.953125], [101.40625, 152.5625, 118.890625, 169.140625]], 'scores': [0.8965693116188049, 0.8695310950279236, 0.8684297800064087, 0.8429877758026123, 0.8358422517776489, 0.8151364326477051, 0.8089362382888794, 0.801361083984375, 0.7947245836257935, 0.7606497406959534, 0.6325908303260803, 0.6139386892318726, 0.5906146764755249, 0.505328893661499, 0.40457233786582947, 0.3460320234298706, 0.33283042907714844, 0.3325657248497009, 0.2594234347343445, 0.25389009714126587], 'label_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 24, 24, 33, 24], 'masks': [], 'contain_masks': False}
五.总结
- 最有问题的还是pod IP映射的问题,没搞清k8s的端口映射逻辑。
- 本机由于虚拟机启动IP会变动为 192.168.49.1,实际服务是之前启动的,已经映射到了192.168.49.2上,这里需要从新启动下server,就会从新映射到当前IP。
- 这里k8s获取docker image的方式也有问题,这是测试无所谓了;正式部署不会存在这种问题。
- GPU方式还没尝试,有空了再试试,主要是搭建环境比较麻烦。
六.引用
https://github.com/PaddlePaddle/FastDeploy/blob/develop/examples/vision/detection/yolov5/serving/README_CN.md
https://www.jianshu.com/p/c8b42d5cda2d