From fd80db220a101f3a8a41934feec3ce7c8c154c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=90=D0=BD=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=BF=D0=BE=D0=B2?= Date: Sun, 26 Oct 2025 10:03:59 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B5=20=D1=83=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20Ingress=20?= =?UTF-8?q?=D1=85=D0=BE=D1=81=D1=82=D0=B0=D0=BC=D0=B8=20=D0=B2=20/etc/host?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавлен скрипт scripts/manage_hosts.py для управления /etc/hosts - Автоматическое добавление Ingress хостов при создании кластера - Автоматическое удаление Ingress хостов при удалении кластера - Записи помечаются меткой #k8s для разделения со статическими - Команды: add, remove, cleanup, list --- Makefile | 4 + scripts/manage_hosts.py | 190 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100755 scripts/manage_hosts.py diff --git a/Makefile b/Makefile index 1e26b59..38c6cc8 100644 --- a/Makefile +++ b/Makefile @@ -1053,6 +1053,8 @@ k8s: echo "✅ Kind кластер создан"; \ echo "🔌 Автоматическое создание port-forward..."; \ python3 scripts/portforward.py create || echo "⚠️ Не удалось создать port-forward автоматически"; \ + echo "📝 Добавление Ingress хостов в /etc/hosts..."; \ + sudo python3 scripts/manage_hosts.py add 2>/dev/null || echo "⚠️ Не удалось добавить Ingress хосты (требуется sudo)"; \ echo "💡 Для подключения используйте: make k8s kubeconfig"; \ echo "💡 Для остановки используйте: make k8s stop";; \ destroy) \ @@ -1062,6 +1064,8 @@ k8s: CONTAINER_NAME=k8s-controller; \ echo "🔌 Очистка port-forward..."; \ python3 scripts/portforward.py clear || echo "⚠️ Не удалось очистить port-forward"; \ + echo "📝 Удаление Ingress хостов из /etc/hosts..."; \ + sudo python3 scripts/manage_hosts.py remove 2>/dev/null || echo "⚠️ Не удалось удалить Ingress хосты (требуется sudo)"; \ if docker ps | grep -q $$CONTAINER_NAME; then \ echo "🗑️ Удаление Kind кластеров..."; \ docker exec $$CONTAINER_NAME bash -c "kind delete clusters --all" 2>/dev/null || true; \ diff --git a/scripts/manage_hosts.py b/scripts/manage_hosts.py new file mode 100755 index 0000000..bd91433 --- /dev/null +++ b/scripts/manage_hosts.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 +""" +Скрипт для управления записями в /etc/hosts для Ingress ресурсов +Автор: Сергей Антропов +Сайт: https://devops.org.ru +""" +import sys +import subprocess +import re +import os + +HOSTS_FILE = "/etc/hosts" +K8S_MARKER = "#k8s" + +def is_root(): + """Проверяет, запущен ли скрипт от root""" + return os.geteuid() == 0 + +def get_ingress_hosts(): + """Получает список Ingress хостов из кластера""" + # Получаем kubeconfig из контейнера k8s-controller + result = subprocess.run( + "docker exec k8s-controller kind get kubeconfig", + shell=True, capture_output=True, text=True + ) + + if result.returncode != 0: + print("⚠️ Кластер недоступен") + return [] + + # Сохраняем kubeconfig во временный файл + import tempfile + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.yaml') as f: + f.write(result.stdout) + kubeconfig_file = f.name + + try: + # Получаем все Ingress ресурсы + result = subprocess.run( + f"kubectl --kubeconfig {kubeconfig_file} get ingress --all-namespaces -o jsonpath='{{range .items}}{{range .spec.rules}}{{.host}}{{\"\\n\"}}{{end}}{{end}}'", + shell=True, capture_output=True, text=True + ) + + hosts = [] + if result.returncode == 0: + hosts = [h.strip() for h in result.stdout.split('\n') if h.strip()] + + return hosts + finally: + # Удаляем временный файл + os.unlink(kubeconfig_file) + +def get_current_k8s_entries(): + """Получает текущие k8s записи из /etc/hosts""" + if not os.path.exists(HOSTS_FILE): + return [] + + entries = [] + with open(HOSTS_FILE, 'r') as f: + for line in f: + if K8S_MARKER in line: + # Извлекаем IP и hostname + parts = line.split() + if len(parts) >= 2: + ip = parts[0] + hostname = parts[1] + entries.append((ip, hostname)) + + return entries + +def remove_k8s_entries(): + """Удаляет все записи с меткой #k8s из /etc/hosts""" + if not os.path.exists(HOSTS_FILE): + print("⚠️ Файл /etc/hosts не существует") + return + + print("🗑️ Удаление k8s записей из /etc/hosts...") + + # Читаем файл + with open(HOSTS_FILE, 'r') as f: + lines = f.readlines() + + # Фильтруем строки с меткой #k8s + new_lines = [] + removed_count = 0 + + for line in lines: + if K8S_MARKER in line: + removed_count += 1 + print(f" ❌ Удалено: {line.strip()}") + else: + new_lines.append(line) + + # Записываем обратно + with open(HOSTS_FILE, 'w') as f: + f.writelines(new_lines) + + print(f"✅ Удалено {removed_count} записей") + +def add_ingress_entries(): + """Добавляет записи Ingress в /etc/hosts""" + if not is_root(): + print("❌ Ошибка: скрипт должен быть запущен от root") + print("💡 Используйте: sudo python3 scripts/manage_hosts.py add") + sys.exit(1) + + # Проверяем доступность кластера + result = subprocess.run("docker ps | grep k8s-controller", shell=True, capture_output=True, text=True) + if result.returncode != 0: + print("❌ Контейнер k8s-controller не запущен") + return + + print("🔍 Поиск Ingress ресурсов в кластере...") + hosts = get_ingress_hosts() + + if not hosts: + print("ℹ️ Не найдено Ingress ресурсов в кластере") + return + + print(f"📋 Найдено {len(hosts)} Ingress хостов: {', '.join(hosts)}") + + # Получаем текущие записи + current_entries = get_current_k8s_entries() + current_hosts = [e[1] for e in current_entries] + + # Удаляем старые записи + if current_entries: + print("🗑️ Удаление старых k8s записей...") + remove_k8s_entries() + + # Добавляем новые записи + print("➕ Добавление новых записей в /etc/hosts...") + + with open(HOSTS_FILE, 'a') as f: + for host in hosts: + entry = f"127.0.0.1 {host} {K8S_MARKER}\n" + f.write(entry) + print(f" ✅ Добавлено: 127.0.0.1 {host}") + + print(f"✅ Добавлено {len(hosts)} записей в /etc/hosts") + +def cleanup_k8s_entries(): + """Очищает k8s записи если кластер недоступен""" + print("🔍 Проверка доступности кластера...") + + # Проверяем доступность контейнера + result = subprocess.run("docker ps | grep k8s-controller", shell=True, capture_output=True, text=True) + if result.returncode == 0: + print("✅ Кластер доступен") + return + + print("⚠️ Кластер недоступен, очищаем k8s записи...") + remove_k8s_entries() + +def list_k8s_entries(): + """Выводит список текущих k8s записей""" + entries = get_current_k8s_entries() + if not entries: + print("ℹ️ Нет k8s записей в /etc/hosts") + return + + print("📋 Текущие k8s записи в /etc/hosts:") + for ip, hostname in entries: + print(f" {ip} {hostname}") + +def main(): + if len(sys.argv) < 2: + print("Usage: manage_hosts.py ") + print(" add - добавить Ingress хосты в /etc/hosts") + print(" remove - удалить все k8s записи из /etc/hosts") + print(" cleanup - удалить k8s записи если кластер недоступен") + print(" list - показать текущие k8s записи") + sys.exit(1) + + command = sys.argv[1] + + if command == "add": + add_ingress_entries() + elif command == "remove": + remove_k8s_entries() + elif command == "cleanup": + cleanup_k8s_entries() + elif command == "list": + list_k8s_entries() + else: + print(f"❌ Неизвестная команда: {command}") + sys.exit(1) + +if __name__ == '__main__': + main()