蘋果 發表於 2020-9-4 14:25:00

Kubernetes Python Client

<h1>一、概述</h1>
<p>Kubernetes官方维护的Python客户端client-python,&nbsp;地址:https://github.com/kubernetes-client/python</p>
<h2>安装模块</h2>
<div class="cnblogs_code">
<pre>pip3 <span style="color: rgba(0, 0, 255, 1)">install</span> kubernetes</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2>环境说明</h2>
<p>操作系统:centos 7.6</p>
<p>k8s版本:1.18.1</p>
<p>ip地址:192.168.31.74</p>
<p>主机名:k8s-master</p>
<p>&nbsp;</p>
<p>操作系统:centos 7.6</p>
<p>k8s版本:1.18.1</p>
<p>ip地址:192.168.31.71</p>
<p>主机名:k8s-node01</p>
<p>&nbsp;</p>
<h1>二、获取API cluster URL与token</h1>
<h2>获取Cluster URL地址</h2>
<p>登录到k8s-master节点,执行:</p>
<div class="cnblogs_code">
<pre># <span style="color: rgba(255, 0, 0, 1)">APISERVER=$(kubectl config view --minify | grep server | cut -f 2- -d ":" | tr -d " ")
</span># <span style="color: rgba(255, 0, 0, 1)">echo</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(255, 0, 0, 1)"> $APISERVER</span>
https:</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">192.168.31.74:6443</span></pre>
</div>
<p>下面python脚本要使用,我获取的是:https://192.168.31.74:6443</p>
<p>&nbsp;</p>
<h2>创建k8s admin-token</h2>
<p>编辑新文件</p>
<div class="cnblogs_code">
<pre># <span style="color: rgba(0, 0, 255, 1)">mkdir</span> -p /kube/<span style="color: rgba(0, 0, 0, 1)">role
# cd </span>/kube/<span style="color: rgba(0, 0, 0, 1)">role
# </span><span style="color: rgba(0, 0, 255, 1)">vi</span> admin-token.yaml</pre>
</div>
<p>内容如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io</span>/<span style="color: rgba(0, 0, 0, 1)">v1beta1
metadata:
name: admin
annotations:
    rbac.authorization.kubernetes.io</span>/autoupdate: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">true</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
roleRef:
kind: ClusterRole
name: cluster</span>-<span style="color: rgba(0, 0, 0, 1)">admin
apiGroup: rbac.authorization.k8s.io
subjects:
</span>-<span style="color: rgba(0, 0, 0, 1)"> kind: ServiceAccount
name: admin
namespace: kube</span>-<span style="color: rgba(0, 0, 0, 1)">system
</span>---<span style="color: rgba(0, 0, 0, 1)">
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: kube</span>-<span style="color: rgba(0, 0, 0, 1)">system
labels:
    kubernetes.io</span>/cluster-service: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">true</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    addonmanager.kubernetes.io</span>/mode: Reconcile</pre>
</div>
<p>执行yaml文件</p>
<div class="cnblogs_code">
<pre>kubectl create -f admin-token.yaml</pre>
</div>
<p>&nbsp;</p>
<h2>获取token值</h2>
<div class="cnblogs_code">
<pre># kubectl describe secret/$(kubectl get secret -nkube-system |<span style="color: rgba(0, 0, 255, 1)">grep</span> admin|<span style="color: rgba(0, 0, 255, 1)">awk</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">{print $1}</span><span style="color: rgba(128, 0, 0, 1)">'</span>) -nkube-system|<span style="color: rgba(0, 0, 255, 1)">grep</span> token:</pre>
</div>
<p>输出:</p>
<div class="cnblogs_code">
<pre>token:      eyJhbGciOiJSUzI1NiIsImtxxxx</pre>
</div>
<p>由于token过长,这里用xxx代替</p>
<p>最后将token与APISERVER地址返回内容复制到python client主机上, 供脚本使用.</p>
<p>&nbsp;</p>
<h1>三、在python client主机上编写脚本</h1>
<p>本文采用的python版本为3.7.3,运行在一台centos 7.6的服务器上面。</p>
<p>&nbsp;</p>
<h2>创建目录结构</h2>
<div class="cnblogs_code">
<pre># <span style="color: rgba(0, 0, 255, 1)">mkdir</span> -p /kube/<span style="color: rgba(0, 0, 0, 1)">auth
# cd </span>/kube/<span style="color: rgba(0, 0, 0, 1)">auth
# vim token.txt</span></pre>
</div>
<p>将刚才获取的Token字符串复制到该文件,比如:eyJhbGciOiJSUzI1NiIsImtxxxx</p>
<p>这里我们获取的token会引入到我们的脚本下, 作为bearer authorization的api key与远程k8s API建立认证连接.</p>
<p>&nbsp;</p>
<h2>编写python client脚本</h2>
<h3>获取的命名空间</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> !/usr/bin/python3</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> -*- coding: utf-8 -*-</span>
<span style="color: rgba(0, 0, 255, 1)">from</span> kubernetes.client <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> api_client
</span><span style="color: rgba(0, 0, 255, 1)">from</span> kubernetes.client.apis <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> core_v1_api
</span><span style="color: rgba(0, 0, 255, 1)">from</span> kubernetes <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> client,config


