- Добавлена функция сворачивания/разворачивания секций локальных и удаленных контейнеров - Реализовано периодическое обновление списка контейнеров каждые 30 секунд - Добавлена автоматическая фильтрация остановленных контейнеров - Обновлены обработчики событий для корректной работы в свернутом sidebar - Добавлены функции обновления счетчиков контейнеров - Обновлена документация с описанием новых функций - Добавлены тестовые скрипты для проверки функциональности Автор: Сергей Антропов Сайт: https://devops.org.ru
368 lines
13 KiB
Markdown
368 lines
13 KiB
Markdown
# 🌐 Удаленные клиенты LogBoard+
|
||
|
||
## Обзор
|
||
|
||
LogBoard+ поддерживает сбор логов с удаленных серверов через специальные клиенты. Это позволяет централизованно мониторить логи контейнеров с нескольких машин.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
┌─────────────────┐ HTTP API ┌─────────────────┐
|
||
│ Удаленный │ ──────────────► │ LogBoard+ │
|
||
│ сервер │ │ Сервер │
|
||
│ │ │ │
|
||
│ ┌─────────────┐ │ │ ┌─────────────┐ │
|
||
│ │ Клиент │ │ │ │ Web UI │ │
|
||
│ │ LogBoard+ │ │ │ │ │ │
|
||
│ └─────────────┘ │ │ └─────────────┘ │
|
||
└─────────────────┘ └─────────────────┘
|
||
```
|
||
|
||
## Компоненты
|
||
|
||
### 1. Серверная часть (LogBoard+ Server)
|
||
|
||
- **API эндпоинты**: Прием логов от удаленных клиентов
|
||
- **Хранение логов**: Сохранение в файловой системе
|
||
- **Web интерфейс**: Отображение локальных и удаленных контейнеров
|
||
- **Визуальное разделение**: Четкое различие между локальными и удаленными контейнерами
|
||
|
||
### 2. Клиентская часть (LogBoard+ Client)
|
||
|
||
- **Сбор логов**: Чтение логов Docker контейнеров
|
||
- **Отправка данных**: HTTP POST запросы на сервер
|
||
- **Автоматизация**: Docker Compose для простого развертывания
|
||
|
||
## Установка и настройка
|
||
|
||
### На сервере LogBoard+
|
||
|
||
1. Убедитесь, что сервер LogBoard+ запущен и доступен
|
||
2. Получите API ключ для аутентификации клиентов
|
||
|
||
### На удаленном сервере
|
||
|
||
1. Создайте директорию для клиента:
|
||
```bash
|
||
mkdir logboard-client
|
||
cd logboard-client
|
||
```
|
||
|
||
2. Создайте `docker-compose.yml`:
|
||
```yaml
|
||
version: '3.8'
|
||
|
||
services:
|
||
logboard-client:
|
||
build: .
|
||
container_name: logboard-client
|
||
environment:
|
||
- LOGBOARD_SERVER_URL=http://your-logboard-server:9001
|
||
- API_KEY=your-api-key
|
||
- HOSTNAME=your-server-name
|
||
volumes:
|
||
- /var/run/docker.sock:/var/run/docker.sock
|
||
- ./logs:/app/logs
|
||
restart: unless-stopped
|
||
user: 0:0
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
|
||
# Тестовый контейнер для демонстрации
|
||
test-nginx:
|
||
image: nginx:alpine
|
||
container_name: test-nginx
|
||
ports:
|
||
- "8080:80"
|
||
restart: unless-stopped
|
||
```
|
||
|
||
3. Создайте `Dockerfile`:
|
||
```dockerfile
|
||
FROM python:3.11-slim
|
||
|
||
RUN apt-get update && apt-get install -y \
|
||
curl \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
RUN groupadd -r logboard && useradd -r -g logboard logboard
|
||
|
||
RUN mkdir -p /app /var/log
|
||
|
||
WORKDIR /app
|
||
|
||
COPY requirements.txt .
|
||
RUN pip install --no-cache-dir -r requirements.txt
|
||
|
||
COPY app/ ./app/
|
||
|
||
RUN mkdir -p /var/log && \
|
||
chown -R logboard:logboard /app /var/log
|
||
|
||
USER logboard
|
||
|
||
CMD ["python", "app/main.py"]
|
||
```
|
||
|
||
4. Создайте `requirements.txt`:
|
||
```
|
||
aiohttp==3.9.1
|
||
docker==6.1.3
|
||
urllib3==2.1.0
|
||
requests==2.31.0
|
||
```
|
||
|
||
5. Создайте `app/main.py`:
|
||
```python
|
||
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
LogBoard+ Client - Клиент для отправки логов на сервер LogBoard+
|
||
Автор: Сергей Антропов
|
||
Сайт: https://devops.org.ru
|
||
"""
|
||
|
||
import asyncio
|
||
import aiohttp
|
||
import docker
|
||
import os
|
||
import logging
|
||
from datetime import datetime
|
||
|
||
# Настройка логирования
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||
)
|
||
logger = logging.getLogger(__name__)
|
||
|
||
class LogBoardClient:
|
||
def __init__(self):
|
||
self.server_url = os.getenv('LOGBOARD_SERVER_URL', 'http://localhost:9001')
|
||
self.api_key = os.getenv('API_KEY', 'default-key')
|
||
self.hostname = os.getenv('HOSTNAME', 'unknown')
|
||
|
||
# Инициализация Docker клиента
|
||
try:
|
||
self.docker_client = docker.from_env()
|
||
logger.info("Docker клиент инициализирован успешно")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка инициализации Docker клиента: {e}")
|
||
self.docker_client = None
|
||
|
||
async def send_logs(self, container_name, logs_data):
|
||
"""Отправка логов на сервер LogBoard+"""
|
||
try:
|
||
async with aiohttp.ClientSession() as session:
|
||
url = f"{self.server_url}/api/logs/remote"
|
||
data = {
|
||
'container_name': container_name,
|
||
'hostname': self.hostname,
|
||
'logs': logs_data,
|
||
'api_key': self.api_key
|
||
}
|
||
|
||
async with session.post(url, json=data) as response:
|
||
if response.status == 200:
|
||
logger.info(f"Логи контейнера {container_name} отправлены успешно")
|
||
else:
|
||
logger.error(f"Ошибка отправки логов: {response.status}")
|
||
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при отправке логов: {e}")
|
||
|
||
def get_container_logs(self, container_name, tail=100):
|
||
"""Получение логов контейнера"""
|
||
try:
|
||
if not self.docker_client:
|
||
return []
|
||
|
||
container = self.docker_client.containers.get(container_name)
|
||
logs = container.logs(tail=tail, timestamps=True).decode('utf-8')
|
||
return logs.split('\n')[:-1] # Убираем пустую строку в конце
|
||
|
||
except Exception as e:
|
||
logger.error(f"Ошибка получения логов контейнера {container_name}: {e}")
|
||
return []
|
||
|
||
async def collect_and_send_logs(self):
|
||
"""Сбор и отправка логов всех контейнеров"""
|
||
try:
|
||
if not self.docker_client:
|
||
logger.error("Docker клиент недоступен")
|
||
return
|
||
|
||
containers = self.docker_client.containers.list()
|
||
logger.info(f"Найдено {len(containers)} контейнеров")
|
||
|
||
for container in containers:
|
||
try:
|
||
logs = self.get_container_logs(container.name)
|
||
if logs:
|
||
await self.send_logs(container.name, logs)
|
||
except Exception as e:
|
||
logger.error(f"Ошибка обработки контейнера {container.name}: {e}")
|
||
|
||
except Exception as e:
|
||
logger.error(f"Ошибка сбора логов: {e}")
|
||
|
||
async def run(self):
|
||
"""Основной цикл работы клиента"""
|
||
logger.info(f"LogBoard+ Client запущен для хоста: {self.hostname}")
|
||
logger.info(f"Сервер: {self.server_url}")
|
||
|
||
while True:
|
||
try:
|
||
await self.collect_and_send_logs()
|
||
await asyncio.sleep(30) # Пауза 30 секунд
|
||
except Exception as e:
|
||
logger.error(f"Критическая ошибка: {e}")
|
||
await asyncio.sleep(60) # Увеличенная пауза при ошибке
|
||
|
||
async def main():
|
||
client = LogBoardClient()
|
||
await client.run()
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main())
|
||
```
|
||
|
||
6. Запустите клиент:
|
||
```bash
|
||
docker-compose up -d
|
||
```
|
||
|
||
## Использование
|
||
|
||
### Web интерфейс
|
||
|
||
После настройки клиентов, в веб-интерфейсе LogBoard+ вы увидите:
|
||
|
||
#### 📍 Локальные контейнеры
|
||
- Контейнеры с текущего сервера
|
||
- Обычное отображение без дополнительных индикаторов
|
||
|
||
#### 🌐 Удаленные контейнеры
|
||
- Контейнеры с удаленных серверов
|
||
- Визуальное разделение по хостам
|
||
- Индикаторы удаленного доступа (глобус 🌐)
|
||
- Время последнего обновления
|
||
- Статистика по хостам
|
||
|
||
### Функции интерфейса
|
||
|
||
#### 🔽 Сворачивание секций
|
||
- **Секции контейнеров**: Можно сворачивать/разворачивать секции "Локальные контейнеры" и "Удаленные контейнеры"
|
||
- **Секции хостов**: Каждый хост в удаленных контейнерах можно сворачивать отдельно
|
||
- **Кнопки управления**: Стрелки для сворачивания/разворачивания
|
||
- **Сохранение состояния**: Состояние сворачивания сохраняется между сессиями
|
||
|
||
#### ⚡ Периодическое обновление
|
||
- **Автоматическое обновление**: Список контейнеров обновляется каждые 30 секунд
|
||
- **Фильтрация остановленных**: Остановленные контейнеры автоматически скрываются из интерфейса
|
||
- **Обновление счетчиков**: Количество контейнеров в секциях обновляется в реальном времени
|
||
- **Логирование изменений**: В консоли браузера отображается информация об изменениях
|
||
|
||
#### 📱 Адаптивный интерфейс
|
||
- **Свернутый sidebar**: Миникарточки контейнеров с иконками статуса
|
||
- **Развернутый sidebar**: Полная информация о контейнерах с возможностью сворачивания секций
|
||
- **Мобильная поддержка**: Адаптивный дизайн для мобильных устройств
|
||
|
||
### API эндпоинты
|
||
|
||
#### Получение контейнеров
|
||
```http
|
||
GET /api/containers/services
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
**Ответ:**
|
||
```json
|
||
[
|
||
{
|
||
"id": "container-id",
|
||
"name": "container-name",
|
||
"status": "running",
|
||
"is_remote": false,
|
||
"hostname": "localhost",
|
||
"project": "project-name",
|
||
"service": "service-name"
|
||
},
|
||
{
|
||
"id": "remote-hostname-container",
|
||
"name": "remote-container",
|
||
"status": "running",
|
||
"is_remote": true,
|
||
"hostname": "remote-host",
|
||
"last_modified": "2025-08-20T16:30:00",
|
||
"size": 1024
|
||
}
|
||
]
|
||
```
|
||
|
||
#### Получение логов удаленного контейнера
|
||
```http
|
||
GET /api/logs/{container_id}
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
#### Получение статистики логов
|
||
```http
|
||
GET /api/logs/stats/{container_id}
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
## Мониторинг и отладка
|
||
|
||
### Логи клиента
|
||
```bash
|
||
docker-compose logs -f logboard-client
|
||
```
|
||
|
||
### Проверка здоровья
|
||
```bash
|
||
curl http://localhost:8080/health
|
||
```
|
||
|
||
### Тестирование API
|
||
```bash
|
||
python3 test_interface.py
|
||
```
|
||
|
||
## Безопасность
|
||
|
||
- **API ключи**: Обязательная аутентификация клиентов
|
||
- **HTTPS**: Рекомендуется использовать HTTPS для передачи данных
|
||
- **Сетевая изоляция**: Клиенты должны иметь доступ только к необходимым портам
|
||
|
||
## Устранение неполадок
|
||
|
||
### Клиент не подключается
|
||
1. Проверьте URL сервера в переменной `LOGBOARD_SERVER_URL`
|
||
2. Убедитесь, что API ключ правильный
|
||
3. Проверьте сетевое подключение
|
||
|
||
### Логи не отображаются
|
||
1. Проверьте права доступа к Docker socket
|
||
2. Убедитесь, что контейнеры запущены
|
||
3. Проверьте логи клиента
|
||
|
||
### Интерфейс не обновляется
|
||
1. Откройте консоль браузера (F12)
|
||
2. Проверьте наличие ошибок JavaScript
|
||
3. Убедитесь, что WebSocket соединения работают
|
||
|
||
## Автор
|
||
|
||
**Сергей Антропов**
|
||
🌐 Сайт: https://devops.org.ru
|
||
📧 Email: contact@devops.org.ru
|
||
|
||
---
|
||
|
||
*Документация обновлена: 2025-08-20*
|
||
|