full_container_scheme/kubernets_api/export_k8s_resources.py

237 lines
9.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env python3
"""
Author: Logan.Li
Gitee: https://gitee.com/attacker
email: admin@attacker.club
Date: 2025-01-05 12:25:52
LastEditTime: 2025-04-09
Description: 导出Kubernetes Deployment+Service和Ingress资源
"""
import os
import yaml
import subprocess
import sys
# 尝试导入kubernetes模块如果失败则尝试安装
try:
from kubernetes import client, config
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
except ImportError:
print("kubernetes模块未安装尝试安装...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "kubernetes"])
from kubernetes import client, config
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def sanitize_resource(obj, resource_type):
"""清理资源对象,移除不必要的字段"""
# 获取序列化后的对象
obj_yaml = api_client.sanitize_for_serialization(obj)
# 确保正确的apiVersion和kind在最前面
if isinstance(obj, client.V1Service):
obj_yaml['apiVersion'] = 'v1'
obj_yaml['kind'] = 'Service'
elif isinstance(obj, client.V1Deployment):
obj_yaml['apiVersion'] = 'apps/v1'
obj_yaml['kind'] = 'Deployment'
elif isinstance(obj, client.V1Ingress):
obj_yaml['apiVersion'] = 'networking.k8s.io/v1'
obj_yaml['kind'] = 'Ingress'
# 重新组织字段顺序确保apiVersion和kind在最前面
ordered_obj = {
'apiVersion': obj_yaml.pop('apiVersion'),
'kind': obj_yaml.pop('kind'),
'metadata': obj_yaml.pop('metadata', {}),
'spec': obj_yaml.pop('spec', {})
}
# 清理metadata中的不必要字段
metadata_fields = ['selfLink', 'generation', 'creationTimestamp',
'resourceVersion', 'uid', 'managedFields']
for field in metadata_fields:
ordered_obj['metadata'].pop(field, None)
# 清理annotations
annotations_to_remove = [
'deployment.kubernetes.io/revision',
'kubectl.kubernetes.io/restartedAt',
'kubectl.kubernetes.io/last-applied-configuration'
]
if 'annotations' in ordered_obj['metadata']:
for ann in annotations_to_remove:
ordered_obj['metadata']['annotations'].pop(ann, None)
# 如果annotations为空则删除该字段
if not ordered_obj['metadata']['annotations']:
del ordered_obj['metadata']['annotations']
# 清理spec中的不必要字段
if resource_type == 'Service':
if 'clusterIPs' in ordered_obj['spec']:
del ordered_obj['spec']['clusterIPs']
if 'clusterIP' in ordered_obj['spec']:
del ordered_obj['spec']['clusterIP']
if 'ipFamilies' in ordered_obj['spec']:
del ordered_obj['spec']['ipFamilies']
if 'internalTrafficPolicy' in ordered_obj['spec']:
del ordered_obj['spec']['internalTrafficPolicy']
if 'ipFamilyPolicy' in ordered_obj['spec']:
del ordered_obj['spec']['ipFamilyPolicy']
elif resource_type == 'Deployment':
if 'strategy' in ordered_obj['spec']:
# 保留strategy但移除不需要的字段
strategy = ordered_obj['spec']['strategy']
if 'rollingUpdate' in strategy:
rolling_update = strategy['rollingUpdate']
if 'maxUnavailable' in rolling_update:
del rolling_update['maxUnavailable']
if 'maxSurge' in rolling_update:
del rolling_update['maxSurge']
# 如果rollingUpdate为空则删除
if not rolling_update:
del strategy['rollingUpdate']
# 移除status字段和其他不需要的字段
if 'status' in obj_yaml:
del obj_yaml['status']
# 添加其他可能需要的字段
for key, value in obj_yaml.items():
if key not in ['apiVersion', 'kind', 'metadata', 'spec'] and value is not None:
ordered_obj[key] = value
return ordered_obj
def export_resources():
"""导出Kubernetes资源到不同目录"""
# 加载kubeconfig
config.load_kube_config()
global api_client
api_client = client.ApiClient()
# 创建API客户端
apps_api = client.AppsV1Api(api_client)
core_api = client.CoreV1Api(api_client)
networking_api = client.NetworkingV1Api(api_client)
# 获取所有资源
all_deployments = apps_api.list_deployment_for_all_namespaces().items
all_services = core_api.list_service_for_all_namespaces().items
all_ingresses = networking_api.list_ingress_for_all_namespaces().items
# 创建输出目录
deployments_dir = os.path.join(os.getcwd(), 'deployments')
ingress_dir = os.path.join(os.getcwd(), 'ingress')
os.makedirs(deployments_dir, exist_ok=True)
os.makedirs(ingress_dir, exist_ok=True)
# 按命名空间和组织资源
namespace_resources = {}
# 处理Deployment和Service
for dep in all_deployments:
namespace = dep.metadata.namespace
dep_name = dep.metadata.name
if namespace not in namespace_resources:
namespace_resources[namespace] = {'deployments': {}, 'services': {}, 'ingresses': {}}
# 清理并添加Deployment
cleaned_dep = sanitize_resource(dep, 'Deployment')
namespace_resources[namespace]['deployments'][dep_name] = cleaned_dep
# 查找匹配的Service
pod_labels = dep.spec.template.metadata.labels
matched_svcs = [
svc for svc in all_services
if svc.metadata.namespace == namespace
and svc.spec.selector
and all(pod_labels.get(k) == v for k, v in svc.spec.selector.items())
]
# 清理并添加匹配的Service
for svc in matched_svcs:
cleaned_svc = sanitize_resource(svc, 'Service')
namespace_resources[namespace]['services'][svc.metadata.name] = cleaned_svc
# 处理Ingress
for ingress in all_ingresses:
namespace = ingress.metadata.namespace
if namespace not in namespace_resources:
namespace_resources[namespace] = {'deployments': {}, 'services': {}, 'ingresses': {}}
# 清理并添加Ingress
cleaned_ingress = sanitize_resource(ingress, 'Ingress')
namespace_resources[namespace]['ingresses'][ingress.metadata.name] = cleaned_ingress
# 导出Deployment+Service到deployments目录
for namespace, resources in namespace_resources.items():
# 在deployments目录下创建命名空间子目录
ns_deployments_dir = os.path.join(deployments_dir, namespace)
os.makedirs(ns_deployments_dir, exist_ok=True)
# 导出每个Deployment及其相关Service
for dep_name, deployment in resources['deployments'].items():
# 查找与此Deployment相关的Service
related_services = []
for svc_name, service in resources['services'].items():
# 简单匹配Service名称包含Deployment名称
if dep_name in svc_name:
related_services.append(service)
# 组合Deployment和Service
combined_resources = [deployment]
combined_resources.extend(related_services)
# 生成文件名
filename = f"{dep_name}.yaml"
filepath = os.path.join(ns_deployments_dir, filename)
# 写入文件确保正确的YAML格式
with open(filepath, 'w') as f:
yaml.dump_all(combined_resources, f, default_flow_style=False, sort_keys=False, explicit_start=True)
print(f"Exported {len(combined_resources)} resources to {filepath}")
# 导出没有关联Deployment的独立Service
exported_services = set()
for deployment_name in resources['deployments']:
for svc_name in resources['services']:
if deployment_name in svc_name:
exported_services.add(svc_name)
for svc_name, service in resources['services'].items():
if svc_name not in exported_services:
filename = f"{svc_name}.yaml"
filepath = os.path.join(ns_deployments_dir, filename)
with open(filepath, 'w') as f:
yaml.dump(service, f, default_flow_style=False, sort_keys=False)
print(f"Exported standalone Service to {filepath}")
# 导出Ingress到ingress目录
for namespace, resources in namespace_resources.items():
if resources['ingresses']:
# 在ingress目录下创建命名空间子目录
ns_ingress_dir = os.path.join(ingress_dir, namespace)
os.makedirs(ns_ingress_dir, exist_ok=True)
# 导出所有Ingress
for ing_name, ingress in resources['ingresses'].items():
filename = f"{ing_name}.yaml"
filepath = os.path.join(ns_ingress_dir, filename)
with open(filepath, 'w') as f:
yaml.dump(ingress, f, default_flow_style=False, sort_keys=False)
print(f"Exported Ingress to {filepath}")
if __name__ == "__main__":
export_resources()