</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> KubernetesTools(object):
    </span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span><span style="color: rgba(0, 0, 0, 1)">(self):
      self.k8s_url </span>= <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">https://192.168.31.74:6443</span><span style="color: rgba(128, 0, 0, 1)">'</span>

    <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_token(self):
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
      获取token
      :return:
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
      with open(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">token.txt</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">r</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">) as file:
            Token </span>= file.read().strip(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\n</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Token

    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_api(self):
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
      获取API的CoreV1Api版本对象
      :return:
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
      configuration </span>=<span style="color: rgba(0, 0, 0, 1)"> client.Configuration()
      configuration.host </span>=<span style="color: rgba(0, 0, 0, 1)"> self.k8s_url
      configuration.verify_ssl </span>=<span style="color: rgba(0, 0, 0, 1)"> False
      configuration.api_key </span>= {<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">authorization</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Bearer </span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> self.get_token()}
      client1 </span>= api_client.ApiClient(configuration=<span style="color: rgba(0, 0, 0, 1)">configuration)
      api </span>=<span style="color: rgba(0, 0, 0, 1)"> core_v1_api.CoreV1Api(client1)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> api

    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_namespace_list(self):
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
      获取命名空间列表
      :return:
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
      api </span>=<span style="color: rgba(0, 0, 0, 1)"> self.get_api()
      namespace_list </span>=<span style="color: rgba(0, 0, 0, 1)"> []
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> ns <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> api.list_namespace().items:
            </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> print(ns.metadata.name)</span>
<span style="color: rgba(0, 0, 0, 1)">            namespace_list.append(ns.metadata.name)

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> namespace_list

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">:
    namespace_list </span>=<span style="color: rgba(0, 0, 0, 1)"> KubernetesTools().get_namespace_list()
    </span><span style="color: rgba(0, 0, 255, 1)">print</span>(namespace_list)</pre>
</div>
<p>执行输出:</p>
<div class="cnblogs_code">
<pre>[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">default</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">istio-system</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">kube-node-lease</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">kube-public</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">kube-system</span><span style="color: rgba(128, 0, 0, 1)">'</span>]</pre>
</div>
<p>&nbsp;</p>
<p>注意:输出时,会有一段警告信息</p>
<div class="cnblogs_code">
<pre>InsecureRequestWarning: Unverified HTTPS request <span style="color: rgba(0, 0, 255, 1)">is</span> being made to host <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">192.168.31.74</span><span style="color: rgba(128, 0, 0, 1)">'</span>. Adding certificate verification <span style="color: rgba(0, 0, 255, 1)">is</span> strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">ssl-warnings</span>
InsecureRequestWarning,</pre>
</div>
<p>这个是requests库提示警告,因为我是ip访问的,所以SSL验证会失败。但这个不影响。</p>
<p>&nbsp;</p>
<h2>获取所有services</h2>
<p>在上面的代码基础上,再加一个方法</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_services(self):
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
      获取所有services
      :return:
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
      api </span>=<span style="color: rgba(0, 0, 0, 1)"> self.get_api()
      ret </span>= api.list_service_for_all_namespaces(watch=<span style="color: rgba(0, 0, 0, 1)">False)
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> ret.items:
            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s \t%s \t%s \t%s \t%s \n</span><span style="color: rgba(128, 0, 0, 1)">"</span> %<span style="color: rgba(0, 0, 0, 1)"> (
                i.kind, i.metadata.namespace, i.metadata.name, i.spec.cluster_ip, i.spec.ports))</span></pre>
</div>
<p>单独执行这个方法,会输出很多信息。由于由于输出过多,这里只列出我运行的一个flaskapp</p>
<div class="cnblogs_code">
<pre>None   default   flaskapp-1   10.1.168.165   [{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">name</span><span style="color: rgba(128, 0, 0, 1)">'</span>: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">flaskapp-port</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">node_port</span><span style="color: rgba(128, 0, 0, 1)">'</span>: 30005<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">port</span><span style="color: rgba(128, 0, 0, 1)">'</span>: 5000<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">protocol</span><span style="color: rgba(128, 0, 0, 1)">'</span>: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">TCP</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">target_port</span><span style="color: rgba(128, 0, 0, 1)">'</span>: 5000}] </pre>
</div>
<p>可以看到很多信息,包括service名,svc地址,以及node_port暴露的端口</p>
<p>&nbsp;</p>
<h2>获取pod信息</h2>
<p>先登录k8s-master,查看目前运行的pod</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(255, 0, 0, 1)"> kubectl get pods</span>
<span style="color: rgba(0, 0, 0, 1)">NAME                        READY   STATUS    RESTARTS   AGE
flaskapp</span>-1-5d96dbf59b-lhmp8   1/1   Running   4          23d</pre>
</div>
<p>&nbsp;</p>
<p>在上面的代码基础上,再加一个方法</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_pod_info(self,namespaces,pod_name):
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
      查看pod信息
      :param namespaces: 命令空间,比如:default
      :param pod_name: pod完整名称,比如:flaskapp-1-5d96dbf59b-lhmp8
      :return:
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
      api </span>=<span style="color: rgba(0, 0, 0, 1)"> self.get_api()
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 示例参数</span>
      namespaces = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">default</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
      pod_name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">flaskapp-1-5d96dbf59b-lhmp8</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
      resp </span>= api.read_namespaced_pod(namespace=namespaces,name=<span style="color: rgba(0, 0, 0, 1)">pod_name)
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">详细信息</span>
      <span style="color: rgba(0, 0, 255, 1)">print</span>(resp)</pre>
</div>
<p>执行此方法,输出以下信息,由于输出过多,使用...省略</p>
<div class="cnblogs_code">
<pre>{<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">api_version</span><span style="color: rgba(128, 0, 0, 1)">'</span>: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">v1</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">kind</span><span style="color: rgba(128, 0, 0, 1)">'</span>: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Pod</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,
...</span></pre>
</div>
<p>它会输出一段很长的json,里面包含了此pod的详细信息</p>
<p>&nbsp;</p>
<h2>获取pod日志</h2>
<p>在上面的代码基础上,再加一个方法</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_pod_logs(self,namespaces,pod_name):
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
      查看pod日志
      :param namespaces: 命令空间,比如:default
      :param pod_name: pod完整名称,比如:flaskapp-1-5d96dbf59b-lhmp8
      :return:
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
      api </span>=<span style="color: rgba(0, 0, 0, 1)"> self.get_api()
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 示例参数</span>
      namespaces = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">default</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
      pod_name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">flaskapp-1-5d96dbf59b-lhmp8</span><span style="color: rgba(128, 0, 0, 1)">"</span>
      <span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
      pretty美化输出
      tail_lines=200输出最近200行
      </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
      log_content </span>= api.read_namespaced_pod_log(pod_name, namespaces, pretty=True, tail_lines=200<span style="color: rgba(0, 0, 0, 1)">)
      </span><span style="color: rgba(0, 0, 255, 1)">print</span>(log_content)</pre>
</div>
<p>执行此方法,输出以下信息:</p>
<div class="cnblogs_code">
<pre> * Serving Flask app <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">app</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> (lazy loading)
</span>*<span style="color: rgba(0, 0, 0, 1)"> Environment: production
   WARNING: Do </span><span style="color: rgba(0, 0, 255, 1)">not</span> use the development server <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> a production environment.
   Use a production WSGI server instead.
</span>*<span style="color: rgba(0, 0, 0, 1)"> Debug mode: on
</span>* Running on http://0.0.0.0:5000/ (Press CTRL+<span style="color: rgba(0, 0, 0, 1)">C to quit)
</span>*<span style="color: rgba(0, 0, 0, 1)"> Restarting with stat
</span>* Debugger <span style="color: rgba(0, 0, 255, 1)">is</span><span style="color: rgba(0, 0, 0, 1)"> active!
</span>* Debugger PIN: 182-124-947</pre>
</div>
<p>这个是flask运行之后,输出的日志信息。</p>
<p>&nbsp;</p>
<p>想了解其他更多参考,请参考链接:</p>
<p>https://blog.csdn.net/sinat_33431419/article/details/105223726</p>
<p>&nbsp;</p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>备注:token直接写入到txt是不安全的,可以考虑将token写入到redis中,然后用python调用即可。</strong></span></p>
<p>&nbsp;</p>
<p>本文参考链接:</p>
<p>https://blog.csdn.net/hypon2016/article/details/99439309</p><br><br>
来源:https://www.cnblogs.com/xiao987334176/p/13613622.html
頁: [1]
查看完整版本: Kubernetes Python Client