k8s #1
5
Makefile
5
Makefile
@@ -1117,7 +1117,7 @@ k8s:
|
||||
docker exec $$CONTAINER_NAME bash -c "kind get clusters | xargs -I {} kind start cluster --name {}" 2>/dev/null || true; \
|
||||
echo "✅ Kind кластер запущен";; \
|
||||
status) \
|
||||
echo "📊 Статус Kind кластеров:"; \
|
||||
echo "📊 Детальный отчет о состоянии кластера..."; \
|
||||
PRESET_ARG="$(word 3, $(MAKECMDGOALS))"; \
|
||||
if [ -z "$$PRESET_ARG" ]; then \
|
||||
echo "❌ Ошибка: Укажите пресет"; \
|
||||
@@ -1126,8 +1126,7 @@ k8s:
|
||||
fi; \
|
||||
CONTAINER_NAME=k8s-controller; \
|
||||
if docker ps | grep -q $$CONTAINER_NAME; then \
|
||||
docker exec $$CONTAINER_NAME bash -c "kind get clusters" 2>/dev/null || echo " Нет кластеров"; \
|
||||
docker exec $$CONTAINER_NAME bash -c "kind get clusters | while read cluster; do echo \"Кластер: \$$cluster\"; kubectl --context kind-\$$cluster get nodes 2>/dev/null || true; done" 2>/dev/null || true; \
|
||||
python3 scripts/k8s_status.py; \
|
||||
else \
|
||||
echo "⚠️ Контейнер $$CONTAINER_NAME не запущен"; \
|
||||
echo "💡 Запустите: make k8s create $$PRESET_ARG"; \
|
||||
|
||||
300
scripts/k8s_status.py
Executable file
300
scripts/k8s_status.py
Executable file
@@ -0,0 +1,300 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для детального отчета о состоянии Kubernetes кластера
|
||||
Автор: Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
"""
|
||||
import sys
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
def get_cluster_name():
|
||||
"""Получает имя кластера"""
|
||||
result = subprocess.run("docker exec k8s-controller kind get clusters | head -1", shell=True, capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
return None
|
||||
|
||||
def run_kubectl_cmd(cmd):
|
||||
"""Выполняет команду kubectl внутри контейнера k8s-controller"""
|
||||
cluster_name = get_cluster_name()
|
||||
if cluster_name:
|
||||
# Используем прямой адрес control-plane
|
||||
server = f"https://{cluster_name}-control-plane:6443"
|
||||
cmd_with_server = f"--server={server} --insecure-skip-tls-verify {cmd}"
|
||||
else:
|
||||
cmd_with_server = cmd
|
||||
|
||||
full_cmd = f"docker exec k8s-controller kubectl {cmd_with_server}"
|
||||
result = subprocess.run(full_cmd, shell=True, capture_output=True, text=True)
|
||||
return result.stdout
|
||||
|
||||
def print_section(title):
|
||||
"""Выводит заголовок секции"""
|
||||
print(f"\n{'='*70}")
|
||||
print(f" {title}")
|
||||
print(f"{'='*70}\n")
|
||||
|
||||
def print_subsection(title):
|
||||
"""Выводит подзаголовок"""
|
||||
print(f"\n{'─'*70}")
|
||||
print(f" {title}")
|
||||
print(f"{'─'*70}\n")
|
||||
|
||||
def get_cluster_info():
|
||||
"""Получает информацию о кластере"""
|
||||
print_section("📊 ОБЩАЯ ИНФОРМАЦИЯ О КЛАСТЕРЕ")
|
||||
|
||||
# Версия Kubernetes
|
||||
version = run_kubectl_cmd("version --short")
|
||||
print(version)
|
||||
|
||||
def get_nodes_status():
|
||||
"""Получает статус узлов"""
|
||||
print_section("🖥️ УЗЛЫ КЛАСТЕРА")
|
||||
|
||||
nodes = run_kubectl_cmd("get nodes -o wide")
|
||||
print(nodes)
|
||||
|
||||
# Детальная информация о каждом узле
|
||||
node_names = run_kubectl_cmd("get nodes -o jsonpath='{.items[*].metadata.name}'")
|
||||
if node_names.strip():
|
||||
for node in node_names.strip().split():
|
||||
print_subsection(f"Узел: {node}")
|
||||
node_info = run_kubectl_cmd(f"describe node {node}")
|
||||
print(node_info)
|
||||
|
||||
def get_namespaces():
|
||||
"""Получает список namespace"""
|
||||
print_section("📁 NAMESPACES")
|
||||
|
||||
namespaces = run_kubectl_cmd("get namespaces")
|
||||
print(namespaces)
|
||||
|
||||
def get_pods_by_namespace():
|
||||
"""Получает поды по namespace"""
|
||||
print_section("🪟 PODS")
|
||||
|
||||
# Получаем список namespace
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
for ns in namespaces:
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
pods = run_kubectl_cmd(f"get pods -n {ns} -o wide")
|
||||
if pods.strip():
|
||||
print(pods)
|
||||
else:
|
||||
print(" (пусто)")
|
||||
|
||||
def get_services():
|
||||
"""Получает сервисы"""
|
||||
print_section("🔗 SERVICES")
|
||||
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
for ns in namespaces:
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
services = run_kubectl_cmd(f"get services -n {ns}")
|
||||
if services.strip():
|
||||
print(services)
|
||||
else:
|
||||
print(" (пусто)")
|
||||
|
||||
def get_ingress():
|
||||
"""Получает Ingress ресурсы"""
|
||||
print_section("🌐 INGRESS")
|
||||
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
ingress_found = False
|
||||
for ns in namespaces:
|
||||
ingress = run_kubectl_cmd(f"get ingress -n {ns} 2>/dev/null")
|
||||
if ingress.strip() and "No resources found" not in ingress:
|
||||
ingress_found = True
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
print(ingress)
|
||||
|
||||
if not ingress_found:
|
||||
print(" Ingress ресурсы не найдены")
|
||||
|
||||
def get_pvcs():
|
||||
"""Получает PersistentVolumeClaims"""
|
||||
print_section("💾 VOLUMES (PVC)")
|
||||
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
pvc_found = False
|
||||
for ns in namespaces:
|
||||
pvcs = run_kubectl_cmd(f"get pvc -n {ns} 2>/dev/null")
|
||||
if pvcs.strip() and "No resources found" not in pvcs:
|
||||
pvc_found = True
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
print(pvcs)
|
||||
|
||||
if not pvc_found:
|
||||
print(" PVC не найдены")
|
||||
|
||||
def get_deployments():
|
||||
"""Получает Deployments"""
|
||||
print_section("🚀 DEPLOYMENTS")
|
||||
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
for ns in namespaces:
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
deployments = run_kubectl_cmd(f"get deployments -n {ns}")
|
||||
if deployments.strip():
|
||||
print(deployments)
|
||||
else:
|
||||
print(" (пусто)")
|
||||
|
||||
def get_daemonsets():
|
||||
"""Получает DaemonSets"""
|
||||
print_section("🔧 DAEMONSETS")
|
||||
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
for ns in namespaces:
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
daemonsets = run_kubectl_cmd(f"get daemonsets -n {ns}")
|
||||
if daemonsets.strip():
|
||||
print(daemonsets)
|
||||
else:
|
||||
print(" (пусто)")
|
||||
|
||||
def get_statefulsets():
|
||||
"""Получает StatefulSets"""
|
||||
print_section("🗄️ STATEFULSETS")
|
||||
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
statefulsets_found = False
|
||||
for ns in namespaces:
|
||||
statefulsets = run_kubectl_cmd(f"get statefulsets -n {ns} 2>/dev/null")
|
||||
if statefulsets.strip() and "No resources found" not in statefulsets:
|
||||
statefulsets_found = True
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
print(statefulsets)
|
||||
|
||||
if not statefulsets_found:
|
||||
print(" StatefulSets не найдены")
|
||||
|
||||
def get_events():
|
||||
"""Получает события"""
|
||||
print_section("📅 СОБЫТИЯ (EVENTS)")
|
||||
|
||||
namespaces_output = run_kubectl_cmd("get namespaces -o json")
|
||||
try:
|
||||
namespaces_data = json.loads(namespaces_output)
|
||||
namespaces = [ns['metadata']['name'] for ns in namespaces_data['items']]
|
||||
except:
|
||||
namespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease']
|
||||
|
||||
for ns in namespaces:
|
||||
print_subsection(f"Namespace: {ns}")
|
||||
events = run_kubectl_cmd(f"get events -n {ns} --sort-by='.lastTimestamp' | tail -20")
|
||||
if events.strip():
|
||||
print(events)
|
||||
else:
|
||||
print(" (пусто)")
|
||||
|
||||
def get_helm_releases():
|
||||
"""Получает Helm релизы"""
|
||||
print_section("📦 HELM RELEASES")
|
||||
|
||||
helm_output = run_kubectl_cmd("helm list --all-namespaces 2>/dev/null")
|
||||
if helm_output.strip():
|
||||
print(helm_output)
|
||||
else:
|
||||
print(" Helm релизы не найдены")
|
||||
|
||||
def get_resource_usage():
|
||||
"""Получает использование ресурсов"""
|
||||
print_section("📈 ИСПОЛЬЗОВАНИЕ РЕСУРСОВ")
|
||||
|
||||
try:
|
||||
# Проверяем наличие metrics-server
|
||||
top_nodes = run_kubectl_cmd("top nodes 2>/dev/null")
|
||||
if top_nodes.strip():
|
||||
print_subsection("Узлы:")
|
||||
print(top_nodes)
|
||||
except:
|
||||
print(" metrics-server не установлен или недоступен")
|
||||
|
||||
try:
|
||||
top_pods = run_kubectl_cmd("top pods --all-namespaces 2>/dev/null")
|
||||
if top_pods.strip():
|
||||
print_subsection("Pods (топ-20):")
|
||||
# Берем только первые 20 строк
|
||||
lines = top_pods.strip().split('\n')
|
||||
print('\n'.join(lines[:21])) # + заголовок
|
||||
except:
|
||||
pass
|
||||
|
||||
def main():
|
||||
"""Главная функция"""
|
||||
# Проверяем доступность контейнера
|
||||
result = subprocess.run("docker ps | grep k8s-controller", shell=True, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print("❌ Контейнер k8s-controller не запущен")
|
||||
sys.exit(1)
|
||||
|
||||
print("="*70)
|
||||
print(" ДЕТАЛЬНЫЙ ОТЧЕТ О СОСТОЯНИИ KUBERNETES КЛАСТЕРА")
|
||||
print("="*70)
|
||||
|
||||
get_cluster_info()
|
||||
get_nodes_status()
|
||||
get_namespaces()
|
||||
get_resource_usage()
|
||||
get_pods_by_namespace()
|
||||
get_deployments()
|
||||
get_daemonsets()
|
||||
get_statefulsets()
|
||||
get_services()
|
||||
get_ingress()
|
||||
get_pvcs()
|
||||
get_events()
|
||||
get_helm_releases()
|
||||
|
||||
print("\n" + "="*70)
|
||||
print(" ОТЧЕТ ЗАВЕРШЕН")
|
||||
print("="*70 + "\n")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user