feat: добавить обработку таймаутов и пропуск нездоровых контейнеров
- Добавлена функция пропуска контейнеров с проблемными health check - Добавлены таймауты для предотвращения зависания приложения - Добавлены переменные окружения для настройки таймаутов - Улучшена обработка ошибок при получении информации о контейнерах - Добавлено подробное логирование проблемных контейнеров Автор: Сергей Антропов Сайт: https://devops.org.ru
This commit is contained in:
parent
e2d532c1f5
commit
9239925206
116
app.py
116
app.py
@ -17,6 +17,10 @@ DEFAULT_TAIL = int(os.getenv("LOGBOARD_TAIL", "500"))
|
||||
BASIC_USER = os.getenv("LOGBOARD_USER", "admin")
|
||||
BASIC_PASS = os.getenv("LOGBOARD_PASS", "admin")
|
||||
DEFAULT_PROJECT = os.getenv("COMPOSE_PROJECT_NAME") # filter by compose project
|
||||
SKIP_UNHEALTHY = os.getenv("LOGBOARD_SKIP_UNHEALTHY", "true").lower() == "true"
|
||||
CONTAINER_LIST_TIMEOUT = int(os.getenv("LOGBOARD_CONTAINER_LIST_TIMEOUT", "10"))
|
||||
CONTAINER_INFO_TIMEOUT = int(os.getenv("LOGBOARD_CONTAINER_INFO_TIMEOUT", "3"))
|
||||
HEALTH_CHECK_TIMEOUT = int(os.getenv("LOGBOARD_HEALTH_CHECK_TIMEOUT", "2"))
|
||||
|
||||
security = HTTPBasic()
|
||||
app = FastAPI(title="LogBoard+")
|
||||
@ -48,21 +52,105 @@ def verify_ws_token(token: str) -> bool:
|
||||
|
||||
# ---------- DOCKER HELPERS ----------
|
||||
def list_containers(project: Optional[str] = None, include_stopped: bool = False) -> List[Dict]:
|
||||
"""
|
||||
Получает список контейнеров, пропуская контейнеры с проблемными health check
|
||||
Автор: Сергей Антропов
|
||||
Сайт: https://devops.org.ru
|
||||
"""
|
||||
import signal
|
||||
import time
|
||||
|
||||
items = []
|
||||
for c in docker_client.containers.list(all=include_stopped):
|
||||
labels = c.labels or {}
|
||||
proj = labels.get("com.docker.compose.project")
|
||||
svc = labels.get("com.docker.compose.service") or c.name
|
||||
if project and proj != project:
|
||||
continue
|
||||
items.append({
|
||||
"id": c.id[:12],
|
||||
"name": c.name,
|
||||
"image": (c.image.tags[0] if c.image and c.image.tags else c.image.short_id),
|
||||
"status": c.status,
|
||||
"service": svc,
|
||||
"project": proj,
|
||||
})
|
||||
|
||||
# Функция для обработки таймаута
|
||||
def timeout_handler(signum, frame):
|
||||
raise TimeoutError("Timeout getting container list")
|
||||
|
||||
try:
|
||||
# Устанавливаем таймаут на получение списка контейнеров
|
||||
signal.signal(signal.SIGALRM, timeout_handler)
|
||||
signal.alarm(CONTAINER_LIST_TIMEOUT)
|
||||
|
||||
# Получаем список контейнеров с обработкой ошибок
|
||||
containers = []
|
||||
try:
|
||||
containers = docker_client.containers.list(all=include_stopped)
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка получения списка контейнеров: {e}")
|
||||
return []
|
||||
|
||||
for c in containers:
|
||||
try:
|
||||
# Проверяем health status контейнера с таймаутом
|
||||
health_status = None
|
||||
try:
|
||||
# Устанавливаем таймаут на получение health status
|
||||
signal.alarm(HEALTH_CHECK_TIMEOUT)
|
||||
health_status = c.attrs.get("State", {}).get("Health", {}).get("Status")
|
||||
signal.alarm(0) # Отменяем таймаут
|
||||
except TimeoutError:
|
||||
print(f"⚠️ Таймаут при получении health status для контейнера {c.name} (ID: {c.id[:12]})")
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"⚠️ Пропускаем контейнер {c.name} (ID: {c.id[:12]}): не удается получить health status - {e}")
|
||||
continue
|
||||
|
||||
# Пропускаем контейнеры с проблемными health check (если включено)
|
||||
if SKIP_UNHEALTHY and health_status == "unhealthy":
|
||||
print(f"⚠️ Пропускаем нездоровый контейнер {c.name} (ID: {c.id[:12]})")
|
||||
continue
|
||||
|
||||
# Получаем информацию о контейнере с таймаутом
|
||||
try:
|
||||
signal.alarm(CONTAINER_INFO_TIMEOUT)
|
||||
labels = c.labels or {}
|
||||
proj = labels.get("com.docker.compose.project")
|
||||
svc = labels.get("com.docker.compose.service") or c.name
|
||||
signal.alarm(0)
|
||||
except TimeoutError:
|
||||
print(f"⚠️ Таймаут при получении меток контейнера {c.name} (ID: {c.id[:12]})")
|
||||
continue
|
||||
|
||||
if project and proj != project:
|
||||
continue
|
||||
|
||||
# Получаем информацию об образе с таймаутом
|
||||
try:
|
||||
signal.alarm(HEALTH_CHECK_TIMEOUT)
|
||||
image_info = c.image.tags[0] if c.image and c.image.tags else c.image.short_id
|
||||
signal.alarm(0)
|
||||
except TimeoutError:
|
||||
print(f"⚠️ Таймаут при получении информации об образе для контейнера {c.name} (ID: {c.id[:12]})")
|
||||
image_info = "unknown"
|
||||
except Exception:
|
||||
image_info = "unknown"
|
||||
|
||||
items.append({
|
||||
"id": c.id[:12],
|
||||
"name": c.name,
|
||||
"image": image_info,
|
||||
"status": c.status,
|
||||
"service": svc,
|
||||
"project": proj,
|
||||
"health": health_status,
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
# Пропускаем контейнеры, которые вызывают ошибки
|
||||
print(f"⚠️ Пропускаем проблемный контейнер {c.name if hasattr(c, 'name') else 'unknown'} (ID: {c.id[:12]}): {e}")
|
||||
continue
|
||||
|
||||
signal.alarm(0) # Отменяем таймаут
|
||||
|
||||
except TimeoutError:
|
||||
print("❌ Таймаут при получении списка контейнеров")
|
||||
signal.alarm(0)
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"❌ Критическая ошибка при получении списка контейнеров: {e}")
|
||||
signal.alarm(0)
|
||||
return []
|
||||
|
||||
items.sort(key=lambda x: (x.get("project") or "", x.get("service") or "", x.get("name") or ""))
|
||||
return items
|
||||
|
||||
|
@ -48,6 +48,15 @@ MAX_CONNECTIONS=100
|
||||
CONNECTION_TIMEOUT=30
|
||||
READ_TIMEOUT=60
|
||||
|
||||
# Настройки фильтрации контейнеров
|
||||
# Пропускать контейнеры с проблемными health check (true/false)
|
||||
LOGBOARD_SKIP_UNHEALTHY=true
|
||||
|
||||
# Настройки таймаутов (в секундах)
|
||||
LOGBOARD_CONTAINER_LIST_TIMEOUT=10
|
||||
LOGBOARD_CONTAINER_INFO_TIMEOUT=3
|
||||
LOGBOARD_HEALTH_CHECK_TIMEOUT=2
|
||||
|
||||
# Настройки аутентификации
|
||||
AUTH_ENABLED=true
|
||||
AUTH_METHOD=basic
|
||||
|
Loading…
x
Reference in New Issue
Block a user