- Добавлен port-forward для Ingress HTTP на порт 8081 (localhost:8081 -> ingress-nginx-controller:80) - Добавлен port-forward для Ingress HTTPS на порт 8443 (localhost:8443 -> ingress-nginx-controller:443) - Теперь все аддоны доступны через port-forward: Ingress, Prometheus, Grafana, Kiali, Metrics Server
		
			
				
	
	
		
			254 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/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():
 | ||
|     """Получаем имя кластера из preset файла"""
 | ||
|     preset_file = "molecule/presets/k8s/kubernetes.yml"
 | ||
|     with open(preset_file, 'r') as f:
 | ||
|         preset = yaml.safe_load(f)
 | ||
|     return preset['kind_clusters'][0]['name']
 | ||
| 
 | ||
| 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 на локальном компьютере"""
 | ||
|     # Загружаем preset
 | ||
|     preset_file = "molecule/presets/k8s/kubernetes.yml"
 | ||
|     with open(preset_file, 'r') as f:
 | ||
|         preset = yaml.safe_load(f)
 | ||
|     
 | ||
|     cluster_name = preset['kind_clusters'][0]['name']
 | ||
|     addon_ports = preset['kind_clusters'][0].get('addon_ports', {})
 | ||
|     
 | ||
|     # Получаем kubeconfig из контейнера k8s-controller
 | ||
|     print(f"🔌 Создание port-forward для кластера: {cluster_name}")
 | ||
|     print("📋 Получение kubeconfig из контейнера k8s-controller...")
 | ||
|     
 | ||
|     # Копируем kubeconfig из контейнера
 | ||
|     result = subprocess.run(
 | ||
|         f"docker exec k8s-controller kind get kubeconfig --name {cluster_name}",
 | ||
|         shell=True, capture_output=True, text=True
 | ||
|     )
 | ||
|     
 | ||
|     if result.returncode != 0:
 | ||
|         print(f"❌ Ошибка получения kubeconfig: {result.stderr}")
 | ||
|         return
 | ||
|     
 | ||
|     # Сохраняем kubeconfig во временный файл
 | ||
|     kubeconfig_file = "/tmp/kubeconfig-lab.yaml"
 | ||
|     with open(kubeconfig_file, 'w') as f:
 | ||
|         f.write(result.stdout)
 | ||
|     
 | ||
|     # Меняем server с 0.0.0.0 на localhost для локального доступа
 | ||
|     subprocess.run(f"sed -i.bak 's|server: https://0.0.0.0:6443|server: https://localhost:6443|g' {kubeconfig_file}", shell=True)
 | ||
|     
 | ||
|     print("✅ Kubeconfig подготовлен")
 | ||
|     
 | ||
|     # 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 <create|list|delete|clear|recreate> [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 <port>")
 | ||
|             sys.exit(1)
 | ||
|         port = sys.argv[2]
 | ||
|         delete_portforward(port)
 | ||
|     else:
 | ||
|         print(f"❌ Неизвестная команда: {command}")
 | ||
|         sys.exit(1)
 | ||
| 
 | ||
| if __name__ == "__main__":
 | ||
|     main()
 |