Rasa是一个对话式的AI框架,用于创建基于上下文的智能语音助手。这一节我们来看看如何将其部署到k8s集群中,并试一下其自带的模型。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。
Rasa
Rasa是基于python的AI框架,可以对用户提供的数据进行训练生成模型,以达到智能语音助手的目的。更多介绍可以查看其官网。
常规安装
在python3.6或者3.7版本下,直接pip安装即可
pip3 install rasa
之后会自动创建二进制可执行文件用作命令行操作
命令行操作
命令行提供绝大多数操作功能,从安装到训练再到起服务都可以完成,如下几个常用命令我们会在下面的操作中用到
命令 | 说明 |
---|---|
rasa init | 新建一个项目,其中包含了演示用的数据 |
rasa train | 根据提供的NLU数据训练模型,结果保存在./models 中 |
rasa run | 根据训练的模型起一个rasa服务器,默认监听5005端口,可修改 |
rasa -h | 查看帮助文档 |
更多的命令行操作参考这里
API操作
运行完rasa run
之后,就可以通过rasa服务器监听的端口进行HTTP API操作了,例如检查服务器状态,传递数据进行训练,和训练完成的服务器进行交互。所有的API信息可以查看这里。
这里需要特别指出的是对服务器状态的判断,如下
http://localhost:5005/
如果服务器正常返回200,可以用这一点来指定k8s中容器的存活检测。
部署到k8s
下面开始部署。我的部署环境是在博客《从零搭建可分配节点GPU资源至容器的Kubernetes集群(Nvidia版本)》中完成的集群,可以为本文的容器分配GPU资源。
准备自定义docker镜像
dockerhub上有一个现成可用的镜像rasa/rasa
,但是根据部署过程中遇到的坑,这里有个地方要改一下。为了安全起见,rasa/rasa
在Dockerfile中将容器内的用户设置为1001,如下
USER 1001
如果Dockerhub不能访问,请注意科学上网
这样子虽然安全,但是在部署过程中可能会有权限问题,所以我们要生成一个新的镜像,将用户改为root。同时也顺便将容器运行命令从rasa --help
改为rasa init
,如下
FROM rasa/rasa:1.10.1-full
USER root
CMD ["init"]
之后生成镜像
docker build -t myrasa:v2 .
待会就用这个镜像去部署到k8s中
Deployment
下面创建部署deployment用的yaml文件,如下
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: rasa-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: rasa
spec:
containers:
- name: myrasa
image: myrasa:v2
ports:
- containerPort: 5005
hostPort: 5005
protocol: TCP
command: ["/bin/sh","-c","rasa init --no-prompt;rasa run --enable-api"]
livenessProbe:
httpGet:
port: 5005
path: /
initialDelaySeconds: 1
periodSeconds: 3
resources:
limits:
aliyun.com/gpu-mem: 1
volumeMounts:
- mountPath: /app
name: rasa-app
- mountPath: /tmp
name: rasa-tmp
volumes:
- name: rasa-app
emptyDir: {}
- name: rasa-tmp
emptyDir: {}
这里有几个部分要注意一下
- livenessProbe
如果不指定存活检测(livenessProbe),会通过command
里面的命令是否执行完毕来决定容器是否存活,对这里不适用,不然容器会一直重启。这里是通过httpGet
进行的存活检测,也就是说容器的5005端口返回200表示容器一直存活,pod状态显示为Running。对于存活检测想了解更多的,可以参考《【Kubernetes 006】容器生命周期之探针Probe》
- command
这里的command
会覆盖掉Dockerfile中的ENTRYPOINT
。一共执行了两个命令,rasa init
会新建一个项目,在这个过程中会需要交互,所以用--no prompt
去自动选择,不然会报错。rasa run
则会起一个rasa服务器,这里监听默认的5005端口
如果不用
/bin/sh -c
的方法,命令是不会在shell中执行的,一定会失败
- volume
这里是根据Dockerfile中指定的两个VOLUME
来的,其中/app
是工作目录,存放主要的训练模型。这里为了简单起见使用了emptyDir
的方式,如果想直接从宿主机上进行操作可以采用hostPath
的方式,但是如果有多个host要注意路径的一致。对k8s中volume想了解更多的,可以参考《【Kubernetes 013】Volume原理和实际操作详解》
- resources
这里使用的是部署集群时候的aliyun插件,为每个容器分配1GiB的GPU。因为只有一个replica所以总消耗为1GiB
开始部署
kubectl apply -f rasa-deployment.yaml
成功以后查看一下状态
root@control-plane-1:~# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
curl-6bf6db5c4f-fr2xv 1/1 Running 0 28h 10.244.2.2 gpu-node <none> <none>
nvidia-deployment-5f4bbd9457-2rj7r 1/1 Running 1 28h 10.244.2.4 gpu-node <none> <none>
nvidia-deployment-5f4bbd9457-hfxqh 1/1 Running 1 28h 10.244.2.3 gpu-node <none> <none>
rasa-deployment-586ff4666-hf6xm 1/1 Running 0 26h 10.244.2.8 gpu-node <none> <none>
这个时候就可以通过pod的ip去对5005端口进行API操作了,例如
root@control-plane-1:~# curl 10.244.2.8:5005/
Hello from Rasa: 1.10.1
同时检查下GPU的分配情况
root@control-plane-1:~# kubectl-inspect-gpushare -d
NAME: gpu-node
IPADDRESS: 172.29.57.202
NAME NAMESPACE GPU0(Allocated)
nvidia-deployment-5f4bbd9457-2rj7r default 1
nvidia-deployment-5f4bbd9457-hfxqh default 1
rasa-deployment-586ff4666-hf6xm default 1
Allocated : 3 (42%)
Total : 7
-------------------------------------------------------------------------------------------------------------------------------------------------
Allocated/Total GPU Memory In Cluster: 3/7 (42%)
算上之前的2个测试用的容器一共分配了3GiB的GPU,符合预期
不过因为并没有跑什么学习任务,所以实际消耗的GPU并没有多少
root@gpu-node:/home/ubuntu/rasa# nvidia-smi
Thu May 21 17:57:48 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 435.21 Driver Version: 435.21 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce RTX 207... Off | 00000000:01:00.0 Off | N/A |
| 24% 27C P8 10W / 215W | 19MiB / 7982MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1765 G /usr/lib/xorg/Xorg 9MiB |
| 0 1799 G /usr/bin/gnome-shell 8MiB |
+-----------------------------------------------------------------------------+
Service
归根结底还是要外面的用户能访问到,所以还需要暴露一下端口,这个就比较简单了,直接nodePort即可
apiVersion: v1
kind: Service
metadata:
name: rasa-service
spec:
type: NodePort
selector:
app: rasa
ports:
- name: http
port: 5005
targetPort: 5005
nodePort: 31111
注意nodePort
的端口如果指定必须要大于30000,不然可以省略让系统自动分配一个端口。
创建
kubectl apply -f rasa-service.yaml
查看一下
root@control-plane-1:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d
rasa-service NodePort 10.108.95.50 <none> 5005:31111/TCP 20h
之后就可以通过node的外网ip来访问API了
[root@ai-asterisk ~]# curl 172.29.57.202:31111/
Hello from Rasa: 1.10.1
API操作
API的使用不是这篇博客的重点,但是有个API必须得说一下,就是一个交互式的API,API格式如下
POST /webhooks/rest/webhook
其中POST的json数据格式如下
{
"sender": "Rasa",
"message": "Hi there!"
}
sender可以随意指定,message是模仿用户说的话。
例如
[root@ai-asterisk ~]# curl -X POST 172.29.57.202:31111/webhooks/rest/webhook -d '{"sender":"xiaofu","message":"Hi there."}'
[{"recipient_id":"xiaofu","text":"Hey! How are you?"}]
[root@ai-asterisk ~]# curl -X POST 172.29.57.202:31111/webhooks/rest/webhook -d '{"sender":"xiaofu","message":"What is your name?"}'
[{"recipient_id":"xiaofu","text":"I am a bot, powered by Rasa."}]
[root@ai-asterisk ~]# curl -X POST 172.29.57.202:31111/webhooks/rest/webhook -d '{"sender":"xiaofu","message":"I love you."}'
[{"recipient_id":"xiaofu","text":"Great, carry on!"}]
总结
这样就成功将rasa部署到了k8s集群中。但是这样子远没有将k8s的优势利用起来,如果可以结合k8s的API进行自动生成pod供用户去训练模型,就更为智能了,以后的文章我们再来讨论。