Kubernetes api微服务开发之jupyter模型创建

目标:完成模型开发功能中的Model创建,返回jupyter notebook访问信息

概述

人工智能服务中模型开发功能的实现主要参考金山云方案,提供一个tensorflow容器,并通过jupyter notebook编写代码,实现模型开发。

本文使用容器镜像为jupyter/tensorflow-notebook

Replication Controller功能修改

DevK8sApiService.java在原有rc创建代码的基础上,增加cpu与memory设定的功能:

//创建Replication Controller
public ReplicationController createRC(String rcName, String nsName, String lbkey, String lbvalue,
                                      int replicas, String ctName, String imName, int cnPort,
                                      String cpuRes, String memRes, String cpuLim, String memLim) {
    Quantity cpuQn = new QuantityBuilder()
            .withAmount(cpuRes)
            .build();
    Quantity memQn = new QuantityBuilder()
            .withAmount(memRes)
            .build();
    Quantity cpuliQn = new QuantityBuilder()
            .withAmount(cpuLim)
            .build();
    Quantity memliQn = new QuantityBuilder()
            .withAmount(memLim)
            .build();
    ReplicationController rc = new ReplicationControllerBuilder()
            .withApiVersion("v1")
            .withKind("ReplicationController")
            .withNewMetadata()
            .withName(rcName)
            .withNamespace(nsName)
            .addToLabels(lbkey, lbvalue)
            .endMetadata()
            .withNewSpec()
            .withReplicas(replicas)
            .addToSelector(lbkey, lbvalue)
            .withNewTemplate()
            .withNewMetadata()
            .addToLabels(lbkey, lbvalue)
            .endMetadata()
            .withNewSpec()
            .addNewContainer()
            .withName(ctName)
            .withImage(imName)
            .addNewPort()
            .withContainerPort(cnPort)
            .endPort()
            .withNewResources()
            .addToRequests("cpu", cpuQn)
            .addToRequests("memory", memQn)
            .addToLimits("cpu", cpuliQn)
            .addToLimits("memory", memliQn)
            .endResources()
            .endContainer()
            .endSpec()
            .endTemplate()
            .endSpec()
            .build();
    try {
        kubernetesClient.replicationControllers().create(rc);
        System.out.println("replication controller create success");
    } catch (Exception e) {
        System.out.println("replication controller create failed");
    }
    return rc;
}

其中request为初始运行时占用的资源值,limit为最大能使用的资源值。

将新增参数加入DevK8sApiController.java

//k8s rc create
@RequestMapping(value = "/createRCWithinQuantity", method = RequestMethod.POST)
public ReplicationController createK8sRC(@RequestParam(value = "ReplicationControllerName") String rcName,
                                         @RequestParam(value = "NamespaceName") String nsName,
                                         @RequestParam(value = "LabelKey") String lbkey,
                                         @RequestParam(value = "LabelValue") String lbvalue,
                                         @RequestParam(value = "Replicas") int replicas,
                                         @RequestParam(value = "ContainerName") String ctName,
                                         @RequestParam(value = "ImageName") String imName,
                                         @RequestParam(value = "ContainerPort") int cnPort,
                                         @RequestParam(value = "CpuR") String cpurName,
                                         @RequestParam(value = "MemR") String memrName,
                                         @RequestParam(value = "CpuL") String cpulName,
                                         @RequestParam(value = "MemL") String memlName) {
    return devK8sApiService.createRC(rcName, nsName, lbkey, lbvalue, replicas, ctName, imName, cnPort, cpurName, memrName, cpulName, memlName);
}

TensorFlow Jupyter Notebook应用创建

修改完成后重新构建项目,启动应用

创建replication controller

POST: http://127.0.0.1:8080/k8s/createRCWithinQuantity
Content-Type: application/x-www-form-urlencoded
Body: {"NameSpaceName":"appblog", "ReplicationControllerName":"tf-nb-rc", "LabelKey":"name", "LabelValue":"tf-nb", "Replicas":"1", "ContainerName":"tf-nb", "ImageName":"jupyter/tensorflow-notebook", "ContainerPort":"8888", "CpuR":"1", "MemR":"1Gi", "CpuL":"1", "MemL":"2Gi"}

注:jupyter/tensorflow-notebookContainerPort必须为8888

{
    "apiVersion": "v1",
    "kind": "ReplicationController",
    "metadata": {
        "annotations": {},
        "labels": {
            "name": "tf-nb"
        },
        "name": "tf-nb-rc",
        "namespace": "appblog"
    },
    "spec": {
        "replicas": 1,
        "selector": {
            "name": "tf-nb"
        },
        "template": {
            "metadata": {
                "annotations": {},
                "labels": {
                    "name": "tf-nb"
                }
            },
            "spec": {
                "containers": [
                    {
                        "image": "jupyter/tensorflow-notebook",
                        "name": "tf-nb",
                        "ports": [
                            {
                                "containerPort": 8888
                            }
                        ],
                        "resources": {
                            "limits": {
                                "cpu": "1",
                                "memory": "2Gi"
                            },
                            "requests": {
                                "cpu": "1",
                                "memory": "1Gi"
                            }
                        }
                    }
                ],
                "nodeSelector": {}
            }
        }
    }
}

在master节点上查看rc信息:

