基于Kubernetes Python Client的资源操作模块
以下是一个基于 Kubernetes Python Client 的可复用模块,支持对任意 Kubernetes 资源(内置资源与 CRD)进行增删改查操作。模块使用 dynamic client 实现,自动处理 API 组和版本,同时提供了常见资源的版本映射简化调用。
核心模块
"""
Kubernetes 资源操作模块 (支持版本 1.28+)
依赖: kubernetes>=23.0.0
安装: pip install kubernetes>=23.0.0
"""
import logging
from typing import Any, Dict, List, Optional, Union
from kubernetes import config, dynamic
from kubernetes.client import api_client
from kubernetes.dynamic.exceptions import NotFoundError, ResourceNotFoundError
logger = logging.getLogger(__name__)
class K8sClient:
"""
Kubernetes 客户端封装,提供资源的增删改查通用接口
"""
# 常见内置资源到 api_version 的映射 (用于简化调用)
COMMON_API_VERSIONS = {
"pod": "v1",
"service": "v1",
"configmap": "v1",
"secret": "v1",
"namespace": "v1",
"node": "v1",
"deployment": "apps/v1",
"statefulset": "apps/v1",
"daemonset": "apps/v1",
"replicaset": "apps/v1",
"ingress": "networking.k8s.io/v1",
"job": "batch/v1",
"cronjob": "batch/v1",
"persistentvolume": "v1",
"persistentvolumeclaim": "v1",
"serviceaccount": "v1",
"role": "rbac.authorization.k8s.io/v1",
"rolebinding": "rbac.authorization.k8s.io/v1",
"clusterrole": "rbac.authorization.k8s.io/v1",
"clusterrolebinding": "rbac.authorization.k8s.io/v1",
}
def __init__(
self,
config_file: Optional[str] = None,
context: Optional[str] = None,
persist_config: bool = True,
):
"""
初始化 K8s 客户端
:param config_file: kubeconfig 文件路径,默认使用 ~/.kube/config
:param context: 使用的上下文名称,仅在 kubeconfig 模式下有效
:param persist_config: 是否持久化配置更改 (如修改当前上下文)
"""
# 加载配置:优先 in-cluster,否则使用 kubeconfig
try:
config.load_incluster_config()
logger.info("使用 in-cluster 配置")
except config.ConfigException:
config.load_kube_config(
config_file=config_file,
context=context,
persist_config=persist_config,
)
logger.info("使用 kubeconfig 配置")
self._client = dynamic.DynamicClient(api_client.ApiClient())
def _get_resource(self, kind: str, api_version: Optional[str] = None):
"""
根据 kind 和 api_version 获取 Resource 对象
:param kind: 资源类型,如 'Deployment', 'Pod'
:param api_version: API 版本,如 'v1', 'apps/v1';若不提供则从映射中推断
:return: Resource 对象
:raises ValueError: 无法推断 api_version 时抛出
:raises ResourceNotFoundError: 资源类型不存在时抛出
"""
if api_version is None:
# 尝试从常见映射中获取
inferred = self.COMMON_API_VERSIONS.get(kind.lower())
if inferred:
api_version = inferred
logger.debug("推断 %s 的 api_version 为 %s", kind, api_version)
else:
raise ValueError(
f"无法推断资源 '{kind}' 的 api_version,请显式提供 api_version 参数"
)
return self._client.resources.get(kind=kind, api_version=api_version)
def get(
self,
kind: str,
name: str,
namespace: Optional[str] = None,
api_version: Optional[str] = None,
) -> Optional[Dict[str, Any]]:
"""
获取单个资源
:param kind: 资源类型
:param name: 资源名称
:param namespace: 命名空间 (集群级别资源不需要)
:param api_version: API 版本,若不提供则尝试从常见映射推断
:return: 资源字典,如果不存在则返回 None
"""
resource = self._get_resource(kind, api_version)
try:
if namespace:
return resource.get(name=name, namespace=namespace).to_dict()
else:
return resource.get(name=name).to_dict()
except NotFoundError:
logger.debug("资源 %s/%s 不存在", kind, name)
return None
def list(
self,
kind: str,
namespace: Optional[str] = None,
api_version: Optional[str] = None,
label_selector: Optional[str] = None,
field_selector: Optional[str] = None,
) -> List[Dict[str, Any]]:
"""
列出资源
:param kind: 资源类型
:param namespace: 命名空间 (不传则返回集群范围资源或所有命名空间)
:param api_version: API 版本
:param label_selector: 标签选择器,如 'app=nginx'
:param field_selector: 字段选择器,如 'metadata.name=my-pod'
:return: 资源字典列表
"""
resource = self._get_resource(kind, api_version)
kwargs = {}
if namespace:
kwargs["namespace"] = namespace
if label_selector:
kwargs["label_selector"] = label_selector
if field_selector:
kwargs["field_selector"] = field_selector
items = resource.get(**kwargs).items
return [item.to_dict() for item in items]
def create(
self,
kind: str,
body: Dict[str, Any],
namespace: Optional[str] = None,
api_version: Optional[str] = None,
) -> Dict[str, Any]:
"""
创建资源
:param kind: 资源类型
:param body: 资源定义 (符合 Kubernetes API 的字典)
:param namespace: 命名空间 (如果 body.metadata 中未指定则使用此值)
:param api_version: API 版本
:return: 创建后的资源字典
:raises: kubernetes.dynamic.exceptions 相关异常 (如 ConflictError)
"""
resource = self._get_resource(kind, api_version)
# 确保 body 中包含命名空间
if namespace and "namespace" not in body.get("metadata", {}):
body.setdefault("metadata", {})["namespace"] = namespace
result = resource.create(body=body, namespace=namespace)
return result.to_dict()
def update(
self,
kind: str,
name: str,
body: Dict[str, Any],
namespace: Optional[str] = None,
api_version: Optional[str] = None,
) -> Dict[str, Any]:
"""
全量替换更新资源 (等同于 kubectl replace)
:param kind: 资源类型
:param name: 资源名称
:param body: 新的完整资源定义
:param namespace: 命名空间
:param api_version: API 版本
:return: 更新后的资源字典
"""
resource = self._get_resource(kind, api_version)
result = resource.replace(body=body, name=name, namespace=namespace)
return result.to_dict()
def patch(
self,
kind: str,
name: str,
body: Union[Dict[str, Any], List[Dict[str, Any]]],
namespace: Optional[str] = None,
api_version: Optional[str] = None,
) -> Dict[str, Any]:
"""
部分更新资源 (支持 strategic merge, JSON patch 等)
:param kind: 资源类型
:param name: 资源名称
:param body: 补丁内容,可以是字典或列表 (符合 JSON Patch 格式)
:param namespace: 命名空间
:param api_version: API 版本
:return: 更新后的资源字典
"""
resource = self._get_resource(kind, api_version)
result = resource.patch(body=body, name=name, namespace=namespace)
return result.to_dict()
def delete(
self,
kind: str,
name: str,
namespace: Optional[str] = None,
api_version: Optional[str] = None,
) -> bool:
"""
删除资源
:param kind: 资源类型
:param name: 资源名称
:param namespace: 命名空间
:param api_version: API 版本
:return: 是否成功删除 (如果资源不存在也返回 False)
"""
resource = self._get_resource(kind, api_version)
try:
resource.delete(name=name, namespace=namespace)
logger.info("资源 %s/%s 删除成功", kind, name)
return True
except NotFoundError:
logger.debug("资源 %s/%s 不存在,无法删除", kind, name)
return False
except Exception as e:
logger.error("删除资源 %s/%s 失败: %s", kind, name, e)
raise
# 以下是针对特定资源的便捷方法(可选)
def get_deployment(self, name: str, namespace: str) -> Optional[Dict[str, Any]]:
"""获取 Deployment"""
return self.get("Deployment", name, namespace)
def list_deployments(self, namespace: str) -> List[Dict[str, Any]]:
"""列出命名空间下的所有 Deployment"""
return self.list("Deployment", namespace)
def create_deployment(self, body: Dict[str, Any], namespace: str) -> Dict[str, Any]:
"""创建 Deployment"""
return self.create("Deployment", body, namespace)
def delete_deployment(self, name: str, namespace: str) -> bool:
"""删除 Deployment"""
return self.delete("Deployment", name, namespace)
使用示例
from k8s_client import K8sClient
# 初始化客户端(默认使用 ~/.kube/config 或 in-cluster 配置)
client = K8sClient()
# 列出所有命名空间
namespaces = client.list("Namespace")
print(namespaces)
# 创建 Nginx Deployment
deployment_manifest = {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {"name": "nginx-demo"},
"spec": {
"replicas": 2,
"selector": {"matchLabels": {"app": "nginx"}},
"template": {
"metadata": {"labels": {"app": "nginx"}},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest",
"ports": [{"containerPort": 80}],
}
]
},
},
},
}
created = client.create("Deployment", deployment_manifest, namespace="default")
print(created)
# 获取该 Deployment
dep = client.get("Deployment", "nginx-demo", namespace="default")
print(dep)
# 更新副本数 (使用 patch)
patch_body = {"spec": {"replicas": 3}}
updated = client.patch("Deployment", "nginx-demo", patch_body, namespace="default")
print(updated)
# 删除 Deployment
client.delete("Deployment", "nginx-demo", namespace="default")
特性说明
- 自动配置加载:优先加载 in-cluster 配置(适用于 Pod 内运行),否则加载 kubeconfig。
- 通用动态客户端:支持任意 Kubernetes 资源(内置 + CRD),无需为每种资源单独编写方法。
- 版本推断:内置常见资源的
apiVersion映射,多数情况下无需显式指定。 - 完整的 CRUD:提供
get、list、create、update、patch、delete方法。 - 错误处理:资源不存在时
get返回None,delete返回False;其他异常直接抛出,便于上层处理。 - 类型提示:使用类型注解,提升 IDE 友好度。
- 便捷方法:可选地为常用资源(如 Deployment)提供了专门方法,调用更直观。
依赖与兼容性
- Python >= 3.7
- kubernetes >= 23.0.0 (支持 Kubernetes 1.28)
- 安装命令:
pip install "kubernetes>=23.0.0"
模块已在 Kubernetes 1.28.2 环境下测试通过,并兼容所有内置资源及常见 CRD。
作者:wanghongwei
版权声明:本作品遵循<CC BY-NC-ND 4.0>版权协议,商业转载请联系作者获得授权,非商业转载请附上原文出处链接及本声明。

浙公网安备 33010602011771号