clone好项目 一. 拉取镜像(CPU版本)
-
拉取tensorflow-serving镜像
docker pull tensorflow/serving
-
启动镜像 2.1 启动模型
格式如下
docker run -d -t --rm -p 8501:8501 -p 8500:8500 -v "模型绝对地址:/models/任务自定义名称" -e MODEL_NAME="任务自定义名称" tensorflow/serving &
按照上面的步骤,我们的模型路径是:
/root/tom/newspage-type-identify/model/
启动
docker run -d -t --rm -p 8501:8501 \
-v "/root/longjiang/newspage-type-identify/model:/models/newspage_type_identify" \
-e MODEL_NAME=newspage_type_identify \
tensorflow/serving &
2.2 接口测试
测试脚本
# -*- coding: utf-8 -*-
import os
import jieba
import numpy as np
import requests
from lxml.html import fromstring
from lxml.html import tostring
def file2element(file_path):
"""
convert file to element
:param file_path:
:return:
"""
if not os.path.exists(file_path):
return
with open(file_path, 'rb') as f:
return html2element(f.read())
def html2element(html: str):
"""
convert html to HtmlElement
:param html:
:return:
"""
if not html:
return None
try:
return fromstring(html)
except:
print(html)
def rest_client():
html_list = [file2element(r"C:\Users\longjiang\Desktop\list1.html")]
# html_list = [file2element(r"C:\Users\longjiang\Desktop\detail1.html")]
SPLIT_SEP = " "
sample_text_list = []
for html in html_list:
sample_text = SPLIT_SEP.join(jieba.lcut(tostring(html, encoding="utf-8"), HMM=False))
sample_text_list.append([sample_text])
a = np.array(sample_text_list)
data = {"instances": a.tolist()}
# 进行预测
r = requests.post("http://xx.xx.xx.xx:8501/v1/models/html_type_identify:predict",
json=data)
def _sigmoid(x):
return 1 / (1 + np.exp(-x))
res = r.json()['predictions'][0][0]
print(_sigmoid(res))
if __name__=='__main__':
rest_client()
二. 在k8s中部署
- 创建docker镜像
- 后台运行serving容器
docker run -d --rm --name serving_base tensorflow/serving
1.1 拷贝模型数据到容器中的model目录
docker cp /root/longjiang/newspage-type-identify/model serving_base:/models/newspage_type_identify
1.2 commit容器,将新的镜像保存为serving newspage_type_identify:
docker commit --change "ENV MODEL_NAME newspage_type_identify" serving_base newspage_type_identify_serving
newspage_type_identify_serving将是我们的新的镜像
1.3 停止并删除serving base镜像
docker kill serving_base
docker rm serving_base
2. 测试自定义的serving
2.1 启动服务
如果之前的服务还启动着,要停掉,否则8501端口被占用会无法启动新服务
docker run -d -p 8501:8501 -t newspage_type_identify_serving &
使用上面的客户端调用测试一下,注意,这一步我把接口名字换成了 /v1/models/newspage_type_identify:predict
3. 部署到k8s
将镜像推送到私有仓库,私有仓库的搭建见:juejin.cn/post/710149…, 当然也可以上传到docker hub的私有库里去,或者使用阿里云的免费私有仓库 3.1 将自定义的镜像推送到镜像仓库
docker tag newspage_type_identify_serving:latest 10.0.0.12:5000/newspage_type_identify_serving:v1
docker push 10.0.0.12:5000/newspage_type_identify_serving:v1
# login success
docker tag newspage_type_identify_serving:latest registry.cn-hangzhou.aliyuncs.com/nln/newspage_type_identify_serving:v1
docker push registry.cn-hangzhou.aliyuncs.com/nln/newspage_type_identify_serving:v1
3.2 通过kubectl 命令创建secret
kubectl create secret docker-registry [secret名称] --docker-server=[私有仓库ip:端口] --docker-username=[用户名] --docker-password=[密码] --namespace=[k8s命名空间]
例如
kubectl create secret docker-registry aliyun-registry-secret --docker-server=registry.cn-hangzhou.aliyuncs.com/nln --docker-username=xxxxxxxx --docker-password=xxxxxxx
创建完成后,可以查看下
kubectl get secret aliyun-registry-secret --output=yaml
3.2 创建deployment.yaml(master机器)
在master机器上创建 vim newspage_type_identify_k8s.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: newspage-type-identify-deployment
spec:
replicas: 1
selector:
matchLabels:
app: newspage-type-identify-server
template:
metadata:
labels:
app: newspage-type-identify-server
spec:
containers:
- name: newspage-type-identify-container
image: registry.cn-hangzhou.aliyuncs.com/nln/newspage_type_identify_serving:v1
ports:
- containerPort: 8501
imagePullSecrets:
- name: aliyun-registry-secret
---
apiVersion: v1
kind: Service
metadata:
labels:
run: newspage-type-identify-service
name: newspage-type-identify-service
spec:
ports:
- port: 8501
targetPort: 8501
selector:
app: newspage-type-identify-server
type: LoadBalancer
然后
kubectl apply -f newspage_type_identify_k8s.yaml
-
查看deployments
kubectl get deployments
-
查看部署的所有副本
kubectl get pod
-
查看部署的services
kubectl get services
-
查看部署服务的详情
kubectl describe service newspage-type-identify-service
,其中的IP即外网ip -
删除 newspage_type_identify_k8s.yaml
kubectl delete -f newspage_type_identify_k8s.yaml
-
删除所有pod
kubectl delete pod --all
-
删除某一个pod
kubectl delete pod POD_NAME
-
删除某一个service
kubectl delete svc SERVICE_NAME
3.3 安装Kuboard
docker run -d \
--restart=unless-stopped \
--name=kuboard \
-p 80:80/tcp \
-p 10081:10081/tcp \
-e KUBOARD_ENDPOINT="http://内网IP:80" \
-e KUBOARD_AGENT_SERVER_TCP_PORT="10081" \
-v /root/kuboard-data:/data \
eipwork/kuboard:v3
注意:
- KUBOARD_ENDPOINT 参数的作用是,让部署到 Kubernetes 中的
kuboard-agent
知道如何访问 Kuboard Server; - KUBOARD_ENDPOINT 中也可以使用外网 IP;
- Kuboard 不需要和 K8S 在同一个网段,Kuboard Agent 甚至可以通过代理访问 Kuboard Server;
- 建议在 KUBOARD_ENDPOINT 中使用域名;
- 如果使用域名,必须能够通过 DNS 正确解析到该域名,如果直接在宿主机配置
/etc/hosts
文件,将不能正常运行;
参数解释:
- 建议将此命令保存为一个 shell 脚本,例如
start-kuboard.sh
,后续升级 Kuboard 或恢复 Kuboard 时,需要通过此命令了解到最初安装 Kuboard 时所使用的参数; - 第 4 行,将 Kuboard Web 端口 80 映射到宿主机的
80
端口(您可以根据自己的情况选择宿主机的其他端口); - 第 5 行,将 Kuboard Agent Server 的端口
10081/tcp
映射到宿主机的10081
端口(您可以根据自己的情况选择宿主机的其他端口); - 第 6 行,指定 KUBOARD_ENDPOINT 为
http://内网IP
,如果后续修改此参数,需要将已导入的 Kubernetes 集群从 Kuboard 中删除,再重新导入; - 第 7 行,指定 KUBOARD_AGENT_SERVER 的端口为
10081
,此参数与第 5 行中的宿主机端口应保持一致,修改此参数不会改变容器内监听的端口10081
,例如,如果第 5 行为-p 30081:10081/tcp
则第 7 行应该修改为-e KUBOARD_AGENT_SERVER_TCP_PORT="30081"
; - 第 8 行,将持久化数据
/data
目录映射到宿主机的/root/kuboard-data
路径,请根据您自己的情况调整宿主机路径;
例如
docker run -d \
--restart=unless-stopped \
--name=kuboard \
-p 8089:80/tcp \
-p 10081:10081/tcp \
-e KUBOARD_ENDPOINT="http://10.0.0.12:8089" \
-e KUBOARD_AGENT_SERVER_TCP_PORT="10081" \
-v /root/container/k8s_project/kuboard-data:/data \
eipwork/kuboard:v3
访问
http://ip:port:8089
初始用户名密码:
admin
Kuboard123
【报错】
- No versions of servable
W tensorflow_serving/sources/storage_path/file_system_storage_path_source.cc:268] No versions of servable html_type_identify found under base path /models/html_type_identify. Did you forget to name your leaf directory as a number (eg. '/1/')?
解决:模型目录不正确,检查是否是模型的绝对路径
- exceeds 10% of free system memory
W external/org_tensorflow/tensorflow/core/framework/cpu_allocator_impl.cc:80] Allocation of 19826176 exceeds 10% of free system memory
解决:网上的解决办法是减小batch size,没有试过
External-IP
一直显示pending
Kubernetes
不为裸机集群提供网络负载均衡器的实现,如果使用minikube、kubeadm自检的Kubernetes集群,是不支持LoadBalancer
的(与 AWS、Google Cloud、阿里云等云厂商不同),此时,只能使用NodePort
或Ingress Controller
, 相反,如果配置中部署了LoadBalancer
则会出现External-IP
一直处于pending
的问题
解决:
使用Ingress为外部访问集群提供了一个统一入口,类似与nginx。
要使用 Ingress,需要一个负载均衡器 + Ingress Controller
如果是裸机(bare metal) 搭建的集群,你需要自己安装一个负载均衡插件,可以安装 MetalLB
如果是云服务商,会自动给你配置,否则你的外部 IP 会是 “pending” 状态,无法使用。