[root@k8s-master ~]# kubectl get pods -n appblog
NAME                    READY   STATUS    RESTARTS   AGE
tf-nb-rc-vs52b          1/1     Running   0          9m2s
[root@k8s-master ~]# kubectl describe rc tf-nb-rc -n appblog
Name:         tf-nb-rc
Namespace:    appblog
Selector:     name=tf-nb
Labels:       name=tf-nb
Annotations:  <none>
Replicas:     1 current / 1 desired
Pods Status:  0 Running / 1 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  name=tf-nb
  Containers:
   tf-nb:
    Image:      jupyter/tensorflow-notebook
    Port:       8888/TCP
    Host Port:  0/TCP
    Limits:
      cpu:     2
      memory:  2Gi
    Requests:
      cpu:        1
      memory:     1Gi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age   From                    Message
  ----    ------            ----  ----                    -------
  Normal  SuccessfulCreate  10s   replication-controller  Created pod: tf-nb-rc-vs52b

创建service

POST: http://127.0.0.1:8080/k8s/createService
Content-Type: application/x-www-form-urlencoded
Body: {"ServiceName":"tf-nb-service", "NameSpaceName":"appblog", "LabelKey":"name", "LabelValue":"tf-nb", "ContainerPort":"80", "NodePort":"30050"}

{
    "apiVersion": "v1",
    "kind": "Service",
    "metadata": {
        "annotations": {},
        "labels": {
            "name": "tf-nb"
        },
        "name": "tf-nb-service",
        "namespace": "appblog"
    },
    "spec": {
        "ports": [
            {
                "nodePort": 30050,
                "port": 8888
            }
        ],
        "selector": {
            "name": "tf-nb"
        },
        "type": "NodePort"
    }
}

在master节点上查看service信息:

[root@k8s-master ~]# kubectl get service tf-nb-service -n appblog
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
tf-nb-service   NodePort   10.98.57.109   <none>        8888:30050/TCP   24s

访问:http://NodeIP:30050

需要获取notebook的token才能访问。

jupyter登陆

获取notebook token

编写token获取方法:

//token查询
public Map<String, String> readToken(String nsName, String rcName, String lbKey, String lbValue) {
    Map<String, String> resourceInfo = new HashMap<String, String>();

    try {
        //ExecWatch tokenResult = kubernetesClient.pods().inNamespace(nsName).withName(rcName).exec("jupyter notebook list");
        PodList podList = kubernetesClient.pods().inNamespace(nsName).withLabel(lbKey, lbValue).list();
        for (Pod pod : podList.getItems()) {
            String podName = pod.getMetadata().getName();
            String podLog = kubernetesClient.pods().inNamespace(nsName).withName(podName).getLog();
            resourceInfo.put(podName + "token: ", podLog);
        }
        //resourceInfo.put("token: ", tokenResult.toString());
        log.error("model token get success");
    } catch (Exception e) {
        log.error("model token get failed");
        log.error("", e);
    }
    return resourceInfo;
}

因执行exec会有认证的问题,此处使用getLog的方法获取启动日志,在日志中查询token。

同时修改DevK8sApiController.java

//token read
@RequestMapping(value = "/readToken", method = RequestMethod.GET)
public Map<String, String> readJNtoken(@RequestParam(value = "NamespaceName") String nsName,
                                       @RequestParam(value = "ReplicationControllerName") String rcName,
                                       @RequestParam(value = "LabelKey") String lbkey,
                                       @RequestParam(value = "LabelValue") String lbvalue) {
    return devK8sApiService.readToken(nsName, rcName, lbkey, lbvalue);
}

因为rc创建的pod都会随机生成5位字符串,所以通过Label查询pod名称,并获取日志。

URL: http://127.0.0.1:8080/k8s/readToken?NamespaceName=appblog&ReplicationControllerName=tf-nb-rc&LabelKey=name&LabelValue=tf-nb

{
    "tf-nb-rc-gzz5jtoken: ": "Executing the command: jupyter notebook\n[I 01:25:06.115 NotebookApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret\n[I 01:25:07.998 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.7/site-packages/jupyterlab\n[I 01:25:07.998 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab\n[I 01:25:08.000 NotebookApp] Serving notebooks from local directory: /home/jovyan\n[I 01:25:08.000 NotebookApp] The Jupyter Notebook is running at:\n[I 01:25:08.000 NotebookApp] http://(tf-nb-rc-gzz5j or 127.0.0.1):8888/?token=f94b3960fb6a1b50f06d07b1211f41b38c26a3a3ec3e9173\n[I 01:25:08.000 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).\n[C 01:25:08.005 NotebookApp] \n    \n    To access the notebook, open this file in a browser:\n        file:///home/jovyan/.local/share/jupyter/runtime/nbserver-6-open.html\n    Or copy and paste one of these URLs:\n        http://(tf-nb-rc-gzz5j or 127.0.0.1):8888/?token=f94b3960fb6a1b50f06d07b1211f41b38c26a3a3ec3e9173\n[I 01:28:48.071 NotebookApp] 302 GET / (192.168.0.10) 0.66ms\n[I 01:28:48.124 NotebookApp] 302 GET /tree? (192.168.0.10) 4.00ms\n"
}

token信息:token=f94b3960fb6a1b50f06d07b1211f41b38c26a3a3ec3e9173

访问jupyter notebook并测试

输入上一节中的token并登录:

jupyter主页

编写tensorflow测试程序:

import tensorflow as tf

hello = tf.Variable('Hello TF')

sess = tf.Session()
init = tf.global_variables_initializer()

sess.run(init)
sess.run(hello)

运行代码:

jupyter编写代码

以上,开发模型创建完成。

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/23/jupyter-model-creation-for-kubernetes-api-microservice-development/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Kubernetes api微服务开发之jupyter模型创建
目标:完成模型开发功能中的Model创建,返回jupyter notebook访问信息 概述 人工智能服务中模型开发功能的实现主要参考金山云方案,提供一个tensorflow容器,……
<<上一篇
下一篇>>
文章目录
关闭
目 录