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/rasaDockerfile中将容器内的用户设置为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供用户去训练模型,就更为智能了,以后的文章我们再来讨论。

Logo

开源、云原生的融合云平台

更多推荐