• python开发基础篇1——后端操作K8s API方式


    一、基本了解

    操作K8s资源api方式:

    K8s支持三种客户端身份认证:

    • HTTPS 证书认证:基于CA证书签名的数字证书认证(kubeconfig文件,默认路径~/.kube/config)
    • HTTP Token认证:通过一个Token来识别用户(ServiceAccount)
    • HTTP Base认证:用户名+密码的方式认证(1.19+已经弃用)

    1.1 操作k8s API

    1.安装Kubernetes客户端库。

    pip install kubernetes -i https://pypi.tuna.tsinghua.edu.cn/simple
    
    • 1

    在这里插入图片描述

    2.基于HTTPS证书认证(kubeconfig)操作k8s API。

    常用资源接口类实例化资源
    core_api = client.CoreV1Api()namespace,pod,service,pv,pvc
    apps_api = client.AppsV1Api()deployment,statefulset,daemonset
    networking_api = client.NetworkingV1beta1Api()ingress
    storage_api = client.StorageV1Api()storage_class
    from kubernetes import client,config
    import os
    print(os.getcwd())
    
    kubeconfig = os.path.join(os.getcwd(),'kubeconfig.yaml')  ##拿到k8s的~.kube/config文件内容。
    config.load_kube_config(kubeconfig)  ##指定kubeconfig配置文件(/root/.kube/config)
    apps_api = client.AppsV1Api()  # 资源接口类实例化,根据要操作的资源实例化不同的组。
    # print(apps_api.list_deployment_for_all_namespaces())
    
    for dp in apps_api.list_deployment_for_all_namespaces().items:
        # print(dp)  # 打印Deployment对象详细信息
        print(dp.metadata.labels)
        print(dp.metadata.name)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    3.基于HTTP Token认证(ServiceAccount)操作K8s API。

    #############################################################
    ##获取Token字符串:创建service account并绑定默认cluster-admin管理员集群角色。
    # 创建用户
    kubectl create serviceaccount dashboard-admin -n kube-system
    # 用户授权
    kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
    # 获取用户Token(1.24版本之前)
    kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
    # 获取用户Token(1.24版本之后)
    kubectl create token  dashboard-admin -n kube-system
    #############################################################
    from kubernetes import client,config
    import os
    configuration = client.Configuration()
    configuration.host = "https://192.168.161.120:6443"  # APISERVER地址
    ca_file = os.path.join(os.getcwd(),"ca.crt") # K8s集群CA证书(/etc/kubernetes/pki/ca.crt)
    configuration.ssl_ca_cert= ca_file
    configuration.verify_ssl = True
    ##启用证书验证。
    token = "eyJhbGciOiJSUzI1NiIsImtpZCI6InhBd1JkOFFocE1oX0VsRnlDcmFwQUN4ajQzblNta2FnVW1ITmk1VU12ZUEifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjk0MDQ3ODI5LCJpYXQiOjE2OTQwNDQyMjksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkYXNoYm9hcmQtYWRtaW4iLCJ1aWQiOiI2Zjg0ZTFjMC0wYTY0LTQ4NTQtYThlMy03MDZkOWYxZThkZGMifX0sIm5iZiI6MTY5NDA0NDIyOSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.GXwDKDNcCPjU23R-kYbs1Sl-73hG2p7RJShB0I8BU7cpifUhBaEKJjymx5IL_CYTl5LHRdlP0uo_sqXqrUBRBYrW5vctVq8MXLFNShSAKKLmxdIxxo4fHrWHMaRv8TU_wtKkATiXAO15q3n9YD7vN443FWK3sRuWpzh6Hvlr4dljnK_37YKiOd8eS8_dDC4BkeLo38EadnO39BwvC5lommz2LkCYMawunWkOxsI_eclPqXJ3ZkSCgEZUPD4_0CNv7D_X6S_gyMkdsCVxwFuL3EjI9ENh4GV2yKBVY69wuChlXB6vHGcYtiWzhTDdibv4l-5jIWhbwR_5CgaskKtmTQ"  #指定Token字符串,下面方式获取
    configuration.api_key = {"authorization": "Bearer " + token}   ##固定格式。
    client.Configuration.set_default(configuration)
    apps_api = client.AppsV1Api()
    
    for dp in apps_api.list_deployment_for_all_namespaces().items:
        # print(dp)  # 打印Deployment对象详细信息
        print(dp.metadata.labels)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    1.2 基本使用

    1.创建一个deployment资源,名为qingjun,3个副本数,使用nginx镜像。

    from kubernetes import client,config
    import os
    
    configuration = client.Configuration()
    configuration.host = "https://192.168.161.120:6443"  # APISERVER地址
    ca_file = os.path.join(os.getcwd(),"ca.crt") # K8s集群CA证书(/etc/kubernetes/pki/ca.crt)
    configuration.ssl_ca_cert= ca_file
    configuration.verify_ssl = True
    # 启用证书验证
    token = "eyJhbGciOiJSUzI1NiIsImtpZCI6InhBd1JkOFFocE1oX0VsRnlDcmFwQUN4ajQzblNta2FnVW1ITmk1VU12ZUEifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjk0MDQ3ODI5LCJpYXQiOjE2OTQwNDQyMjksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkYXNoYm9hcmQtYWRtaW4iLCJ1aWQiOiI2Zjg0ZTFjMC0wYTY0LTQ4NTQtYThlMy03MDZkOWYxZThkZGMifX0sIm5iZiI6MTY5NDA0NDIyOSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.GXwDKDNcCPjU23R-kYbs1Sl-73hG2p7RJShB0I8BU7cpifUhBaEKJjymx5IL_CYTl5LHRdlP0uo_sqXqrUBRBYrW5vctVq8MXLFNShSAKKLmxdIxxo4fHrWHMaRv8TU_wtKkATiXAO15q3n9YD7vN443FWK3sRuWpzh6Hvlr4dljnK_37YKiOd8eS8_dDC4BkeLo38EadnO39BwvC5lommz2LkCYMawunWkOxsI_eclPqXJ3ZkSCgEZUPD4_0CNv7D_X6S_gyMkdsCVxwFuL3EjI9ENh4GV2yKBVY69wuChlXB6vHGcYtiWzhTDdibv4l-5jIWhbwR_5CgaskKtmTQ"  #指定Token字符串,下面方式获取
    configuration.api_key = {"authorization": "Bearer " + token}   ##固定格式。
    client.Configuration.set_default(configuration)
    apps_api = client.AppsV1Api()
    
    
    
    namespace = "default"
    name = "qingjun"
    replicas = 3
    labels = {'a':'1', 'b':'2'}  # 不区分数据类型,都要加引号
    image = "nginx"
    body = client.V1Deployment(
                api_version="apps/v1",
                kind="Deployment",
                metadata=client.V1ObjectMeta(name=name),
                spec=client.V1DeploymentSpec(
                    replicas=replicas,
                    selector={'matchLabels': labels},
                    template=client.V1PodTemplateSpec(
                        metadata=client.V1ObjectMeta(labels=labels),
                        spec=client.V1PodSpec(
                            containers=[client.V1Container(
                                name="web",
                                image=image
                            )]
                        )
                    ),
                )
            )
    try:
        apps_api.create_namespaced_deployment(namespace=namespace, body=body)   ##创建命令。
    except Exception as e:
        status = getattr(e, "status")   ##获取状态码。
        if status == 400:  # 400 格式错误,409 资源存在,403 没权限。
            print(e)
            print("格式错误")
        elif status == 409:
        	print("deployment资源存在")
        elif status == 403:
            print("没权限")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    在这里插入图片描述
    2.创建一个service资源。

    core_api = client.CoreV1Api()
    namespace = "default"
    name = "qingjun"
    selector = {'a':'1', 'b':'2'}  # 不区分数据类型,都要加引号
    port = 80
    target_port = 80
    type = "NodePort"
    body = client.V1Service(
        api_version="v1",
        kind="Service",
        metadata=client.V1ObjectMeta(
            name=name
        ),
        spec=client.V1ServiceSpec(
            selector=selector,
            ports=[client.V1ServicePort(
                port=port,
                target_port=target_port
            )],
            type=type
        )
    )
    try:
        core_api.create_namespaced_service(namespace=namespace, body=body)
    except Exception as e:
        status = getattr(e, "status")
        if status == 400:  # 400 格式错误,409 资源存在,403 没权限。
            print(e)
            print("格式错误")
        elif status == 409:
        	print("service资源存在")
        elif status == 403:
            print("没权限")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    二、数据表格展示K8s常见资源

    大致思路:

    1. 使用Layui从接口获取JSON数据,动态渲染表格。
    2. Django准备接口,以JSON格式返回。
    3. 接口类实例化,遍历获取接口数据,取对应字段值,组成一个字典。
    • 资源增删改查采用不同HTTP方法:
    HTTP方法数据处理说明
    POST新增新增一个资源
    GET获取取得一个资源
    PUT更新更新一个资源
    DELETE删除删除一个资源

    2.1 Namespace

    1.查询资源。

    ##items返回一个对象,类LIST([{命名空间属性},{命名空间属性}] ),每个元素是一个类字典(命名空间属性),操作类字典
    for ns in core_api.list_namespace().items:
        name = ns.metadata.name   ##名称。
        labels = ns.metadata.labels    ##标签。
        create_time = ns.metadata.creation_timestamp  ##创建时间。
        namespace = {"name": name, "labels": labels, "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.删除资源。

    core_api.delete_namespace(name=name)
    
    • 1

    3.创建资源。

    body = client.V1Namespace(
        api_version="v1",
        kind="Namespace",
        metadata=client.V1ObjectMeta(
        name=ns_name
        )
    )
    core_api.create_namespace(body=body)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.使用数据表格显示资源。

          table.render({
            elem: '#test'
            ,url:'{% url 'namespace_api' %}'
            ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
            ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
              title: '提示'
              ,layEvent: 'LAYTABLE_TIPS'
              ,icon: 'layui-icon-tips'
            }]
            ,cols: [[
              {field: 'name', title: '名称', sort: true}
              ,{field: 'labels', title: '标签',templet: labelsFormat}
              ,{field: 'create_time', title: '创建时间'}
              ,{fixed: 'right', title:'操作', toolbar: '#barDemo', width:150}
            ]]
            ,page: true
          });
          // 标签格式化,是一个对象
          function labelsFormat(d){
              result = "";
              if (d.labels == null){
                  return "None"
              } else {
                  for (let key in d.labels) {
                      result += '' +
                          key + ':' + d.labels[key] +
                          '
    ' } return result } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    总结:其他资源功能开发与命名空间一样,拷贝后需要的修改位置:

    • 服务端:新添加一个url,函数视图
    • 服务端:函数视图GET方法里修改for遍历的K8s API接口、对应字段,DELETE方法里修改删除的K8s API接口
    • 前端:面包屑
    • 前端:table.renader修改连接的API接口,对应表头,删除接口及提示文字
    • 另外,除了Namespace、Node、PV,其他适配加命名空间

    2.2 Node

    1.查询。

    for node in core_api.list_node_with_http_info()[0].items:
        name = node.metadata.name   ##名称。
        labels = node.metadata.labels   ##标签。
        status = node.status.conditions[-1].status   ##准备就绪状态。
        scheduler = ("是" if node.spec.unschedulable is None else "否")   ##是否可调度。
        cpu = node.status.capacity['cpu']   ##cpui资源
        memory = node.status.capacity['memory']   ##内存资源
        kebelet_version = node.status.node_info.kubelet_version   ##kubelet版本
        cri_version = node.status.node_info.container_runtime_version   ##CRI版本
        create_time = node.metadata.creation_timestamp   ##创建时间
        node = {"name": name, "labels": labels, "status":status,
                     "scheduler":scheduler , "cpu":cpu, "memory":memory,
                     "kebelet_version":kebelet_version, "cri_version":cri_version,
                    "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.数据表格。

      table.render({
        elem: '#test'
        ,url:'{% url 'node_api' %}'
        ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
        ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
          title: '提示'
          ,layEvent: 'LAYTABLE_TIPS'
          ,icon: 'layui-icon-tips'
        }]
        ,cols: [[
          {field: 'name', title: '名称', sort: true}
          ,{field: 'labels', title: '标签',templet: labelsFormat}
          ,{field: 'status', title: '准备就绪'}
          ,{field: 'scheduler', title: '可调度'}
          ,{field: 'cpu', title: 'CPU'}
          ,{field: 'memory', title: '内存'}
          ,{field: 'kebelet_version', title: 'kubelet版本'}
          ,{field: 'cri_version', title: 'CRI版本'}
          ,{field: 'create_time', title: '创建时间'}
          ,{fixed: 'right', title:'操作', toolbar: '#barDemo', width:150}
        ]]
        ,page: true
      });
      // 标签格式化,是一个对象
          function labelsFormat(d){
              result = "";
              if (d.labels == null){
                  return "None"
              } else {
                  for (let key in d.labels) {
                      result += '' +
                          key + ':' + d.labels[key] +
                          '
    ' } return result } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2.3 PV

    • 数据存储,Pod->PVC->PV->外部存储,例如NFS、Ceph

    1.查询。

    字段:名称、容量、访问模式、回收策略、状态、卷申请(PVC)/命名空间、存储类、创建时间

                for pv in core_api.list_persistent_volume().items:
                    name = pv.metadata.name
                    capacity = pv.spec.capacity["storage"]
                    access_modes = pv.spec.access_modes
                    reclaim_policy = pv.spec.persistent_volume_reclaim_policy
                    status = pv.status.phase
                    if pv.spec.claim_ref is not None:
                        pvc_ns = pv.spec.claim_ref.namespace
                        pvc_name = pv.spec.claim_ref.name
                        pvc = "%s / %s" % (pvc_ns, pvc_name)
                    else:
                        pvc = "未绑定"
                    storage_class = pv.spec.storage_class_name
                    create_time = pv.metadata.creation_timestamp
                    pv = {"name": name, "capacity": capacity, "access_modes":access_modes,
                                 "reclaim_policy":reclaim_policy , "status":status, "pvc":pvc,
                                "storage_class":storage_class,"create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.创建。

            name = request.POST.get("name", None)
            capacity = request.POST.get("capacity", None)
            access_mode = request.POST.get("access_mode", None)
            storage_type = request.POST.get("storage_type", None)
            server_ip = request.POST.get("server_ip", None)
            mount_path = request.POST.get("mount_path", None)
    
    		body = client.V1PersistentVolume(
                api_version="v1",
                kind="PersistentVolume",
                metadata=client.V1ObjectMeta(name=name),
                spec=client.V1PersistentVolumeSpec(
                    capacity={'storage':capacity},
                    access_modes=[access_mode],
                    nfs=client.V1NFSVolumeSource(
                        server=server_ip,
                        path="/ifs/kubernetes/%s" %mount_path
                    )
                )
            )
            core_api.create_persistent_volume(body=body)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.删除。

    core_api.delete_persistent_volume(name=name)
    
    • 1

    4.数据表格。

    table.render({
      elem: '#test'
      ,url:'{% url 'pv_api' %}'
      ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
      ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
        title: '提示'
        ,layEvent: 'LAYTABLE_TIPS'
        ,icon: 'layui-icon-tips'
      }]
      ,cols: [[
        {field: 'name', title: '名称', sort: true}
        ,{field: 'capacity', title: '容量'}
        ,{field: 'access_modes', title: '访问模式'}
        ,{field: 'reclaim_policy', title: '回收策略'}
        ,{field: 'status', title: '状态'}
        ,{field: 'pvc', title: 'PVC(命名空间/名称)'}
        ,{field: 'storage_class', title: '存储类'}
        ,{field: 'create_time', title: '创建时间'}
        ,{fixed: 'right', title:'操作', toolbar: '#barDemo', width:150}
      ]]
      ,page: true
      ,id: 'pvtb'
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.4 Deployment

    1.查询。

    字段:名称、命名空间、预期副本数、可用副本数、Pod标签选择器、镜像/状态、创建时间

    for dp in apps_api.list_namespaced_deployment(namespace).items:
        name = dp.metadata.name
        namespace = dp.metadata.namespace
        replicas = dp.spec.replicas
        available_replicas = ( 0 if dp.status.available_replicas is None else dp.status.available_replicas)
        labels = dp.metadata.labels
        selector = dp.spec.selector.match_labels
        containers = {}
        for c in dp.spec.template.spec.containers:
            containers[c.name] = c.image
        create_time = dp.metadata.creation_timestamp
        dp = {"name": name, "namespace": namespace, "replicas":replicas,
                     "available_replicas":available_replicas , "labels":labels, "selector":selector,
                     "containers":containers, "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.创建。

            name = request.POST.get("name",None)
            namespace = request.POST.get("namespace",None)
            image = request.POST.get("image",None)
            replicas = int(request.POST.get("replicas",None))
            # 处理标签
            labels = {}
            try:
                for l in request.POST.get("labels",None).split(","):
                    k = l.split("=")[0]
                    v = l.split("=")[1]
                    labels[k] = v
            except Exception as e:
                res = {"code": 1, "msg": "标签格式错误!"}
                return JsonResponse(res)
            resources = request.POST.get("resources",None)
            health_liveness = request.POST.get("health[liveness]",None)  # {'health[liveness]': ['on'], 'health[readiness]': ['on']}
            health_readiness = request.POST.get("health[readiness]",None)
    
            if resources == "1c2g":
                resources = client.V1ResourceRequirements(limits={"cpu":"1","memory":"1Gi"},
                                                          requests={"cpu":"0.9","memory":"0.9Gi"})
            elif resources == "2c4g":
                resources = client.V1ResourceRequirements(limits={"cpu": "2", "memory": "4Gi"},
                                                          requests={"cpu": "1.9", "memory": "3.9Gi"})
            elif resources == "4c8g":
                resources = client.V1ResourceRequirements(limits={"cpu": "4", "memory": "8Gi"},
                                                          requests={"cpu": "3.9", "memory": "7.9Gi"})
            else:
                resources = client.V1ResourceRequirements(limits={"cpu":"500m","memory":"1Gi"},
                                                          requests={"cpu":"450m","memory":"900Mi"})
            liveness_probe = ""
            if health_liveness == "on":
                liveness_probe = client.V1Probe(http_get="/",timeout_seconds=30,initial_delay_seconds=30)
            readiness_probe = ""
            if health_readiness == "on":
                readiness_probe = client.V1Probe(http_get="/",timeout_seconds=30,initial_delay_seconds=30)
    
            for dp in apps_api.list_namespaced_deployment(namespace=namespace).items:
                if name == dp.metadata.name:
                    res = {"code": 1, "msg": "Deployment已经存在!"}
                    return JsonResponse(res)
    
            body = client.V1Deployment(
                api_version="apps/v1",
                kind="Deployment",
                metadata=client.V1ObjectMeta(name=name),
                spec=client.V1DeploymentSpec(
                    replicas=replicas,
                    selector={'matchLabels': labels},
                    template=client.V1PodTemplateSpec(
                        metadata=client.V1ObjectMeta(labels=labels),
                        spec=client.V1PodSpec(
                            containers=[client.V1Container(   # https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Container.md
                                name="web",
                                image=image,
                                env=[{"name": "TEST", "value": "123"}, {"name": "DEV", "value": "456"}],
                                ports=[client.V1ContainerPort(container_port=80)],
                                # liveness_probe=liveness_probe, 
                                # readiness_probe=readiness_probe,
                                resources=resources,
                            )]
                        )
                    ),
                )
            )
    
       apps_api.create_namespaced_deployment(namespace=namespace, body=body)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    3.删除。

    apps_api.delete_namespaced_deployment(namespace=namespace, name=name)
    
    • 1

    4.数据表格。

          table.render({
            elem: '#test'
            ,url:'{% url 'deployment_api' %}?namespace=' + namespace
            ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
            ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
              title: '提示'
              ,layEvent: 'LAYTABLE_TIPS'
              ,icon: 'layui-icon-tips'
            }]
            ,cols: [[
              {field: 'name', title: '名称', sort: true}
              ,{field: 'namespace', title: '命名空间'}
              ,{field: 'replicas', title: '预期副本数'}
              ,{field: 'available_replicas', title: '可用副本数'}
              ,{field: 'labels', title: '标签',templet: labelsFormat}
              ,{field: 'selector', title: 'Pod标签选择器',templet: selectorFormat}
              ,{field: 'containers', title: '容器', templet: containersFormat}
              ,{field: 'create_time', title: '创建时间'}
              ,{fixed: 'right', title:'操作', toolbar: '#barDemo', width:150}
            ]]
            ,page: true
              ,id: 'dptb'
          });
          // 标签格式化,是一个对象
          function labelsFormat(d){
              result = "";
              if(d.labels == null){
                  return "None"
              } else {
                  for (let key in d.labels) {
                      result += '' +
                          key + ':' + d.labels[key] +
                          '
    ' } return result } } function selectorFormat(d){ result = ""; for(let key in d.selector) { result += '' + key + ':' + d.selector[key] + '
    ' } return result } function containersFormat(d) { result = ""; for(let key in d.containers) { result += key + '=' + d.containers[key] + '
    ' } return result }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    2.5 DaemonSet

    1.查询。

    字段:名称、命名空间、预期节点数、可用节点数、Pod标签选择器、镜像、创建时间

    for ds in apps_api.list_namespaced_daemon_set(namespace).items:
        name = ds.metadata.name
        namespace = ds.metadata.namespace
        desired_number = ds.status.desired_number_scheduled
        available_number = ds.status.number_available
        labels = ds.metadata.labels
        selector = ds.spec.selector.match_labels
    	containers = {}
    	for c in ds.spec.template.spec.containers:
    		containers[c.name] = c.image    
    	create_time = ds.metadata.creation_timestamp
     
        ds = {"name": name, "namespace": namespace, "labels": labels, "desired_number": desired_number,
                "available_number": available_number,
                "selector": selector, "containers": containers, "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.创建。

            name = request.POST.get("name",None)
            namespace = request.POST.get("namespace",None)
            image = request.POST.get("image",None)
            # 处理标签
            labels = {}
            try:
                for l in request.POST.get("labels",None).split(","):
                    k = l.split("=")[0]
                    v = l.split("=")[1]
                    labels[k] = v
            except Exception as e:
                res = {"code": 1, "msg": "标签格式错误!"}
                return JsonResponse(res)
            resources = request.POST.get("resources",None)
            health_liveness = request.POST.get("health[liveness]",None)  # {'health[liveness]': ['on'], 'health[readiness]': ['on']}
            health_readiness = request.POST.get("health[readiness]",None)
        
            if resources == "1c2g":
                resources = client.V1ResourceRequirements(limits={"cpu":"1","memory":"1Gi"},
                                                          requests={"cpu":"0.9","memory":"0.9Gi"})
            elif resources == "2c4g":
                resources = client.V1ResourceRequirements(limits={"cpu": "2", "memory": "4Gi"},
                                                          requests={"cpu": "1.9", "memory": "3.9Gi"})
            elif resources == "4c8g":
                resources = client.V1ResourceRequirements(limits={"cpu": "4", "memory": "8Gi"},
                                                          requests={"cpu": "3.9", "memory": "7.9Gi"})
            else:
                resources = client.V1ResourceRequirements(limits={"cpu":"500m","memory":"1Gi"},
                                                          requests={"cpu":"450m","memory":"900Mi"})
            liveness_probe = ""
            if health_liveness == "on":
                liveness_probe = client.V1Probe(http_get="/",timeout_seconds=30,initial_delay_seconds=30)
            readiness_probe = ""
            if health_readiness == "on":
                readiness_probe = client.V1Probe(http_get="/",timeout_seconds=30,initial_delay_seconds=30)
        
            for dp in apps_api.list_namespaced_daemon_set(namespace=namespace).items:
                if name == dp.metadata.name:
                    res = {"code": 1, "msg": "DaemonSet已经存在!"}
                    return JsonResponse(res)
        
            body = client.V1DaemonSet(
                api_version="apps/v1",
                kind="DaemonSet",
                metadata=client.V1ObjectMeta(name=name),
                spec=client.V1DeploymentSpec(
                    selector={'matchLabels': labels},
                    template=client.V1PodTemplateSpec(
                        metadata=client.V1ObjectMeta(labels=labels),
                        spec=client.V1PodSpec(
                            containers=[client.V1Container(   # https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Container.md
                                name="web",
                                image=image,
                                env=[{"name": "TEST", "value": "123"}, {"name": "DEV", "value": "456"}],
                                ports=[client.V1ContainerPort(container_port=80)],
                                # liveness_probe=liveness_probe, 
                                # readiness_probe=readiness_probe,
                                resources=resources,
                            )]
                        )
                    ),
                )
            )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    3.删除。

    apps_api.delete_namespaced_daemon_set(namespace=namespace, name=name)
    
    • 1

    4.数据表格。

          table.render({
            elem: '#test'
            ,url:'{% url 'daemonset_api' %}?namespace=' + namespace
            ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
            ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
              title: '提示'
              ,layEvent: 'LAYTABLE_TIPS'
              ,icon: 'layui-icon-tips'
            }]
            ,cols: [[
              {field: 'name', title: '名称', sort: true}
              ,{field: 'namespace', title: '命名空间',sort: true}
              ,{field: 'desired_number', title: '预期节点数',width: 100}
              ,{field: 'available_number', title: '可用节点数',width: 100}
              ,{field: 'labels', title: '标签',templet: labelsFormat}
              ,{field: 'selector', title: 'Pod 标签选择器',templet: selecotrFormat}
              ,{field: 'containers', title: '容器', templet: containersFormat}
              ,{field: 'create_time', title: '创建时间',width: 200}
              ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 150}
            ]]
            ,page: true
              ,id: 'dstb'
          });
          // 标签格式化,是一个对象
          function labelsFormat(d){
              result = "";
              if(d.labels == null){
                  return "None"
              } else {
                  for (let key in d.labels) {
                      result += '' +
                          key + ':' + d.labels[key] +
                          '
    ' } return result } } function selecotrFormat(d){ result = ""; for(let key in d.selector) { result += '' + key + ':' + d.selector[key] + '
    ' } return result } function containersFormat(d) { result = ""; for(let key in d.containers) { result += key + '=' + d.containers[key] + '
    ' } return result }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    2.6 StatefulSet

    1.查询。

    字段:名称、命名空间、Service名称、预期副本数、可用副本数、Pod标签选择器、镜像、创建时间

    for sts in apps_api.list_namespaced_stateful_set(namespace).items:
        name = sts.metadata.name
        namespace = sts.metadata.namespace
        labels = sts.metadata.labels
        selector = sts.spec.selector.match_labels
        replicas = sts.spec.replicas
        ready_replicas = ("0" if sts.status.ready_replicas is None else sts.status.ready_replicas)
        #current_replicas = sts.status.current_replicas
        service_name = sts.spec.service_name
    	containers = {}
    	for c in sts.spec.template.spec.containers:
    		containers[c.name] = c.image    
        create_time = sts.metadata.creation_timestamp
     
        ds = {"name": name, "namespace": namespace, "labels": labels, "replicas": replicas,
                "ready_replicas": ready_replicas, "service_name": service_name,
                "selector": selector, "containers": containers, "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.删除。

    apps_api.delete_namespaced_stateful_set(namespace=namespace, name=name)
    
    • 1

    3.数据表格。

          table.render({
            elem: '#test'
            ,url:'{% url 'statefulset_api' %}?namespace=' + namespace
            ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
            ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
              title: '提示'
              ,layEvent: 'LAYTABLE_TIPS'
              ,icon: 'layui-icon-tips'
            }]
            ,cols: [[
              {field: 'name', title: '名称', sort: true}
              ,{field: 'namespace', title: '命名空间',sort: true}
              ,{field: 'service_name', title: 'Service名称'}
              ,{field: 'replicas', title: '预期副本数',width: 100}
              ,{field: 'ready_replicas', title: '可用副本数',width: 100}
              ,{field: 'labels', title: '标签',templet: labelsFormat}
              ,{field: 'selector', title: 'Pod 标签选择器',templet: selecotrFormat}
              ,{field: 'containers', title: '容器', templet: containersFormat}
              ,{field: 'create_time', title: '创建时间',width: 200}
              ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 150}
            ]]
            ,page: true
              ,id: 'ststb'
          });
          // 标签格式化,是一个对象
          function labelsFormat(d){
              result = "";
              if(d.labels == null){
                  return "None"
              } else {
                  for (let key in d.labels) {
                      result += '' +
                          key + ':' + d.labels[key] +
                          '
    ' } return result } } function selecotrFormat(d){ result = ""; for(let key in d.selector) { result += '' + key + ':' + d.selector[key] + '
    ' } return result } function containersFormat(d) { result = ""; for(let key in d.containers) { result += key + '=' + d.containers[key] + '
    ' } return result }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    2.7 Pod

    1.查询。

    字段:名称、命名空间、IP地址、标签、容器组、状态、创建时间

    for po in core_api.list_namespaced_pod(namespace).items:
        name = po.metadata.name
        namespace = po.metadata.namespace
        labels = po.metadata.labels
        pod_ip = po.status.pod_ip
    
        containers = []  # [{},{},{}]
        status = "None"
        # 只为None说明Pod没有创建(不能调度或者正在下载镜像)
        if po.status.container_statuses is None:
            status = po.status.conditions[-1].reason
        else:
            for c in po.status.container_statuses:
                c_name = c.name
                c_image = c.image
    
                # 获取重启次数
                restart_count = c.restart_count
    
                # 获取容器状态
                c_status = "None"
                if c.ready is True:
                    c_status = "Running"
                elif c.ready is False:
                    if c.state.waiting is not None:
                        c_status = c.state.waiting.reason
                    elif c.state.terminated is not None:
                        c_status = c.state.terminated.reason
                    elif c.state.last_state.terminated is not None:
                        c_status = c.last_state.terminated.reason
    
                c = {'c_name': c_name,'c_image':c_image ,'restart_count': restart_count, 'c_status': c_status}
                containers.append(c)
    
        create_time = po.metadata.creation_timestamp
    
        po = {"name": name, "namespace": namespace, "pod_ip": pod_ip,
                "labels": labels, "containers": containers, "status": status,
                "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    2.删除。

    core_api.delete_namespaced_pod(namespace=namespace, name=name)
    
    • 1

    3.数据表格。

    table.render({
      elem: '#test'
      ,url:'{% url 'pod_api' %}?namespace=' + namespace
      ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
      ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
        title: '提示'
        ,layEvent: 'LAYTABLE_TIPS'
        ,icon: 'layui-icon-tips'
      }]
      ,cols: [[
        {field: 'name', title: '名称', sort: true}
        ,{field: 'namespace', title: '命名空间',sort: true}
        ,{field: 'pod_ip', title: 'IP地址'}
        ,{field: 'labels', title: '标签', templet: labelsFormat}
        ,{field: 'containers', title: '容器组', templet: containersFormat}
        ,{field: 'status', title: '状态',sort: true, templet: statusFormat}
        ,{field: 'create_time', title: '创建时间'}
        ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 250}
      ]]
      ,page: true
      ,id: 'potb'
    });
    // 标签格式化,是一个对象
    function labelsFormat(d){
        result = "";
        if(d.labels == null){
            return "None"
        } else {
            for (let key in d.labels) {
                result += '' +
                    key + ':' + d.labels[key] +
                    '
    ' } return result } } function containersFormat(d) { result = ""; if (d.containers) { for(let key in d.containers) { data = d.containers[key]; result += key + ':' + data.c_name + '=' + data.c_image + '
    ' + '重启次数:' + data.restart_count + '
    ' + '状态:' + data.c_status + '
    ' } return result } else { return "None" } } // 如果status为None,使用容器状态显示 function statusFormat(d){ result = ""; if(d.status == "None"){ for(let key in d.containers) { result += d.containers[key].c_status + '
    ' } return result } else { return d.status } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    2.8 Service

    1.查询。

    字段:名称、命名空间、类型、集群IP、端口信息、Pod标签选择器、后端Pod、创建时间

    for svc in core_api.list_namespaced_service(namespace=namespace).items:
        name = svc.metadata.name
        namespace = svc.metadata.namespace
        labels = svc.metadata.labels
        type = svc.spec.type
        cluster_ip = svc.spec.cluster_ip
        ports = []
        for p in svc.spec.ports:  # 不是序列,不能直接返回
            port_name = p.name
            port = p.port
            target_port = p.target_port
            protocol = p.protocol
            node_port = ""
            if type == "NodePort":
                node_port = " 
    NodePort: %s" % p.node_port port = {'port_name': port_name, 'port': port, 'protocol': protocol, 'target_port':target_port, 'node_port': node_port} ports.append(port) selector = svc.spec.selector create_time = svc.metadata.creation_timestamp # 确认是否关联Pod endpoint = "" for ep in core_api.list_namespaced_endpoints(namespace=namespace).items: if ep.metadata.name == name and ep.subsets is None: endpoint = "未关联" else: endpoint = "已关联" svc = {"name": name, "namespace": namespace, "type": type, "cluster_ip": cluster_ip, "ports": ports, "labels": labels, "selector": selector, "endpoint": endpoint, "create_time": create_time}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    2.创建。

            name = request.POST.get("name",None)
            namespace = request.POST.get("namespace",None)
            port = int(request.POST.get("port",None))
            target_port = int(request.POST.get("target-port",None))
            labels = {}
            try:
                for l in request.POST.get("labels",None).split(","):
                    k = l.split("=")[0]
                    v = l.split("=")[1]
                    labels[k] = v
            except Exception as e:
                res = {"code": 1, "msg": "标签格式错误!"}
                return JsonResponse(res)
            type = request.POST.get("type","")
    
            body = client.V1Service(
                api_version="v1",
                kind="Service",
                metadata=client.V1ObjectMeta(
                    name=name
                ),
                spec=client.V1ServiceSpec(
                    selector=labels,
                    ports=[client.V1ServicePort(
                        port=port,
                        target_port=target_port,
    
                    )],
                    type=type
                )
            )
           core_api.create_namespaced_service(namespace=namespace, body=body)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.删除。

    core_api.delete_namespaced_service(namespace=namespace, name=name)
    
    • 1

    4.数据表格。

    table.render({
      elem: '#test'
      ,url:'{% url 'service_api' %}?namespace=' + namespace
      ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
      ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
        title: '提示'
        ,layEvent: 'LAYTABLE_TIPS'
        ,icon: 'layui-icon-tips'
      }]
      ,cols: [[
          {field: 'name', title: '名称', sort: true, width: 150}
          ,{field: 'namespace', title: '命名空间',width: 150, sort: true}
          ,{field: 'type', title: '类型',width: 120, sort: true}
          ,{field: 'cluster_ip', title: '集群IP',width: 100}
          ,{field: 'ports', title: '端口信息',templet: portsFormat}
          ,{field: 'labels', title: '标签', templet: labelsFormat}
          ,{field: 'selector', title: 'Pod 标签选择器', templet: selecotrFormat}
          ,{field: 'endpoint', title: '后端 Pod'}
          ,{field: 'create_time', title: '创建时间'}
        ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 150}
      ]]
      ,page: true
        ,id: 'svctb'
    });
    // 标签格式化,是一个对象
    function labelsFormat(d){
        result = "";
        if(d.labels == null){
            return "None"
        } else {
            for (let key in d.labels) {
                result += '' +
                    key + ':' + d.labels[key] +
                    '
    ' } return result } } function selecotrFormat(d){ result = ""; for(let key in d.selector) { result += '' + key + ':' + d.selector[key] + '
    ' } return result } function portsFormat(d) { result = ""; for(let key in d.ports) { data = d.ports[key]; result += '名称: ' + data.port_name + '
    ' + '端口: ' + data.port + '
    ' + '协议: ' + data.protocol + '
    ' + '容器端口: ' + data.target_port + '
    ' } return result }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    2.9 Ingress

    1.查询。

    字段:名称、命名空间、HTTP、HTTPS、关联Service、创建时间

    for ing in networking_api.list_namespaced_ingress(namespace=namespace).items:
        name = ing.metadata.name
        namespace = ing.metadata.namespace
        labels = ing.metadata.labels
        service = "None"
        http_hosts = "None"
        for h in ing.spec.rules:
            host = h.host
            path = ("/" if h.http.paths[0].path is None else h.http.paths[0].path)
            service_name = h.http.paths[0].backend.service_name
            service_port = h.http.paths[0].backend.service_port
            http_hosts = {'host': host, 'path': path, 'service_name': service_name, 'service_port': service_port}
    
        https_hosts = "None"
        if ing.spec.tls is None:
            https_hosts = ing.spec.tls
        else:
            for tls in ing.spec.tls:
                host = tls.hosts[0]
                secret_name = tls.secret_name
                https_hosts = {'host': host, 'secret_name': secret_name}
    
        create_time = ing.metadata.creation_timestamp
    
        ing = {"name": name, "namespace": namespace,"labels": labels ,"http_hosts": http_hosts,
                "https_hosts": https_hosts, "service": service, "create_time": create_time
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    2.创建。

            name = request.POST.get("name",None)
            namespace = request.POST.get("namespace",None)
            host = request.POST.get("host",None)
            path = request.POST.get("path","/")
            svc_name = request.POST.get("svc_name",None)
            svc_port = int(request.POST.get("svc_port",None))
    
            body = client.NetworkingV1beta1Ingress(
                api_version="networking.k8s.io/v1beta1",
                kind="Ingress",
                metadata=client.V1ObjectMeta(name=name, annotations={
                    "nginx.ingress.kubernetes.io/rewrite-target": "/"
                }),
                spec=client.NetworkingV1beta1IngressSpec(
                    rules=[client.NetworkingV1beta1IngressRule(
                        host=host,
                        http=client.NetworkingV1beta1HTTPIngressRuleValue(
                            paths=[client.NetworkingV1beta1HTTPIngressPath(
                                path=path,
                                backend=client.NetworkingV1beta1IngressBackend(
                                    service_port=svc_port,
                                    service_name=svc_name)
    
                            )]
                        )
                    )
                    ]
                )
            )
        networking_api.create_namespaced_ingress(namespace=namespace, body=body)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3.删除。

    networking_api.delete_namespaced_ingress(namespace=namespace, name=name)
    
    • 1

    4.数据表格。

    table.render({
      elem: '#test'
      ,url:'{% url 'ingress_api' %}?namespace=' + namespace
      ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
      ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
        title: '提示'
        ,layEvent: 'LAYTABLE_TIPS'
        ,icon: 'layui-icon-tips'
      }]
      ,cols: [[
        {field: 'name', title: '名称', sort: true, width: 300}
        ,{field: 'namespace', title: '命名空间',width: 200, sort: true}
        ,{field: 'http_hosts', title: 'HTTP',templet: httpFormat}
        ,{field: 'https_hosts', title: 'HTTPS',templet: httpsFormat}
        ,{field: 'service', title: '关联 Service', templet: serviceFormat}
        ,{field: 'create_time', title: '创建时间',width: 200}
        ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 150}
      ]]
      ,page: true
        ,id: 'ingtb'
    });
    // 标签格式化,是一个对象
    function httpFormat(d){
        return "域名: " + d.http_hosts.host + '
    ' + "路径: " + d.http_hosts.path + '
    ' } function httpsFormat(d){ if(d.https_hosts != null){ return "域名: " + d.https_hosts.host + '
    ' + "证书Secret名称: " + d.https_hosts.secret_name + '
    '; } else { return "None" } } function serviceFormat(d) { return "名称: " + d.http_hosts.service_name + '
    ' + "端口: " + d.http_hosts.service_port + '
    '; }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2.10 PVC

    1.查询。

    字段:名称、命名空间、状态、卷名称、容量、访问模式、存储类、创建时间

    for pvc in core_api.list_namespaced_persistent_volume_claim(namespace=namespace).items:
        name = pvc.metadata.name
        namespace = pvc.metadata.namespace
        labels = pvc.metadata.labels
        storage_class_name = pvc.spec.storage_class_name
        access_modes = pvc.spec.access_modes
        capacity = (pvc.status.capacity if pvc.status.capacity is None else pvc.status.capacity["storage"])
        volume_name = pvc.spec.volume_name
        status = pvc.status.phase
        create_time = pvc.metadata.creation_timestamp
    
        pvc = {"name": name, "namespace": namespace, "lables": labels,
                "storage_class_name": storage_class_name, "access_modes": access_modes, "capacity": capacity,
                "volume_name": volume_name, "status": status, "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.创建。

            name = request.POST.get("name", None)
            namespace = request.POST.get("namespace", None)
            storage_class = request.POST.get("storage_class", None)
            access_mode = request.POST.get("access_mode", None)
            capacity = request.POST.get("capacity", None)
            body = client.V1PersistentVolumeClaim(
                    api_version="v1",
                    kind="PersistentVolumeClaim",
                    metadata=client.V1ObjectMeta(name=name,namespace=namespace),
                    spec=client.V1PersistentVolumeClaimSpec(
                        storage_class_name=storage_class,   # 使用存储类创建PV,如果不用可去掉
                        access_modes=[access_mode],
                        resources=client.V1ResourceRequirements(
                          requests={"storage" : capacity}
                        )
                    )
                )
             core_api.create_namespaced_persistent_volume_claim(namespace=namespace, body=body)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.删除。

    core_api.delete_namespaced_persistent_volume_claim(namespace=namespace, name=name)
    
    • 1

    3.数据表格。

    layui.use('table', function(){
      var table = layui.table;
      var $ = layui.jquery;
    
      table.render({
        elem: '#test'
        ,url:'{% url 'pvc_api' %}?namespace=' + namespace
        ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
        ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
          title: '提示'
          ,layEvent: 'LAYTABLE_TIPS'
          ,icon: 'layui-icon-tips'
        }]
        ,cols: [[
          {field: 'name', title: '名称', sort: true}
          ,{field: 'namespace', title: '命名空间',sort: true}
          ,{field: 'labels', title: '标签',templet: labelsFormat}
          ,{field: 'status', title: '状态',width: 130}
          ,{field: 'volume_name', title: '卷名称'}
          ,{field: 'capacity', title: '容量',width: 130}
          ,{field: 'access_modes', title: '访问模式'}
          ,{field: 'storage_class_name', title: '存储类'}
          ,{field: 'create_time', title: '创建时间',width: 200}
          ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 150}
        ]]
        ,page: true
          ,id: 'pvctb'
      });
      // 标签格式化,是一个对象
      function labelsFormat(d){
          result = "";
          if(d.labels == null){
              return "None"
          } else {
              for (let key in d.labels) {
                  result += '' +
                      key + ':' + d.labels[key] +
                      '
    ' } return result } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    2.11 ConfigMap

    1.查询.

    字段:名称、命名空间、数据数量、创建时间

    for cm in core_api.list_namespaced_config_map(namespace=namespace).items:
        name = cm.metadata.name
        namespace = cm.metadata.namespace
        data_length = ("0" if cm.data is None else len(cm.data))
        create_time = cm.metadata.creation_timestamp
    
        cm = {"name": name, "namespace": namespace, "data_length": data_length, "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.删除。

    core_api.delete_namespaced_config_map(name=name,namespace=namespace)
    
    • 1

    3.数据表格。

    table.render({
      elem: '#test'
      ,url:'{% url 'configmap_api' %}?namespace=' + namespace
      ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
      ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
        title: '提示'
        ,layEvent: 'LAYTABLE_TIPS'
        ,icon: 'layui-icon-tips'
      }]
      ,cols: [[
        {field: 'name', title: '名称', sort: true}
        ,{field: 'namespace', title: '命名空间',sort: true}
        ,{field: 'data_length', title: '数据数量'}
        ,{field: 'create_time', title: '创建时间'}
        ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 150}
      ]]
      ,page: true
        ,id: 'cmtb'
    });
    // 标签格式化,是一个对象
    function labelsFormat(d){
        result = "";
        if(d.labels == null){
            return "None"
        } else {
            for (let key in d.labels) {
                result += '' +
                    key + ':' + d.labels[key] +
                    '
    ' } return result } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    2.12 Secret

    1.查询.

    字段:名称、命名空间、数据数量、创建时间

    for secret in core_api.list_namespaced_secret(namespace=namespace).items:
        name = secret.metadata.name
        namespace = secret.metadata.namespace
        data_length = ("空" if secret.data is None else len(secret.data))
        create_time = secret.metadata.creation_timestamp
    
        se = {"name": name, "namespace": namespace, "data_length": data_length, "create_time": create_time}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.删除。

    core_api.delete_namespaced_secret(namespace=namespace, name=name)
    
    • 1

    3.数据表格.

    table.render({
      elem: '#test'
      ,url:'{% url 'secret_api' %}?namespace=' + namespace
      ,toolbar: '#toolbarDemo' //开启头部工具栏,并为其绑定左侧模板
      ,defaultToolbar: ['filter', 'exports', 'print', { //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可
        title: '提示'
        ,layEvent: 'LAYTABLE_TIPS'
        ,icon: 'layui-icon-tips'
      }]
      ,cols: [[
        {field: 'name', title: '名称', sort: true}
        ,{field: 'namespace', title: '命名空间'}
        ,{field: 'data_length', title: '数据数量'}
        ,{field: 'create_time', title: '创建时间'}
        ,{fixed: 'right', title:'操作', toolbar: '#barDemo',width: 150}
      ]]
      ,page: true
        ,id: 'secrettb'
    });
    // 标签格式化,是一个对象
    function labelsFormat(d){
        result = "";
        if(d.labels == null){
            return "None"
        } else {
            for (let key in d.labels) {
                result += '' +
                    key + ':' + d.labels[key] +
                    '
    ' } return result } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    2.13 优化

    1.每个k8s资源都有一个时间,默认是UTC,进行格式化中国时区

    def dt_format(dt):
        current_datetime = dt + timedelta(hours=8)
        dt = date.strftime(current_datetime, '%Y-%m-%d %H:%M:%S')
        return dt
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    基于VR元宇宙技术搭建林业生态模拟仿真教学系统
    音频——解析 PCM 数据
    【ESP32调试-快速入门】
    消息队列-RabbitMQ
    电脑重装系统后如何把网站设为首页
    常见的框架漏洞
    安卓毕业设计选题基于Uniapp实现的鲜花购物商城
    实现领域驱动设计 - 使用ABP框架 - 存储库
    解决module ‘os‘ has no attribute ‘add_dll_directory‘
    大学计算机毕业设计真的很难完成吗?(资源持续更新~~)
  • 原文地址:https://blog.csdn.net/yi_qingjun/article/details/132712826