Files
DevOpsLab/scripts/portforward.py
Sergey Antropoff 05881e8d74 podman: переход на Podman, Minikube, локальные образы и док для новичков
- Molecule: драйвер delegated, коллекция containers.podman, create/destroy/verify на Podman
- Makefile: все вызовы docker заменены на podman, сокет /run/podman/podman.sock
- Сборка образов: podman build (без buildx), buildall/buildall-image — только локально без push
- Ansible-controller: Podman в образе, docker-compose на podman compose, сокет Podman
- K8s: Kind заменён на Minikube (драйвер podman), скрипты и Makefile обновлены
- Пресеты: проверка локальных образов, без podman pull (registry запрещён)
- Документация: docs/podman.md, docs/quickstart-for-dummies.md (роли, плейбук, линт, тесты, пресеты, инвентори)
- README: ссылка на quickstart-for-dummies

Made-with: Cursor
2026-03-11 19:59:47 +03:00

242 lines
9.0 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 <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()