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
This commit is contained in:
74
scripts/create_minikube_cluster.py
Normal file
74
scripts/create_minikube_cluster.py
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для создания Minikube кластера с драйвером Podman.
|
||||
Автор: Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
"""
|
||||
import sys
|
||||
import yaml
|
||||
import subprocess
|
||||
|
||||
|
||||
def run_cmd(cmd, check=True):
|
||||
"""Выполнить команду на хосте."""
|
||||
print(f"[run] {cmd}")
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
if check and result.returncode != 0:
|
||||
print(f"[error] {result.stderr}")
|
||||
sys.exit(1)
|
||||
if result.stdout:
|
||||
print(result.stdout)
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: create_minikube_cluster.py <preset_file>")
|
||||
print(" Создаёт Minikube кластер с драйвером podman и опционально включает аддоны из пресета.")
|
||||
sys.exit(1)
|
||||
|
||||
preset_file = sys.argv[1]
|
||||
print(f"📋 Читаю пресет: {preset_file}")
|
||||
|
||||
with open(preset_file, "r", encoding="utf-8") as f:
|
||||
preset = yaml.safe_load(f) or {}
|
||||
|
||||
profile = preset.get("minikube_profile", "minikube")
|
||||
addons = preset.get("minikube_addons", [])
|
||||
cpus = preset.get("minikube_cpus", "2")
|
||||
memory = preset.get("minikube_memory", "4096")
|
||||
|
||||
print(f"\n☸️ Создание Minikube кластера (драйвер: podman)")
|
||||
print(f" Профиль: {profile}")
|
||||
print(f" CPU: {cpus}, Memory: {memory}")
|
||||
|
||||
# Проверяем, запущен ли уже кластер
|
||||
result = subprocess.run(
|
||||
f"minikube profile list 2>/dev/null | grep -E '^{profile}' | grep 'Running'",
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
print(f"⚠️ Кластер с профилем '{profile}' уже запущен.")
|
||||
print(" Для пересоздания выполните: minikube delete -p " + profile)
|
||||
else:
|
||||
run_cmd(
|
||||
f"minikube start --driver=podman --profile={profile} --cpus={cpus} --memory={memory}"
|
||||
)
|
||||
print(f"✅ Minikube кластер '{profile}' создан и запущен.")
|
||||
|
||||
# Включаем аддоны из пресета
|
||||
if addons:
|
||||
print(f"\n📦 Включение аддонов: {', '.join(addons)}")
|
||||
for addon in addons:
|
||||
run_cmd(f"minikube addons enable {addon} -p {profile}", check=False)
|
||||
|
||||
print("\n🎉 Готово. Использование:")
|
||||
print(f" kubectl config use-context {profile}")
|
||||
print(" minikube kubectl -- get nodes")
|
||||
print(" minikube dashboard -p " + profile)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -29,11 +29,11 @@ def main():
|
||||
host_name = host['name']
|
||||
|
||||
# Проверяем существование контейнера
|
||||
result = subprocess.run(f"docker ps -a --format '{{{{.Names}}}}' | grep -x {host_name}",
|
||||
result = subprocess.run(f"podman ps -a --format '{{{{.Names}}}}' | grep -x {host_name}",
|
||||
shell=True, capture_output=True, text=True)
|
||||
if result.stdout.strip():
|
||||
print(f"🗑️ Удаление контейнера: {host_name}")
|
||||
subprocess.run(f"docker rm -f {host_name}", shell=True, capture_output=True, text=True)
|
||||
subprocess.run(f"podman rm -f {host_name}", shell=True, capture_output=True, text=True)
|
||||
print(f"✅ Контейнер '{host_name}' удален")
|
||||
else:
|
||||
print(f"⚠️ Контейнер '{host_name}' не найден")
|
||||
|
||||
@@ -9,23 +9,18 @@ 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)
|
||||
"""Получает имя текущего контекста (Minikube)."""
|
||||
result = subprocess.run(
|
||||
"kubectl config current-context 2>/dev/null", 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}"
|
||||
"""Выполняет команду kubectl на хосте (контекст Minikube)."""
|
||||
full_cmd = f"kubectl {cmd}"
|
||||
result = subprocess.run(full_cmd, shell=True, capture_output=True, text=True)
|
||||
return result.stdout
|
||||
|
||||
|
||||
@@ -12,11 +12,13 @@ import signal
|
||||
import time
|
||||
|
||||
def get_cluster_name():
|
||||
"""Получаем имя кластера из preset файла"""
|
||||
"""Получаем имя профиля Minikube из 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']
|
||||
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):
|
||||
"""Выполняет команду и возвращает результат"""
|
||||
@@ -80,38 +82,24 @@ def clear_portforwards():
|
||||
pass
|
||||
|
||||
def create_portforwards():
|
||||
"""Создает port-forward для всех сервисов из preset на локальном компьютере"""
|
||||
# Загружаем preset
|
||||
"""Создает port-forward для всех сервисов из preset на локальном компьютере (Minikube)."""
|
||||
preset_file = "molecule/presets/k8s/kubernetes.yml"
|
||||
with open(preset_file, 'r') as f:
|
||||
preset = yaml.safe_load(f)
|
||||
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", {})
|
||||
|
||||
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}")
|
||||
# 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
|
||||
|
||||
# Сохраняем 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 подготовлен")
|
||||
print(f"🔌 Создание port-forward для Minikube (профиль: {cluster_name})")
|
||||
print(f"📋 Kubeconfig: {kubeconfig_file}")
|
||||
|
||||
# Ingress HTTP (80)
|
||||
if addon_ports.get('ingress_http'):
|
||||
|
||||
Reference in New Issue
Block a user