#!/usr/bin/env python3 """ Скрипт для управления port-forward для Kubernetes сервисов Автор: Сергей Антропов Сайт: https://devops.org.ru """ import sys import yaml import subprocess import os import signal import time def get_cluster_name(): """Получаем имя профиля Minikube из preset файла""" preset_file = "molecule/presets/k8s/kubernetes.yml" if not os.path.exists(preset_file): return "minikube" with open(preset_file, "r", encoding="utf-8") as f: preset = yaml.safe_load(f) or {} return preset.get("minikube_profile", "minikube") def run_cmd(cmd): """Выполняет команду и возвращает результат""" print(f"[run] {cmd}") result = subprocess.run(cmd, shell=True, capture_output=True, text=True) if result.returncode != 0: print(f"[error] {result.stderr}") else: print(result.stdout) return result def get_portforward_pids(): """Получает PID процессов port-forward""" result = subprocess.run("ps aux | grep 'kubectl.*port-forward' | grep -v grep", shell=True, capture_output=True, text=True) pids = [] for line in result.stdout.split('\n'): if line.strip(): pids.append(int(line.split()[1])) return pids def list_portforwards(): """Показывает список всех активных port-forward""" pids = get_portforward_pids() if not pids: print("❌ Нет активных port-forward") return print("📋 Активные port-forward:") result = subprocess.run("ps aux | grep 'kubectl.*port-forward' | grep -v grep", shell=True, capture_output=True, text=True) for line in result.stdout.split('\n'): if line.strip(): print(f" {line}") def clear_portforwards(): """Завершает все процессы port-forward""" pids = get_portforward_pids() if not pids: print("❌ Нет активных port-forward") return print(f"🗑️ Завершение {len(pids)} процессов port-forward...") for pid in pids: try: os.kill(pid, signal.SIGTERM) print(f"✅ Процесс {pid} завершен") except ProcessLookupError: print(f"⚠️ Процесс {pid} уже не существует") # Ждем завершения процессов time.sleep(2) # Принудительно убиваем оставшиеся remaining_pids = get_portforward_pids() if remaining_pids: print("⚠️ Принудительное завершение оставшихся процессов...") for pid in remaining_pids: try: os.kill(pid, signal.SIGKILL) print(f"✅ Процесс {pid} принудительно завершен") except ProcessLookupError: pass def create_portforwards(): """Создает port-forward для всех сервисов из preset на локальном компьютере (Minikube).""" preset_file = "molecule/presets/k8s/kubernetes.yml" preset = {} if os.path.exists(preset_file): with open(preset_file, "r", encoding="utf-8") as f: preset = yaml.safe_load(f) or {} # Поддержка minikube_profile и addon_ports (на верхнем уровне или в kind_clusters[0]) cluster_name = preset.get("minikube_profile", "minikube") addon_ports = preset.get("addon_ports") or (preset.get("kind_clusters") or [{}])[0].get("addon_ports", {}) # Minikube обновляет ~/.kube/config — используем его kubeconfig_file = os.environ.get("KUBECONFIG", os.path.expanduser("~/.kube/config")) if not os.path.exists(kubeconfig_file): print(f"❌ Kubeconfig не найден: {kubeconfig_file}. Запустите: make k8s create") return print(f"🔌 Создание port-forward для Minikube (профиль: {cluster_name})") print(f"📋 Kubeconfig: {kubeconfig_file}") # Ingress HTTP (80) if addon_ports.get('ingress_http'): port = addon_ports['ingress_http'] print(f" - Ingress HTTP: localhost:{port} -> ingress-nginx-controller:80") subprocess.Popen([ "kubectl", f"--kubeconfig={kubeconfig_file}", "port-forward", "-n", "ingress-nginx", "svc/ingress-nginx-controller", f"{port}:80" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Ingress HTTPS (443) if addon_ports.get('ingress_https'): port = addon_ports['ingress_https'] print(f" - Ingress HTTPS: localhost:{port} -> ingress-nginx-controller:443") subprocess.Popen([ "kubectl", f"--kubeconfig={kubeconfig_file}", "port-forward", "-n", "ingress-nginx", "svc/ingress-nginx-controller", f"{port}:443" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Prometheus if addon_ports.get('prometheus'): port = addon_ports['prometheus'] print(f" - Prometheus: localhost:{port} -> monitoring/monitoring-kube-prometheus-prometheus:9090") subprocess.Popen([ "kubectl", f"--kubeconfig={kubeconfig_file}", "port-forward", "-n", "monitoring", "svc/monitoring-kube-prometheus-prometheus", f"{port}:9090" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Grafana if addon_ports.get('grafana'): port = addon_ports['grafana'] print(f" - Grafana: localhost:{port} -> monitoring/monitoring-grafana:80") subprocess.Popen([ "kubectl", f"--kubeconfig={kubeconfig_file}", "port-forward", "-n", "monitoring", "svc/monitoring-grafana", f"{port}:80" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Kiali if addon_ports.get('kiali'): port = addon_ports['kiali'] print(f" - Kiali: localhost:{port} -> istio-system/kiali:20001") subprocess.Popen([ "kubectl", f"--kubeconfig={kubeconfig_file}", "port-forward", "-n", "istio-system", "svc/kiali", f"{port}:20001" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Metrics Server if addon_ports.get('metrics_server'): port = addon_ports['metrics_server'] print(f" - Metrics Server: localhost:{port} -> kube-system/metrics-server:4443") subprocess.Popen([ "kubectl", f"--kubeconfig={kubeconfig_file}", "port-forward", "-n", "kube-system", "svc/metrics-server", f"{port}:4443" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(2) print("✅ Port-forward создан") list_portforwards() def delete_portforward(port): """Удаляет port-forward для конкретного порта""" pids = get_portforward_pids() if not pids: print(f"❌ Нет активных port-forward на порту {port}") return # Находим процесс с нужным портом result = subprocess.run(f"ps aux | grep 'kubectl.*port-forward.*:{port}' | grep -v grep", shell=True, capture_output=True, text=True) if not result.stdout.strip(): print(f"❌ Не найден port-forward на порту {port}") return # Извлекаем PID pid = int(result.stdout.split()[1]) print(f"🗑️ Завершение port-forward на порту {port} (PID: {pid})...") try: os.kill(pid, signal.SIGTERM) print(f"✅ Port-forward на порту {port} завершен") except ProcessLookupError: print(f"⚠️ Процесс {pid} уже не существует") def recreate_portforwards(): """Пересоздает port-forward: удаляет существующие и создает заново""" print("🔄 Пересоздание port-forward...") clear_portforwards() time.sleep(1) create_portforwards() def main(): if len(sys.argv) < 2: print("Usage: portforward.py [port]") sys.exit(1) command = sys.argv[1] if command == "create": create_portforwards() elif command == "list": list_portforwards() elif command == "clear": clear_portforwards() elif command == "recreate": recreate_portforwards() elif command == "delete": if len(sys.argv) < 3: print("Usage: portforward.py delete ") sys.exit(1) port = sys.argv[2] delete_portforward(port) else: print(f"❌ Неизвестная команда: {command}") sys.exit(1) if __name__ == "__main__": main()