Добавлена полная документация проекта LogBoard+

- Создан основной README.md с описанием проекта
- Добавлена подробная документация в папке docs/
- Создан файл LICENSE (MIT)
- Обновлен .gitignore
- Добавлена документация по безопасности с генерацией ключей
- Включены примеры конфигураций и устранение неполадок

Автор: Сергей Антропов
Сайт: https://devops.org.ru
This commit is contained in:
Сергей Антропов
2025-08-19 01:06:23 +03:00
parent 86a2c44333
commit 5c8efe2644
11 changed files with 4932 additions and 90 deletions

657
docs/api.md Normal file
View File

@@ -0,0 +1,657 @@
# API Документация LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Содержание
1. [Обзор API](#обзор-api)
2. [Аутентификация](#аутентификация)
3. [REST API](#rest-api)
4. [WebSocket API](#websocket-api)
5. [Коды ошибок](#коды-ошибок)
6. [Примеры использования](#примеры-использования)
## Обзор API
LogBoard+ предоставляет REST API и WebSocket API для работы с логами Docker контейнеров.
### Базовый URL
```
http://localhost:9001
```
### Форматы данных
- **Content-Type:** `application/json`
- **Кодировка:** UTF-8
- **Временные метки:** ISO 8601 (UTC)
### Аутентификация
Все API endpoints (кроме `/healthz` и `/api/auth/login`) требуют JWT токен в заголовке:
```
Authorization: Bearer <token>
```
## Аутентификация
### POST /api/auth/login
Вход в систему и получение JWT токена.
**Запрос:**
```json
{
"username": "admin",
"password": "your-password"
}
```
**Ответ:**
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
```
**Пример curl:**
```bash
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}'
```
### POST /api/auth/logout
Выход из системы (удаление токена из cookies).
**Ответ:**
```json
{
"message": "Успешный выход из системы"
}
```
### GET /api/auth/me
Получение информации о текущем пользователе.
**Заголовки:**
```
Authorization: Bearer <token>
```
**Ответ:**
```json
{
"username": "admin"
}
```
## REST API
### Контейнеры и сервисы
#### GET /api/services
Получение списка всех контейнеров.
**Параметры запроса:**
| Параметр | Тип | Описание | По умолчанию |
|----------|-----|----------|--------------|
| `projects` | string | Фильтр по проектам (через запятую) | Все проекты |
| `include_stopped` | boolean | Включить остановленные контейнеры | false |
**Пример запроса:**
```bash
curl -X GET "http://localhost:9001/api/services?projects=myproject&include_stopped=true" \
-H "Authorization: Bearer YOUR_TOKEN"
```
**Ответ:**
```json
[
{
"id": "abc123def456",
"name": "myproject_web_1",
"status": "running",
"image": "nginx:latest",
"service": "web",
"project": "myproject",
"health": "healthy",
"ports": ["80/tcp"],
"url": "http://localhost:8080",
"host_port": "8080"
},
{
"id": "def456ghi789",
"name": "myproject_db_1",
"status": "running",
"image": "postgres:13",
"service": "db",
"project": "myproject",
"health": "healthy",
"ports": ["5432/tcp"],
"url": null,
"host_port": null
}
]
```
#### GET /api/projects
Получение списка всех проектов Docker Compose.
**Ответ:**
```json
[
"myproject",
"another-project",
"standalone"
]
```
### Логи
#### GET /api/logs/{container_id}
Получение логов контейнера.
**Параметры пути:**
- `container_id` - ID контейнера (первые 12 символов)
**Параметры запроса:**
| Параметр | Тип | Описание | По умолчанию |
|----------|-----|----------|--------------|
| `tail` | string | Количество строк или 'all' | 500 |
| `since` | string | Время начала (ISO 8601 или относительное) | null |
**Пример запроса:**
```bash
curl -X GET "http://localhost:9001/api/logs/abc123def456?tail=100&since=2024-01-15T10:00:00Z" \
-H "Authorization: Bearer YOUR_TOKEN"
```
**Ответ:**
```json
{
"container": {
"id": "abc123def456",
"name": "myproject_web_1",
"status": "running",
"image": "nginx:latest",
"created": "2024-01-15T09:00:00.000000000Z",
"state": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 1234,
"ExitCode": 0,
"Error": "",
"StartedAt": "2024-01-15T09:00:00.000000000Z",
"FinishedAt": "0001-01-01T00:00:00Z"
}
},
"logs": [
{
"timestamp": "2024-01-15T10:30:15.123456789Z",
"message": "2024/01/15 10:30:15 [notice] 1#1: start worker processes",
"raw": "2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker processes"
},
{
"timestamp": "2024-01-15T10:30:15.123456789Z",
"message": "2024/01/15 10:30:15 [notice] 1#1: start worker process 1234",
"raw": "2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker process 1234"
}
],
"total_lines": 2,
"tail": "100",
"since": "2024-01-15T10:00:00Z",
"timestamp": "2024-01-15T10:30:15.123456789Z"
}
```
#### GET /api/logs/stats/{container_id}
Получение статистики логов контейнера.
**Ответ:**
```json
{
"debug": 15,
"info": 42,
"warn": 8,
"error": 3
}
```
### Управление
#### GET /api/settings
Получение настроек приложения.
**Ответ:**
```json
{
"ajax_update_interval": 2000,
"default_tail": 500,
"skip_unhealthy": true
}
```
#### GET /api/excluded-containers
Получение списка исключенных контейнеров.
**Ответ:**
```json
{
"excluded_containers": [
"noisy-container-1",
"noisy-container-2"
]
}
```
#### POST /api/excluded-containers
Обновление списка исключенных контейнеров.
**Запрос:**
```json
[
"noisy-container-1",
"noisy-container-2",
"another-noisy-container"
]
```
**Ответ:**
```json
{
"status": "success",
"message": "Список исключенных контейнеров обновлен"
}
```
#### POST /api/snapshot
Создание снимка логов.
**Запрос:**
```json
{
"container_id": "abc123def456",
"service": "web",
"content": "Логи контейнера..."
}
```
**Ответ:**
```json
{
"file": "web-20240115-103015.log",
"url": "/snapshots/web-20240115-103015.log"
}
```
### Системные
#### GET /healthz
Health check endpoint.
**Ответ:**
```
ok
```
## WebSocket API
### Подключение
Все WebSocket endpoints требуют JWT токен в параметре `token`.
### ws://host:port/ws/logs/{container_id}
Получение логов отдельного контейнера.
**Параметры:**
- `container_id` - ID контейнера
- `tail` - Количество строк (по умолчанию 500)
- `token` - JWT токен
- `service` - Имя сервиса (опционально)
- `project` - Имя проекта (опционально)
**Пример подключения:**
```javascript
const token = "your-jwt-token";
const containerId = "abc123def456";
const ws = new WebSocket(`ws://localhost:9001/ws/logs/${containerId}?token=${token}&tail=100`);
ws.onmessage = function(event) {
console.log('Получены логи:', event.data);
};
ws.onerror = function(error) {
console.error('WebSocket ошибка:', error);
};
```
### ws://host:port/ws/fan/{service_name}
Получение логов сервиса (все реплики).
**Параметры:**
- `service_name` - Имя сервиса Docker Compose
- `tail` - Количество строк (по умолчанию 500)
- `token` - JWT токен
- `project` - Имя проекта (опционально)
**Пример подключения:**
```javascript
const token = "your-jwt-token";
const serviceName = "web";
const ws = new WebSocket(`ws://localhost:9001/ws/fan/${serviceName}?token=${token}&tail=100`);
ws.onmessage = function(event) {
console.log('Логи сервиса:', event.data);
};
```
### ws://host:port/ws/fan_group
Получение логов группы сервисов.
**Параметры:**
- `services` - Имена сервисов через запятую
- `tail` - Количество строк (по умолчанию 500)
- `token` - JWT токен
- `project` - Имя проекта (опционально)
**Пример подключения:**
```javascript
const token = "your-jwt-token";
const services = "web,db,redis";
const ws = new WebSocket(`ws://localhost:9001/ws/fan_group?services=${services}&token=${token}&tail=100`);
ws.onmessage = function(event) {
console.log('Логи группы сервисов:', event.data);
};
```
## Коды ошибок
### HTTP коды состояния
| Код | Описание |
|-----|----------|
| 200 | Успешный запрос |
| 400 | Неверный запрос |
| 401 | Не авторизован |
| 403 | Доступ запрещен |
| 404 | Ресурс не найден |
| 500 | Внутренняя ошибка сервера |
### Формат ошибок
```json
{
"error": "error_type",
"message": "Описание ошибки",
"details": "Дополнительная информация"
}
```
### Примеры ошибок
#### 401 Unauthorized
```json
{
"error": "unauthorized",
"message": "Требуется авторизация",
"details": "Для доступа к этому API необходимо войти в систему."
}
```
#### 404 Not Found
```json
{
"error": "http_404",
"message": "Контейнер не найден",
"details": "URL: /api/logs/invalid-id"
}
```
#### 500 Internal Server Error
```json
{
"error": "http_500",
"message": "Ошибка подключения к Docker",
"details": "URL: /api/services"
}
```
## Примеры использования
### Python
```python
import requests
import json
# Базовый URL
BASE_URL = "http://localhost:9001"
# Аутентификация
def login(username, password):
response = requests.post(f"{BASE_URL}/api/auth/login", json={
"username": username,
"password": password
})
return response.json()["access_token"]
# Получение списка контейнеров
def get_containers(token):
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(f"{BASE_URL}/api/services", headers=headers)
return response.json()
# Получение логов контейнера
def get_logs(token, container_id, tail=100):
headers = {"Authorization": f"Bearer {token}"}
params = {"tail": tail}
response = requests.get(f"{BASE_URL}/api/logs/{container_id}",
headers=headers, params=params)
return response.json()
# Использование
token = login("admin", "your-password")
containers = get_containers(token)
print(f"Найдено контейнеров: {len(containers)}")
for container in containers:
logs = get_logs(token, container["id"], tail=10)
print(f"Контейнер {container['name']}: {len(logs['logs'])} строк логов")
```
### JavaScript
```javascript
// Класс для работы с LogBoard+ API
class LogBoardAPI {
constructor(baseUrl, token) {
this.baseUrl = baseUrl;
this.token = token;
this.headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
}
// Получение списка контейнеров
async getContainers(projects = null, includeStopped = false) {
const params = new URLSearchParams();
if (projects) params.append('projects', projects);
if (includeStopped) params.append('include_stopped', 'true');
const response = await fetch(`${this.baseUrl}/api/services?${params}`, {
headers: this.headers
});
return await response.json();
}
// Получение логов контейнера
async getLogs(containerId, tail = 100, since = null) {
const params = new URLSearchParams();
params.append('tail', tail);
if (since) params.append('since', since);
const response = await fetch(`${this.baseUrl}/api/logs/${containerId}?${params}`, {
headers: this.headers
});
return await response.json();
}
// Получение статистики логов
async getLogStats(containerId) {
const response = await fetch(`${this.baseUrl}/api/logs/stats/${containerId}`, {
headers: this.headers
});
return await response.json();
}
// WebSocket для live-логов
createLogsWebSocket(containerId, tail = 100) {
const ws = new WebSocket(
`ws://${this.baseUrl.replace('http://', '')}/ws/logs/${containerId}?token=${this.token}&tail=${tail}`
);
return ws;
}
}
// Использование
async function main() {
// Получение токена
const loginResponse = await fetch('http://localhost:9001/api/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: 'admin',
password: 'your-password'
})
});
const {access_token} = await loginResponse.json();
// Создание API клиента
const api = new LogBoardAPI('http://localhost:9001', access_token);
// Получение контейнеров
const containers = await api.getContainers();
console.log('Контейнеры:', containers);
// Получение логов первого контейнера
if (containers.length > 0) {
const logs = await api.getLogs(containers[0].id, 50);
console.log('Логи:', logs);
// WebSocket для live-логов
const ws = api.createLogsWebSocket(containers[0].id, 100);
ws.onmessage = (event) => {
console.log('Новые логи:', event.data);
};
}
}
main().catch(console.error);
```
### cURL
```bash
#!/bin/bash
# Переменные
BASE_URL="http://localhost:9001"
USERNAME="admin"
PASSWORD="your-password"
# Получение токена
TOKEN=$(curl -s -X POST "$BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}" \
| jq -r '.access_token')
echo "Токен получен: ${TOKEN:0:20}..."
# Получение списка контейнеров
echo "Получение списка контейнеров..."
curl -s -X GET "$BASE_URL/api/services" \
-H "Authorization: Bearer $TOKEN" \
| jq '.[] | {name: .name, status: .status, project: .project}'
# Получение логов первого контейнера
CONTAINER_ID=$(curl -s -X GET "$BASE_URL/api/services" \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.[0].id')
echo "Получение логов контейнера $CONTAINER_ID..."
curl -s -X GET "$BASE_URL/api/logs/$CONTAINER_ID?tail=10" \
-H "Authorization: Bearer $TOKEN" \
| jq '.logs[] | .message'
```
## Ограничения и рекомендации
### Ограничения
- Максимальное количество строк логов: 10000
- Таймаут WebSocket соединения: 60 секунд
- Максимальный размер снимка логов: 10 MB
### Рекомендации
1. **Используйте фильтрацию по времени** для больших объемов логов
2. **Настройте исключение контейнеров** с избыточным логированием
3. **Используйте WebSocket** для real-time мониторинга
4. **Регулярно очищайте снимки логов** для экономии места
### Производительность
- REST API: до 1000 запросов в минуту
- WebSocket: до 100 одновременных соединений
- Размер ответа: до 1 MB на запрос

503
docs/configuration.md Normal file
View File

@@ -0,0 +1,503 @@
# Конфигурация LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Содержание
1. [Обзор конфигурации](#обзор-конфигурации)
2. [Переменные окружения](#переменные-окружения)
3. [Настройка Docker](#настройка-docker)
4. [Настройка безопасности](#настройка-безопасности)
5. [Настройка производительности](#настройка-производительности)
6. [Настройка логирования](#настройка-логирования)
7. [Примеры конфигураций](#примеры-конфигураций)
## Обзор конфигурации
LogBoard+ использует переменные окружения для настройки всех аспектов работы приложения. Конфигурация разделена на несколько категорий для удобства управления.
### Файлы конфигурации
- `.env` - Основной файл конфигурации (создается из `env.example`)
- `docker-compose.yml` - Конфигурация Docker Compose
- `excluded_containers.json` - Список исключенных контейнеров
### Приоритет настроек
1. Переменные окружения системы
2. Файл `.env`
3. Значения по умолчанию в коде
## Переменные окружения
### Основные настройки приложения
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `LOGBOARD_PORT` | Порт веб-интерфейса | `9001` | Нет |
| `LOGBOARD_TAIL` | Количество строк логов по умолчанию | `500` | Нет |
| `LOGBOARD_USER` | Имя пользователя для входа | `admin` | Нет |
| `LOGBOARD_PASS` | Пароль пользователя | `admin` | Да |
| `LOGBOARD_SNAPSHOT_DIR` | Директория для снимков логов | `/app/snapshots` | Нет |
| `LOGBOARD_INDEX_HTML` | Путь к HTML шаблону | `./templates/index.html` | Нет |
| `TZ_TS` | Временная зона | `Europe/Moscow` | Нет |
### Настройки Docker
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `COMPOSE_PROJECT_NAME` | Фильтр по проекту Docker Compose | - | Нет |
| `LOGBOARD_PROJECTS` | Множественные проекты (через запятую) | - | Нет |
| `DOCKER_HOST` | Путь к Docker socket | `unix:///var/run/docker.sock` | Нет |
| `DOCKER_TLS_VERIFY` | Проверка TLS для Docker | - | Нет |
| `DOCKER_CERT_PATH` | Путь к сертификатам Docker | - | Нет |
| `DOCKER_NETWORKS` | Внешние сети Docker | `iaas,infrastructure_iaas` | Нет |
### Настройки безопасности
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `SECRET_KEY` | Секретный ключ для JWT | `your-secret-key-here` | Да |
| `ENCRYPTION_KEY` | Ключ шифрования | `your-encryption-key-here` | Да |
| `AUTH_ENABLED` | Включить аутентификацию | `true` | Нет |
| `AUTH_METHOD` | Метод аутентификации | `jwt` | Нет |
| `SESSION_TIMEOUT` | Время жизни сессии (секунды) | `3600` | Нет |
### Настройки производительности
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `MAX_CONNECTIONS` | Максимальное количество соединений | `100` | Нет |
| `CONNECTION_TIMEOUT` | Таймаут подключения (секунды) | `30` | Нет |
| `READ_TIMEOUT` | Таймаут чтения (секунды) | `60` | Нет |
| `LOGBOARD_AJAX_UPDATE_INTERVAL` | Интервал AJAX обновления (мс) | `2000` | Нет |
### Настройки фильтрации контейнеров
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `LOGBOARD_SKIP_UNHEALTHY` | Пропускать нездоровые контейнеры | `true` | Нет |
| `LOGBOARD_CONTAINER_LIST_TIMEOUT` | Таймаут получения списка контейнеров | `10` | Нет |
| `LOGBOARD_CONTAINER_INFO_TIMEOUT` | Таймаут получения информации о контейнере | `3` | Нет |
| `LOGBOARD_HEALTH_CHECK_TIMEOUT` | Таймаут health check | `2` | Нет |
### Настройки логирования
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `LOG_LEVEL` | Уровень логирования | `INFO` | Нет |
| `LOG_FORMAT` | Формат логов | `json` | Нет |
### Настройки веб-интерфейса
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `WEB_TITLE` | Заголовок веб-интерфейса | `LogBoard+` | Нет |
| `WEB_DESCRIPTION` | Описание веб-интерфейса | `Веб-панель для просмотра логов микросервисов` | Нет |
| `WEB_VERSION` | Версия веб-интерфейса | `1.0.0` | Нет |
### Настройки уведомлений
| Переменная | Описание | По умолчанию | Обязательная |
|------------|----------|--------------|--------------|
| `NOTIFICATIONS_ENABLED` | Включить уведомления | `false` | Нет |
| `SMTP_HOST` | SMTP сервер | - | Нет |
| `SMTP_PORT` | Порт SMTP | `587` | Нет |
| `SMTP_USER` | Пользователь SMTP | - | Нет |
| `SMTP_PASS` | Пароль SMTP | - | Нет |
| `SMTP_FROM` | Email отправителя | - | Нет |
## Настройка Docker
### Подключение к Docker daemon
#### Локальный Docker
```bash
# Стандартная конфигурация для локального Docker
DOCKER_HOST=unix:///var/run/docker.sock
```
#### Удаленный Docker
```bash
# Подключение к удаленному Docker daemon
DOCKER_HOST=tcp://192.168.1.100:2375
# С TLS сертификатами
DOCKER_HOST=tcp://192.168.1.100:2376
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/path/to/certs
```
### Фильтрация проектов
#### Один проект
```bash
# Показать только контейнеры из одного проекта
COMPOSE_PROJECT_NAME=myproject
```
#### Несколько проектов
```bash
# Показать контейнеры из нескольких проектов
LOGBOARD_PROJECTS=project1,project2,project3
```
#### Все проекты
```bash
# Показать все контейнеры (по умолчанию)
# Оставьте переменные пустыми или не указывайте их
```
### Настройка сетей
```bash
# Подключение к внешним Docker сетям
DOCKER_NETWORKS=iaas,infrastructure_iaas,frontend,backend
```
## Настройка безопасности
### Генерация секретных ключей
```bash
# Генерация секретного ключа для JWT
openssl rand -hex 32
# 8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
# Генерация ключа шифрования
openssl rand -hex 32
# 1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
```
### Настройка аутентификации
```bash
# Включение аутентификации
AUTH_ENABLED=true
AUTH_METHOD=jwt
# Настройка времени жизни сессии (1 час)
SESSION_TIMEOUT=3600
# Настройка пользователей
LOGBOARD_USER=admin
LOGBOARD_PASS=your-secure-password
```
### Настройка HTTPS
Для продакшена рекомендуется использовать HTTPS через reverse proxy:
```nginx
# Nginx конфигурация
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
location / {
proxy_pass http://localhost:9001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket поддержка
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
## Настройка производительности
### Ограничения соединений
```bash
# Максимальное количество одновременных подключений
MAX_CONNECTIONS=100
# Таймауты
CONNECTION_TIMEOUT=30
READ_TIMEOUT=60
```
### Настройка AJAX обновления
```bash
# Интервал обновления логов (в миллисекундах)
LOGBOARD_AJAX_UPDATE_INTERVAL=2000
# Количество строк логов по умолчанию
LOGBOARD_TAIL=500
```
### Оптимизация Docker
```bash
# Таймауты для операций с Docker
LOGBOARD_CONTAINER_LIST_TIMEOUT=10
LOGBOARD_CONTAINER_INFO_TIMEOUT=3
LOGBOARD_HEALTH_CHECK_TIMEOUT=2
# Пропуск нездоровых контейнеров
LOGBOARD_SKIP_UNHEALTHY=true
```
## Настройка логирования
### Уровни логирования
```bash
# Доступные уровни: DEBUG, INFO, WARNING, ERROR
LOG_LEVEL=INFO
# Форматы: json, text
LOG_FORMAT=json
```
### Настройка логов приложения
```bash
# Создание директории для логов
sudo mkdir -p /var/log/logboard
sudo chown $USER:$USER /var/log/logboard
# Обновление docker-compose.yml
volumes:
- /var/log/logboard:/app/logs
```
## Исключение контейнеров
### Файл excluded_containers.json
```json
{
"excluded_containers": [
"noisy-container-1",
"noisy-container-2",
"debug-container",
"test-container"
],
"description": "Контейнеры с избыточным логированием, исключенные из отображения"
}
```
### Управление через API
```bash
# Получение списка исключенных контейнеров
curl -X GET "http://localhost:9001/api/excluded-containers" \
-H "Authorization: Bearer YOUR_TOKEN"
# Обновление списка
curl -X POST "http://localhost:9001/api/excluded-containers" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '["container1", "container2"]'
```
## Примеры конфигураций
### Разработка
```bash
# .env для разработки
LOGBOARD_PORT=9001
LOGBOARD_USER=admin
LOGBOARD_PASS=dev-password
SECRET_KEY=dev-secret-key-change-in-production
ENCRYPTION_KEY=dev-encryption-key-change-in-production
# Docker настройки
DOCKER_HOST=unix:///var/run/docker.sock
LOGBOARD_PROJECTS=dev-project
# Производительность
LOGBOARD_TAIL=100
LOGBOARD_AJAX_UPDATE_INTERVAL=1000
LOG_LEVEL=DEBUG
# Безопасность
AUTH_ENABLED=true
SESSION_TIMEOUT=7200
```
### Тестирование
```bash
# .env для тестирования
LOGBOARD_PORT=9002
LOGBOARD_USER=test
LOGBOARD_PASS=test-password
SECRET_KEY=test-secret-key
ENCRYPTION_KEY=test-encryption-key
# Docker настройки
DOCKER_HOST=unix:///var/run/docker.sock
LOGBOARD_PROJECTS=test-project
# Производительность
LOGBOARD_TAIL=50
LOGBOARD_AJAX_UPDATE_INTERVAL=500
LOG_LEVEL=INFO
# Безопасность
AUTH_ENABLED=true
SESSION_TIMEOUT=1800
```
### Продакшен
```bash
# .env для продакшена
LOGBOARD_PORT=9001
LOGBOARD_USER=admin
LOGBOARD_PASS=very-secure-password-here
SECRET_KEY=8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
ENCRYPTION_KEY=1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
# Docker настройки
DOCKER_HOST=unix:///var/run/docker.sock
LOGBOARD_PROJECTS=prod-project,monitoring
# Производительность
LOGBOARD_TAIL=1000
LOGBOARD_AJAX_UPDATE_INTERVAL=5000
MAX_CONNECTIONS=200
CONNECTION_TIMEOUT=60
READ_TIMEOUT=120
# Безопасность
AUTH_ENABLED=true
SESSION_TIMEOUT=3600
# Логирование
LOG_LEVEL=WARNING
LOG_FORMAT=json
# Уведомления
NOTIFICATIONS_ENABLED=true
SMTP_HOST=smtp.company.com
SMTP_PORT=587
SMTP_USER=logboard@company.com
SMTP_PASS=email-password
SMTP_FROM=logboard@company.com
```
### Масштабированная установка
```bash
# .env для масштабированной установки
LOGBOARD_PORT=9001
LOGBOARD_USER=admin
LOGBOARD_PASS=very-secure-password
SECRET_KEY=8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
ENCRYPTION_KEY=1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
# Docker настройки
DOCKER_HOST=tcp://docker-swarm-manager:2376
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/etc/docker/certs
LOGBOARD_PROJECTS=app1,app2,app3,monitoring
# Производительность
LOGBOARD_TAIL=2000
LOGBOARD_AJAX_UPDATE_INTERVAL=3000
MAX_CONNECTIONS=500
CONNECTION_TIMEOUT=120
READ_TIMEOUT=300
# Безопасность
AUTH_ENABLED=true
SESSION_TIMEOUT=7200
# Логирование
LOG_LEVEL=INFO
LOG_FORMAT=json
# Уведомления
NOTIFICATIONS_ENABLED=true
SMTP_HOST=smtp.company.com
SMTP_PORT=587
SMTP_USER=logboard@company.com
SMTP_PASS=email-password
SMTP_FROM=logboard@company.com
```
## Проверка конфигурации
### Валидация переменных окружения
```bash
# Проверка конфигурации
make env-check
# Проверка Docker Compose
make validate
```
### Тестирование подключения
```bash
# Проверка подключения к Docker
docker ps
# Проверка доступности API
curl http://localhost:9001/healthz
# Проверка аутентификации
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}'
```
### Мониторинг конфигурации
```bash
# Просмотр текущих настроек
curl -X GET "http://localhost:9001/api/settings" \
-H "Authorization: Bearer YOUR_TOKEN"
# Проверка списка контейнеров
curl -X GET "http://localhost:9001/api/services" \
-H "Authorization: Bearer YOUR_TOKEN"
```
## Рекомендации по безопасности
### Обязательные настройки для продакшена
1. **Измените пароли по умолчанию**
2. **Используйте сильные секретные ключи**
3. **Настройте HTTPS через reverse proxy**
4. **Ограничьте доступ к Docker socket**
5. **Настройте файрвол**
6. **Регулярно обновляйте зависимости**
7. **Мониторьте логи доступа**
### Мониторинг безопасности
```bash
# Проверка прав доступа к Docker socket
ls -la /var/run/docker.sock
# Проверка пользователей в группе docker
getent group docker
# Проверка открытых портов
netstat -tlnp | grep 9001
# Проверка логов аутентификации
grep "authentication" /var/log/logboard/app.log
```

313
docs/index.md Normal file
View File

@@ -0,0 +1,313 @@
# Документация LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Обзор
LogBoard+ - это современная веб-панель для мониторинга и просмотра логов Docker контейнеров в реальном времени. Приложение предоставляет удобный веб-интерфейс для работы с логами микросервисов, поддерживает множественные проекты Docker Compose и включает в себя функции безопасности.
## Быстрый старт
### Установка
```bash
# Клонирование репозитория
git clone <repository-url>
cd logboard
# Настройка переменных окружения
make setup
# Запуск приложения
make up
```
### Доступ
- **URL:** http://localhost:9001
- **Пользователь:** `admin`
- **Пароль:** `admin` (обязательно измените в продакшене!)
## Документация
### Основные разделы
1. **[Установка и настройка](./installation.md)**
- Предварительные требования
- Пошаговая установка
- Настройка для продакшена
- Устранение проблем установки
2. **[API Документация](./api.md)**
- REST API endpoints
- WebSocket API
- Примеры использования
- Коды ошибок
3. **[WebSocket API](./websocket.md)**
- Подключение к WebSocket
- Real-time логи
- Обработка ошибок
- Лучшие практики
4. **[Конфигурация](./configuration.md)**
- Переменные окружения
- Настройка Docker
- Настройка безопасности
- Примеры конфигураций
5. **[Безопасность](./security.md)**
- Генерация ключей
- Аутентификация
- Настройка HTTPS
- Мониторинг безопасности
6. **[Устранение неполадок](./troubleshooting.md)**
- Общие проблемы
- Проблемы с Docker
- Проблемы с аутентификацией
- Диагностика и логи
### Дополнительные ресурсы
- **[README.md](../README.md)** - Основная документация проекта
- **[env.example](../env.example)** - Пример конфигурации
- **[Makefile](../Makefile)** - Команды управления
## Архитектура
### Технологический стек
- **Backend:** Python 3.11, FastAPI 0.104.1
- **Web Server:** Uvicorn с uvloop
- **Docker Integration:** Docker SDK for Python 6.1.3
- **Authentication:** JWT с PyJWT
- **Frontend:** HTML5, CSS3, JavaScript (Vanilla)
- **Templates:** Jinja2
- **Containerization:** Docker, Docker Compose
### Основные возможности
- **Просмотр логов в реальном времени** - WebSocket соединения для live-логов
- **Поддержка множественных проектов** - Фильтрация по проектам Docker Compose
- **Безопасность** - JWT аутентификация и авторизация
- **Фильтрация контейнеров** - Исключение проблемных контейнеров
- **Снимки логов** - Сохранение логов в файлы для анализа
- **Статистика** - Анализ уровней логирования
- **Адаптивный интерфейс** - Поддержка светлой и темной темы
## API Endpoints
### REST API
#### Аутентификация
- `POST /api/auth/login` - Вход в систему
- `POST /api/auth/logout` - Выход из системы
- `GET /api/auth/me` - Информация о текущем пользователе
#### Контейнеры и сервисы
- `GET /api/services` - Список контейнеров
- `GET /api/projects` - Список проектов Docker Compose
- `GET /api/logs/{container_id}` - Логи контейнера
- `GET /api/logs/stats/{container_id}` - Статистика логов
#### Управление
- `GET /api/settings` - Настройки приложения
- `GET /api/excluded-containers` - Список исключенных контейнеров
- `POST /api/excluded-containers` - Обновление исключенных контейнеров
- `POST /api/snapshot` - Создание снимка логов
### WebSocket API
- `ws://host:port/ws/logs/{container_id}` - Логи отдельного контейнера
- `ws://host:port/ws/fan/{service_name}` - Логи сервиса (все реплики)
- `ws://host:port/ws/fan_group` - Логи группы сервисов
## Конфигурация
### Основные переменные окружения
| Переменная | Описание | По умолчанию |
|------------|----------|--------------|
| `LOGBOARD_PORT` | Порт веб-интерфейса | `9001` |
| `LOGBOARD_USER` | Имя пользователя | `admin` |
| `LOGBOARD_PASS` | Пароль пользователя | `admin` |
| `LOGBOARD_TAIL` | Количество строк логов | `500` |
| `SECRET_KEY` | Секретный ключ JWT | `your-secret-key-here` |
### Настройка проектов
```bash
# Один проект
COMPOSE_PROJECT_NAME=myproject
# Несколько проектов
LOGBOARD_PROJECTS=project1,project2,project3
```
## Управление
### Команды Makefile
```bash
make help # Справка по командам
make setup # Настройка переменных окружения
make build # Сборка Docker образа
make up # Запуск сервисов
make down # Остановка сервисов
make restart # Перезапуск сервисов
make logs # Просмотр логов
make clean # Очистка проекта
make status # Статус сервисов
make shell # Подключение к контейнеру
```
### Docker Compose команды
```bash
# Запуск
docker compose up -d
# Остановка
docker compose down
# Просмотр логов
docker compose logs -f
# Пересборка
docker compose build --no-cache
```
## Безопасность
### Рекомендации для продакшена
1. **Измените пароли по умолчанию**
2. **Настройте секретные ключи**
3. **Используйте HTTPS**
4. **Ограничьте доступ к Docker socket**
5. **Настройте файрвол**
### Аутентификация
Приложение использует JWT токены для аутентификации:
- Токены хранятся в HTTP-only cookies
- Время жизни токена настраивается через `SESSION_TIMEOUT`
- Поддерживается автоматическое обновление токенов
## Мониторинг и логирование
### Health Check
```bash
curl http://localhost:9001/healthz
# Ответ: ok
```
### Логирование
Приложение логирует:
- Ошибки подключения к Docker
- Проблемы с контейнерами
- Ошибки аутентификации
- WebSocket соединения
## Примеры использования
### Python
```python
import requests
# Аутентификация
response = requests.post('http://localhost:9001/api/auth/login', json={
'username': 'admin',
'password': 'your-password'
})
token = response.json()['access_token']
# Получение списка контейнеров
headers = {'Authorization': f'Bearer {token}'}
containers = requests.get('http://localhost:9001/api/services', headers=headers).json()
```
### JavaScript
```javascript
// Получение токена
const response = await fetch('http://localhost:9001/api/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: 'admin',
password: 'your-password'
})
});
const {access_token} = await response.json();
// WebSocket подключение
const ws = new WebSocket(`ws://localhost:9001/ws/logs/container-id?token=${access_token}`);
```
### cURL
```bash
# Получение токена
TOKEN=$(curl -s -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}' \
| jq -r '.access_token')
# Получение списка контейнеров
curl -X GET "http://localhost:9001/api/services" \
-H "Authorization: Bearer $TOKEN"
```
## Устранение неполадок
### Частые проблемы
1. **Ошибка подключения к Docker**
```bash
sudo usermod -aG docker $USER
newgrp docker
```
2. **Контейнеры не отображаются**
```bash
docker ps --format "table {{.Names}}\t{{.Labels}}"
```
3. **Ошибки аутентификации**
```bash
make env-check
```
### Диагностика
```bash
# Проверка статуса
make status
# Просмотр логов
make logs
# Проверка конфигурации
make validate
```
## Поддержка
- **Автор:** Сергей Антропов
- **Сайт:** https://devops.org.ru
- **Issues:** Создавайте issues в репозитории проекта
- **Документация:** [./docs/](./docs/)
## Лицензия
MIT License - см. файл [LICENSE](../LICENSE) для подробностей.
---
**LogBoard+** - Удобный просмотр логов микросервисов в реальном времени.

430
docs/installation.md Normal file
View File

@@ -0,0 +1,430 @@
# Установка и настройка LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Содержание
1. [Предварительные требования](#предварительные-требования)
2. [Установка](#установка)
3. [Настройка](#настройка)
4. [Первый запуск](#первый-запуск)
5. [Проверка установки](#проверка-установки)
6. [Настройка для продакшена](#настройка-для-продакшена)
## Предварительные требования
### Системные требования
- **Операционная система:** Linux (Ubuntu 20.04+, CentOS 8+, RHEL 8+)
- **Docker Engine:** 20.10.0 или выше
- **Docker Compose:** 2.0.0 или выше
- **RAM:** Минимум 1 GB, рекомендуется 2 GB
- **CPU:** Минимум 1 ядро, рекомендуется 2 ядра
- **Дисковое пространство:** Минимум 2 GB свободного места
### Проверка системы
```bash
# Проверка версии Docker
docker --version
# Docker version 20.10.21, build baeda1f
# Проверка версии Docker Compose
docker compose version
# Docker Compose version v2.12.2
# Проверка доступной памяти
free -h
# total used free shared buff/cache available
# Mem: 7.7Gi 2.1Gi 4.2Gi 0.0Ki 1.4Gi 5.3Gi
# Проверка свободного места
df -h /
# Filesystem Size Used Avail Use% Mounted on
# /dev/sda1 100G 20G 80G 20% /
```
## Установка
### Метод 1: Клонирование из Git
```bash
# Клонирование репозитория
git clone https://github.com/your-username/logboard.git
cd logboard
# Проверка структуры проекта
ls -la
```
### Метод 2: Скачивание архива
```bash
# Скачивание и распаковка
wget https://github.com/your-username/logboard/archive/refs/tags/v1.0.0.tar.gz
tar -xzf v1.0.0.tar.gz
cd logboard-1.0.0
```
## Настройка
### 1. Создание файла переменных окружения
```bash
# Копирование примера конфигурации
make setup
# Или вручную
cp env.example .env
```
### 2. Редактирование конфигурации
Откройте файл `.env` и настройте основные параметры:
```bash
# Основные настройки
LOGBOARD_PORT=9001
LOGBOARD_USER=admin
LOGBOARD_PASS=your-secure-password
# Безопасность (обязательно измените!)
SECRET_KEY=your-very-secure-secret-key-here
ENCRYPTION_KEY=your-encryption-key-here
# Настройки Docker
DOCKER_HOST=unix:///var/run/docker.sock
```
### 3. Настройка прав доступа к Docker
```bash
# Создание группы docker (если не существует)
sudo groupadd docker
# Добавление пользователя в группу docker
sudo usermod -aG docker $USER
# Проверка прав доступа
ls -la /var/run/docker.sock
# srw-rw-rw- 1 root docker 0 Jan 15 10:00 /var/run/docker.sock
# Перезагрузка группы (или перелогин)
newgrp docker
```
### 4. Создание директорий
```bash
# Создание директории для снимков логов
mkdir -p snapshots
# Установка прав доступа
chmod 755 snapshots
```
## Первый запуск
### 1. Сборка Docker образа
```bash
# Сборка образа
make build
# Или вручную
docker compose build --no-cache
```
### 2. Запуск приложения
```bash
# Запуск в фоновом режиме
make up
# Или вручную
docker compose up -d
```
### 3. Проверка статуса
```bash
# Проверка статуса контейнеров
make status
# Просмотр логов
make logs
```
## Проверка установки
### 1. Проверка доступности веб-интерфейса
```bash
# Проверка HTTP ответа
curl -I http://localhost:9001
# HTTP/1.1 200 OK
# Content-Type: text/html; charset=utf-8
# Проверка health check
curl http://localhost:9001/healthz
# ok
```
### 2. Проверка API
```bash
# Получение токена аутентификации
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-secure-password"}'
# Ответ должен содержать access_token
```
### 3. Проверка Docker интеграции
```bash
# Проверка списка контейнеров
curl -X GET "http://localhost:9001/api/services" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
# Проверка списка проектов
curl -X GET "http://localhost:9001/api/projects" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
```
### 4. Проверка WebSocket соединений
```bash
# Тестирование WebSocket (требует специального клиента)
# Используйте браузер или wscat для тестирования
```
## Настройка для продакшена
### 1. Безопасность
#### Изменение паролей и ключей
```bash
# Генерация секретного ключа
openssl rand -hex 32
# 8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
# Генерация ключа шифрования
openssl rand -hex 32
# 1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
# Обновление .env файла
LOGBOARD_PASS=your-very-secure-password
SECRET_KEY=8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
ENCRYPTION_KEY=1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
```
#### Настройка HTTPS
Создайте файл `nginx.conf`:
```nginx
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
location / {
proxy_pass http://localhost:9001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket поддержка
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
### 2. Мониторинг
#### Настройка логирования
```bash
# Создание директории для логов
sudo mkdir -p /var/log/logboard
sudo chown $USER:$USER /var/log/logboard
# Обновление docker-compose.yml
volumes:
- /var/log/logboard:/app/logs
```
#### Настройка systemd сервиса
Создайте файл `/etc/systemd/system/logboard.service`:
```ini
[Unit]
Description=LogBoard+ Docker Compose
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/path/to/logboard
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
```
```bash
# Включение автозапуска
sudo systemctl enable logboard.service
sudo systemctl start logboard.service
```
### 3. Резервное копирование
#### Скрипт резервного копирования
Создайте файл `backup.sh`:
```bash
#!/bin/bash
# Скрипт резервного копирования LogBoard+
BACKUP_DIR="/backup/logboard"
DATE=$(date +%Y%m%d_%H%M%S)
# Создание директории для резервных копий
mkdir -p $BACKUP_DIR
# Резервное копирование конфигурации
tar -czf $BACKUP_DIR/logboard_config_$DATE.tar.gz \
.env \
excluded_containers.json \
docker-compose.yml
# Резервное копирование снимков логов
tar -czf $BACKUP_DIR/logboard_snapshots_$DATE.tar.gz \
snapshots/
# Удаление старых резервных копий (старше 30 дней)
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
echo "Резервное копирование завершено: $DATE"
```
```bash
# Установка прав на выполнение
chmod +x backup.sh
# Добавление в cron (ежедневно в 2:00)
crontab -e
# 0 2 * * * /path/to/logboard/backup.sh
```
### 4. Обновление
#### Скрипт обновления
Создайте файл `update.sh`:
```bash
#!/bin/bash
# Скрипт обновления LogBoard+
echo "Начинаем обновление LogBoard+..."
# Остановка сервисов
make down
# Получение обновлений
git pull origin main
# Пересборка образов
make build
# Запуск сервисов
make up
# Проверка статуса
make status
echo "Обновление завершено!"
```
```bash
# Установка прав на выполнение
chmod +x update.sh
```
## Устранение проблем установки
### Частые ошибки
1. **Ошибка доступа к Docker socket**
```bash
# Решение: добавление пользователя в группу docker
sudo usermod -aG docker $USER
newgrp docker
```
2. **Ошибка порта уже используется**
```bash
# Решение: изменение порта в .env
LOGBOARD_PORT=9002
```
3. **Ошибка недостаточно памяти**
```bash
# Решение: увеличение лимитов Docker
sudo systemctl edit docker
# Добавьте:
# [Service]
# MemoryLimit=2G
```
4. **Ошибка SSL сертификатов**
```bash
# Решение: использование самоподписанных сертификатов для тестирования
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout private.key -out certificate.crt
```
### Логи для диагностики
```bash
# Просмотр логов приложения
make logs
# Просмотр логов Docker
docker logs logboard
# Проверка статуса контейнера
docker inspect logboard
```
## Следующие шаги
После успешной установки:
1. [Настройте безопасность](./security.md)
2. [Изучите API документацию](./api.md)
3. [Настройте конфигурацию](./configuration.md)
4. [Изучите WebSocket API](./websocket.md)

750
docs/security.md Normal file
View File

@@ -0,0 +1,750 @@
# Безопасность LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Содержание
1. [Обзор безопасности](#обзор-безопасности)
2. [Генерация ключей](#генерация-ключей)
3. [Аутентификация](#аутентификация)
4. [Настройка HTTPS](#настройка-https)
5. [Доступ к Docker](#доступ-к-docker)
6. [Сетевая безопасность](#сетевая-безопасность)
7. [Мониторинг безопасности](#мониторинг-безопасности)
8. [Рекомендации для продакшена](#рекомендации-для-продакшена)
## Обзор безопасности
LogBoard+ включает в себя несколько уровней безопасности для защиты доступа к логам и системной информации. Правильная настройка безопасности критически важна для продакшена.
### Уровни безопасности
1. **Аутентификация** - JWT токены для доступа к API
2. **Шифрование** - Защита чувствительных данных
3. **Сетевая безопасность** - HTTPS, файрвол, ограничение доступа
4. **Docker безопасность** - Ограничение прав доступа к Docker socket
5. **Мониторинг** - Логирование событий безопасности
## Генерация ключей
### SECRET_KEY
SECRET_KEY используется для подписи JWT токенов. Это критически важный ключ для безопасности аутентификации.
#### Генерация SECRET_KEY
**Метод 1: OpenSSL (рекомендуется)**
```bash
# Генерация 32-байтового ключа в hex формате
openssl rand -hex 32
# Пример вывода: 8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
# Генерация 64-байтового ключа (для максимальной безопасности)
openssl rand -hex 64
# Пример вывода: 8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6...
```
**Метод 2: Python**
```bash
# Использование Python для генерации
python3 -c "import secrets; print(secrets.token_hex(32))"
# Пример вывода: 8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
# Генерация через Python скрипт
python3 -c "
import secrets
import base64
key = secrets.token_bytes(32)
print('Hex:', key.hex())
print('Base64:', base64.b64encode(key).decode())
"
```
**Метод 3: Node.js**
```bash
# Использование Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Пример вывода: 8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6
```
#### Требования к SECRET_KEY
- **Длина:** Минимум 32 байта (64 символа в hex)
- **Энтропия:** Используйте криптографически стойкий генератор случайных чисел
- **Уникальность:** Каждая установка должна иметь уникальный ключ
- **Хранение:** Храните в безопасном месте, не в коде
### ENCRYPTION_KEY
ENCRYPTION_KEY используется для шифрования чувствительных данных в приложении.
#### Генерация ENCRYPTION_KEY
**Метод 1: OpenSSL (рекомендуется)**
```bash
# Генерация 32-байтового ключа шифрования
openssl rand -hex 32
# Пример вывода: 1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
# Генерация ключа для AES-256
openssl rand -base64 32
# Пример вывода: 1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
```
**Метод 2: Python с Fernet**
```bash
# Генерация ключа для Fernet (Base64)
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# Пример вывода: 1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7
# Генерация через Python скрипт
python3 -c "
import secrets
import base64
key = secrets.token_bytes(32)
print('Hex:', key.hex())
print('Base64:', base64.b64encode(key).decode())
print('Fernet:', base64.urlsafe_b64encode(key).decode())
"
```
**Метод 3: Скрипт генерации ключей**
Создайте файл `generate_keys.sh`:
```bash
#!/bin/bash
# Скрипт генерации ключей безопасности для LogBoard+
# Автор: Сергей Антропов
# Сайт: https://devops.org.ru
echo "=== Генерация ключей безопасности для LogBoard+ ==="
echo ""
# Проверка наличия OpenSSL
if ! command -v openssl &> /dev/null; then
echo "❌ OpenSSL не найден. Установите OpenSSL для генерации ключей."
exit 1
fi
echo "🔐 Генерация SECRET_KEY..."
SECRET_KEY=$(openssl rand -hex 32)
echo "SECRET_KEY=$SECRET_KEY"
echo ""
echo "🔐 Генерация ENCRYPTION_KEY..."
ENCRYPTION_KEY=$(openssl rand -hex 32)
echo "ENCRYPTION_KEY=$ENCRYPTION_KEY"
echo ""
echo "🔐 Генерация пароля пользователя..."
USER_PASSWORD=$(openssl rand -base64 16 | tr -d "=+/" | cut -c1-16)
echo "LOGBOARD_PASS=$USER_PASSWORD"
echo ""
echo "📝 Обновление .env файла..."
if [ -f .env ]; then
# Создание резервной копии
cp .env .env.backup.$(date +%Y%m%d_%H%M%S)
echo "✅ Создана резервная копия .env"
# Обновление ключей
sed -i "s/^SECRET_KEY=.*/SECRET_KEY=$SECRET_KEY/" .env
sed -i "s/^ENCRYPTION_KEY=.*/ENCRYPTION_KEY=$ENCRYPTION_KEY/" .env
sed -i "s/^LOGBOARD_PASS=.*/LOGBOARD_PASS=$USER_PASSWORD/" .env
echo "✅ Ключи обновлены в .env"
else
echo "⚠️ Файл .env не найден. Создайте его из env.example"
fi
echo ""
echo "=== Рекомендации по безопасности ==="
echo "1. Сохраните ключи в безопасном месте"
echo "2. Не передавайте ключи через незащищенные каналы"
echo "3. Регулярно обновляйте ключи"
echo "4. Используйте разные ключи для разных окружений"
echo ""
echo "✅ Генерация ключей завершена!"
```
```bash
# Установка прав на выполнение
chmod +x generate_keys.sh
# Запуск генерации
./generate_keys.sh
```
#### Требования к ENCRYPTION_KEY
- **Длина:** 32 байта для AES-256
- **Формат:** Hex или Base64
- **Энтропия:** Криптографически стойкий генератор
- **Уникальность:** Уникальный для каждой установки
### Проверка качества ключей
```bash
# Проверка энтропии ключа
python3 -c "
import secrets
import base64
def check_entropy(key_hex):
# Преобразование hex в байты
key_bytes = bytes.fromhex(key_hex)
# Подсчет уникальных байтов
unique_bytes = len(set(key_bytes))
total_bytes = len(key_bytes)
# Вычисление энтропии
entropy = unique_bytes / total_bytes
print(f'Длина ключа: {total_bytes} байт')
print(f'Уникальных байтов: {unique_bytes}')
print(f'Энтропия: {entropy:.2%}')
if entropy > 0.8:
print('✅ Ключ имеет хорошую энтропию')
else:
print('⚠️ Ключ может иметь низкую энтропию')
# Проверка вашего ключа
key = '8a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6'
check_entropy(key)
"
```
## Аутентификация
### JWT токены
LogBoard+ использует JWT (JSON Web Tokens) для аутентификации.
#### Структура JWT токена
```json
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "admin",
"exp": 1642234567,
"iat": 1642230967
},
"signature": "HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), SECRET_KEY)"
}
```
#### Настройка JWT
```bash
# В .env файле
SECRET_KEY=your-secret-key-here
SESSION_TIMEOUT=3600 # Время жизни токена в секундах
```
#### Безопасность JWT
1. **Используйте сильный SECRET_KEY**
2. **Установите разумное время жизни токена**
3. **Используйте HTTPS для передачи токенов**
4. **Регулярно обновляйте токены**
### Пароли пользователей
#### Генерация безопасного пароля
```bash
# Генерация пароля с OpenSSL
openssl rand -base64 16 | tr -d "=+/" | cut -c1-16
# Пример вывода: aB3cD4eF5gH6iJ7k
# Генерация пароля с Python
python3 -c "
import secrets
import string
def generate_password(length=16):
alphabet = string.ascii_letters + string.digits + '!@#$%^&*'
return ''.join(secrets.choice(alphabet) for _ in range(length))
print('Пароль:', generate_password(16))
"
# Генерация пароля с pwgen
pwgen -s 16 1
```
#### Требования к паролям
- **Длина:** Минимум 12 символов
- **Сложность:** Буквы, цифры, специальные символы
- **Уникальность:** Не используйте пароли по умолчанию
- **Хранение:** Храните в безопасном месте
## Настройка HTTPS
### Самоподписанные сертификаты (для тестирования)
```bash
# Генерация приватного ключа
openssl genrsa -out private.key 2048
# Генерация сертификата
openssl req -x509 -new -nodes -key private.key -sha256 -days 365 -out certificate.crt
# Или одной командой
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout private.key -out certificate.crt \
-subj "/C=RU/ST=Moscow/L=Moscow/O=Company/CN=localhost"
```
### Let's Encrypt сертификаты (для продакшена)
```bash
# Установка certbot
sudo apt install certbot python3-certbot-nginx
# Получение сертификата
sudo certbot --nginx -d your-domain.com
# Автоматическое обновление
sudo crontab -e
# Добавить строку:
# 0 12 * * * /usr/bin/certbot renew --quiet
```
### Nginx конфигурация с HTTPS
```nginx
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL сертификаты
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
# SSL настройки
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Безопасные заголовки
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
proxy_pass http://localhost:9001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket поддержка
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Таймауты
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
```
## Доступ к Docker
### Ограничение прав доступа
```bash
# Создание группы docker
sudo groupadd docker
# Добавление пользователя в группу
sudo usermod -aG docker $USER
# Проверка прав
ls -la /var/run/docker.sock
# Должно быть: srw-rw-rw- 1 root docker 0 Jan 15 10:00 /var/run/docker.sock
# Перезагрузка группы
newgrp docker
```
### Альтернативные методы
#### Метод 1: Docker API с TLS
```bash
# Генерация CA ключа
openssl genrsa -aes256 -out ca-key.pem 4096
# Генерация CA сертификата
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# Генерация серверного ключа
openssl genrsa -out server-key.pem 4096
# Генерация серверного сертификата
openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr
# Подпись серверного сертификата
openssl x509 -req -days 365 -sha256 \
-in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem
# Настройка Docker daemon
sudo mkdir -p /etc/docker
sudo cp ca.pem server-cert.pem server-key.pem /etc/docker/
# Конфигурация Docker daemon
sudo tee /etc/docker/daemon.json <<EOF
{
"tls": true,
"tlscacert": "/etc/docker/ca.pem",
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem",
"hosts": ["tcp://0.0.0.0:2376", "unix:///var/run/docker.sock"]
}
EOF
# Перезапуск Docker
sudo systemctl restart docker
```
#### Метод 2: Docker API с аутентификацией
```bash
# Создание пользователя для API
sudo useradd -r -s /bin/false docker-api
# Настройка прав
sudo usermod -aG docker docker-api
# Конфигурация в .env
DOCKER_HOST=tcp://localhost:2375
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/path/to/certs
```
## Сетевая безопасность
### Настройка файрвола
```bash
# Установка UFW
sudo apt install ufw
# Базовые правила
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Разрешение SSH
sudo ufw allow ssh
# Разрешение HTTPS
sudo ufw allow 443/tcp
# Разрешение LogBoard+ только для локальной сети
sudo ufw allow from 192.168.1.0/24 to any port 9001
# Включение файрвола
sudo ufw enable
# Проверка статуса
sudo ufw status verbose
```
### iptables правила
```bash
# Очистка правил
sudo iptables -F
sudo iptables -X
# Установка политик по умолчанию
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
# Разрешение локального трафика
sudo iptables -A INPUT -i lo -j ACCEPT
# Разрешение установленных соединений
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Разрешение SSH
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Разрешение HTTPS
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Разрешение LogBoard+ для локальной сети
sudo iptables -A INPUT -p tcp --dport 9001 -s 192.168.1.0/24 -j ACCEPT
# Сохранение правил
sudo iptables-save > /etc/iptables/rules.v4
```
### Настройка Docker сетей
```yaml
# В docker-compose.yml
networks:
logboard_network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
driver_opts:
com.docker.network.bridge.name: logboard_br0
services:
logboard:
networks:
- logboard_network
# Ограничение доступа к Docker socket
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
```
## Мониторинг безопасности
### Логирование событий безопасности
```bash
# Настройка логирования в .env
LOG_LEVEL=INFO
LOG_FORMAT=json
# Создание директории для логов
sudo mkdir -p /var/log/logboard
sudo chown $USER:$USER /var/log/logboard
# Настройка ротации логов
sudo tee /etc/logrotate.d/logboard <<EOF
/var/log/logboard/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 $USER $USER
postrotate
docker compose -f /path/to/logboard/docker-compose.yml restart logboard
endscript
}
EOF
```
### Мониторинг доступа
```bash
# Скрипт мониторинга доступа
cat > monitor_access.sh <<'EOF'
#!/bin/bash
# Мониторинг доступа к LogBoard+
# Автор: Сергей Антропов
LOG_FILE="/var/log/logboard/access.log"
ALERT_FILE="/var/log/logboard/security_alerts.log"
# Функция логирования
log_alert() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$ALERT_FILE"
}
# Мониторинг неудачных попыток входа
failed_logins=$(grep -c "authentication failed" "$LOG_FILE" 2>/dev/null || echo "0")
if [ "$failed_logins" -gt 10 ]; then
log_alert "Обнаружено $failed_logins неудачных попыток входа"
fi
# Мониторинг подозрительных IP
suspicious_ips=$(grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" "$LOG_FILE" | sort | uniq -c | awk '$1 > 100 {print $2}')
if [ -n "$suspicious_ips" ]; then
log_alert "Подозрительная активность с IP: $suspicious_ips"
fi
echo "Мониторинг завершен: $(date)"
EOF
chmod +x monitor_access.sh
# Добавление в cron
crontab -e
# Добавить строку:
# */5 * * * * /path/to/logboard/monitor_access.sh
```
### Алерты безопасности
```bash
# Скрипт отправки алертов
cat > security_alerts.sh <<'EOF'
#!/bin/bash
# Отправка алертов безопасности
# Автор: Сергей Антропов
ALERT_FILE="/var/log/logboard/security_alerts.log"
EMAIL="admin@company.com"
# Проверка новых алертов
if [ -f "$ALERT_FILE" ]; then
new_alerts=$(tail -n 10 "$ALERT_FILE")
if [ -n "$new_alerts" ]; then
echo "$new_alerts" | mail -s "LogBoard+ Security Alert" "$EMAIL"
fi
fi
EOF
chmod +x security_alerts.sh
# Добавление в cron
crontab -e
# Добавить строку:
# 0 */1 * * * /path/to/logboard/security_alerts.sh
```
## Рекомендации для продакшена
### Обязательные настройки
1. **Измените все пароли по умолчанию**
2. **Используйте сильные секретные ключи**
3. **Настройте HTTPS**
4. **Ограничьте доступ к Docker socket**
5. **Настройте файрвол**
6. **Включите мониторинг безопасности**
### Регулярные проверки
```bash
# Скрипт проверки безопасности
cat > security_check.sh <<'EOF'
#!/bin/bash
# Проверка безопасности LogBoard+
# Автор: Сергей Антропов
echo "=== Проверка безопасности LogBoard+ ==="
echo "Дата: $(date)"
echo ""
# Проверка паролей по умолчанию
if grep -q "LOGBOARD_PASS=admin" .env; then
echo "❌ Пароль по умолчанию не изменен!"
else
echo "✅ Пароль изменен"
fi
# Проверка секретных ключей
if grep -q "SECRET_KEY=your-secret-key-here" .env; then
echo "❌ SECRET_KEY не изменен!"
else
echo "✅ SECRET_KEY изменен"
fi
if grep -q "ENCRYPTION_KEY=your-encryption-key-here" .env; then
echo "❌ ENCRYPTION_KEY не изменен!"
else
echo "✅ ENCRYPTION_KEY изменен"
fi
# Проверка HTTPS
if curl -s -I https://localhost:9001 > /dev/null 2>&1; then
echo "✅ HTTPS доступен"
else
echo "⚠️ HTTPS недоступен"
fi
# Проверка прав Docker
if ls -la /var/run/docker.sock | grep -q "srw-rw-rw-"; then
echo "✅ Docker socket доступен"
else
echo "❌ Проблемы с доступом к Docker socket"
fi
# Проверка файрвола
if command -v ufw > /dev/null && sudo ufw status | grep -q "Status: active"; then
echo "✅ Файрвол активен"
else
echo "⚠️ Файрвол не настроен"
fi
echo ""
echo "=== Рекомендации ==="
echo "1. Регулярно обновляйте ключи"
echo "2. Мониторьте логи доступа"
echo "3. Обновляйте зависимости"
echo "4. Проверяйте права доступа"
echo "5. Тестируйте резервные копии"
EOF
chmod +x security_check.sh
# Запуск проверки
./security_check.sh
```
### План реагирования на инциденты
1. **Немедленные действия**
- Отключение подозрительных IP
- Блокировка скомпрометированных учетных записей
- Анализ логов
2. **Расследование**
- Определение источника атаки
- Оценка ущерба
- Документирование инцидента
3. **Восстановление**
- Обновление ключей
- Патчинг уязвимостей
- Восстановление из резервных копий
4. **Профилактика**
- Усиление безопасности
- Обновление процедур
- Обучение персонала
### Контрольный список безопасности
- [ ] Изменены пароли по умолчанию
- [ ] Сгенерированы сильные секретные ключи
- [ ] Настроен HTTPS
- [ ] Ограничен доступ к Docker
- [ ] Настроен файрвол
- [ ] Включено логирование
- [ ] Настроен мониторинг
- [ ] Созданы резервные копии
- [ ] Документированы процедуры
- [ ] Проведено тестирование безопасности

767
docs/troubleshooting.md Normal file
View File

@@ -0,0 +1,767 @@
# Устранение неполадок LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Содержание
1. [Общие проблемы](#общие-проблемы)
2. [Проблемы с Docker](#проблемы-с-docker)
3. [Проблемы с аутентификацией](#проблемы-с-аутентификацией)
4. [Проблемы с WebSocket](#проблемы-с-websocket)
5. [Проблемы с производительностью](#проблемы-с-производительностью)
6. [Проблемы с сетью](#проблемы-с-сетью)
7. [Диагностика и логи](#диагностика-и-логи)
## Общие проблемы
### Приложение не запускается
#### Симптомы
- Ошибка при выполнении `make up`
- Контейнер не стартует
- Ошибки в логах Docker
#### Диагностика
```bash
# Проверка статуса контейнеров
make status
# Просмотр логов
make logs
# Проверка конфигурации
make validate
# Проверка переменных окружения
make env-check
```
#### Решения
1. **Проблема с портом**
```bash
# Проверка занятости порта
netstat -tlnp | grep 9001
# Изменение порта в .env
LOGBOARD_PORT=9002
```
2. **Проблема с правами доступа**
```bash
# Проверка прав на директории
ls -la snapshots/
# Установка правильных прав
chmod 755 snapshots/
chown $USER:$USER snapshots/
```
3. **Проблема с Docker**
```bash
# Проверка статуса Docker
sudo systemctl status docker
# Перезапуск Docker
sudo systemctl restart docker
```
### Ошибки конфигурации
#### Симптомы
- Ошибки при парсинге переменных окружения
- Неправильная работа функций
- Ошибки в логах приложения
#### Диагностика
```bash
# Проверка синтаксиса .env файла
cat .env | grep -v "^#" | grep -v "^$"
# Проверка обязательных переменных
grep -E "^(LOGBOARD_PASS|SECRET_KEY|ENCRYPTION_KEY)=" .env
```
#### Решения
1. **Отсутствуют обязательные переменные**
```bash
# Создание .env из примера
make setup
# Редактирование .env
nano .env
```
2. **Неправильный формат переменных**
```bash
# Проверка формата
# Переменные должны быть в формате KEY=value
# Без пробелов вокруг знака равенства
```
## Проблемы с Docker
### Ошибка подключения к Docker socket
#### Симптомы
- Ошибка "Permission denied" при доступе к Docker
- Контейнеры не отображаются в интерфейсе
- Ошибки в логах приложения
#### Диагностика
```bash
# Проверка прав доступа к Docker socket
ls -la /var/run/docker.sock
# Проверка группы docker
getent group docker
# Проверка пользователя в группе
groups $USER
```
#### Решения
1. **Добавление пользователя в группу docker**
```bash
# Создание группы docker (если не существует)
sudo groupadd docker
# Добавление пользователя в группу
sudo usermod -aG docker $USER
# Перезагрузка группы
newgrp docker
# Проверка
docker ps
```
2. **Изменение прав на Docker socket**
```bash
# Временное решение (не рекомендуется для продакшена)
sudo chmod 666 /var/run/docker.sock
```
3. **Перезапуск Docker daemon**
```bash
sudo systemctl restart docker
```
### Контейнеры не отображаются
#### Симптомы
- Пустой список контейнеров в интерфейсе
- Ошибки при получении списка контейнеров
- Контейнеры видны в `docker ps`, но не в LogBoard+
#### Диагностика
```bash
# Проверка списка контейнеров
docker ps -a
# Проверка меток контейнеров
docker inspect <container_id> | grep -A 10 "Labels"
# Проверка фильтров проектов
echo $COMPOSE_PROJECT_NAME
echo $LOGBOARD_PROJECTS
```
#### Решения
1. **Проблема с фильтрами проектов**
```bash
# Очистка фильтров в .env
# COMPOSE_PROJECT_NAME=
# LOGBOARD_PROJECTS=
# Перезапуск приложения
make restart
```
2. **Проблема с метками контейнеров**
```bash
# Проверка меток Docker Compose
docker inspect <container_id> | grep "com.docker.compose"
# Перезапуск контейнеров с правильными метками
docker compose down && docker compose up -d
```
3. **Проблема с исключенными контейнерами**
```bash
# Проверка файла исключений
cat excluded_containers.json
# Очистка исключений
echo '{"excluded_containers": []}' > excluded_containers.json
```
### Ошибки получения логов
#### Симптомы
- Логи не загружаются
- Ошибки при запросе логов
- Пустые логи в интерфейсе
#### Диагностика
```bash
# Проверка логов контейнера напрямую
docker logs <container_id>
# Проверка статуса контейнера
docker inspect <container_id> | grep -A 5 "State"
# Проверка прав доступа к логам
docker logs <container_id> 2>&1
```
#### Решения
1. **Контейнер остановлен**
```bash
# Запуск контейнера
docker start <container_id>
# Проверка статуса
docker ps
```
2. **Проблема с драйвером логирования**
```bash
# Проверка драйвера логирования
docker inspect <container_id> | grep "LogDriver"
# Изменение драйвера логирования
docker run --log-driver=json-file ...
```
3. **Проблема с размером логов**
```bash
# Очистка логов контейнера
docker logs --since 1h <container_id>
# Ограничение размера логов
docker run --log-opt max-size=10m ...
```
## Проблемы с аутентификацией
### Ошибка входа в систему
#### Симптомы
- Не удается войти в систему
- Ошибка "Неверное имя пользователя или пароль"
- Бесконечная перезагрузка страницы входа
#### Диагностика
```bash
# Проверка переменных аутентификации
grep -E "^(LOGBOARD_USER|LOGBOARD_PASS)=" .env
# Проверка API аутентификации
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}'
```
#### Решения
1. **Неправильные учетные данные**
```bash
# Проверка и исправление .env
LOGBOARD_USER=admin
LOGBOARD_PASS=your-correct-password
# Перезапуск приложения
make restart
```
2. **Проблема с JWT токенами**
```bash
# Проверка SECRET_KEY
grep "SECRET_KEY" .env
# Генерация нового ключа
openssl rand -hex 32
# Обновление .env
SECRET_KEY=your-new-secret-key
```
3. **Проблема с cookies**
```bash
# Очистка cookies браузера
# Или использование режима инкогнито
```
### Ошибки авторизации API
#### Симптомы
- Ошибка 401 при запросах к API
- "Требуется авторизация" в ответах
- Не работает WebSocket API
#### Диагностика
```bash
# Проверка токена
curl -X GET "http://localhost:9001/api/auth/me" \
-H "Authorization: Bearer YOUR_TOKEN"
# Проверка времени жизни токена
echo $SESSION_TIMEOUT
```
#### Решения
1. **Истекший токен**
```bash
# Увеличение времени жизни токена
SESSION_TIMEOUT=7200 # 2 часа
# Перезапуск приложения
make restart
```
2. **Неправильный формат токена**
```bash
# Получение нового токена
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}'
```
3. **Проблема с часовыми поясами**
```bash
# Установка правильного часового пояса
TZ_TS=UTC
# Перезапуск приложения
make restart
```
## Проблемы с WebSocket
### WebSocket соединения не устанавливаются
#### Симптомы
- Ошибки WebSocket в консоли браузера
- Логи не обновляются в реальном времени
- Ошибка "WebSocket connection failed"
#### Диагностика
```bash
# Проверка WebSocket endpoint
curl -I "http://localhost:9001/ws/logs/test"
# Проверка логов приложения
make logs | grep -i websocket
# Проверка в браузере
# Открыть Developer Tools -> Console
```
#### Решения
1. **Проблема с прокси**
```nginx
# Настройка Nginx для WebSocket
location /ws/ {
proxy_pass http://localhost:9001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
```
2. **Проблема с токеном**
```javascript
// Проверка токена в WebSocket URL
const token = "your-valid-token";
const ws = new WebSocket(`ws://localhost:9001/ws/logs/container-id?token=${token}`);
```
3. **Проблема с CORS**
```bash
# Добавление CORS заголовков в конфигурацию
# (если используется)
```
### WebSocket соединения разрываются
#### Симптомы
- Соединения закрываются через некоторое время
- Ошибки "Connection closed unexpectedly"
- Логи перестают обновляться
#### Диагностика
```bash
# Проверка таймаутов
grep -E "TIMEOUT|timeout" .env
# Проверка нагрузки на систему
top
free -h
```
#### Решения
1. **Увеличение таймаутов**
```bash
# Увеличение таймаутов в .env
CONNECTION_TIMEOUT=120
READ_TIMEOUT=300
# Перезапуск приложения
make restart
```
2. **Проблема с нагрузкой**
```bash
# Ограничение количества соединений
MAX_CONNECTIONS=50
# Увеличение ресурсов контейнера
# В docker-compose.yml
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
```
3. **Проблема с сетевыми таймаутами**
```bash
# Настройка keepalive
# В конфигурации прокси или балансировщика
```
## Проблемы с производительностью
### Медленная загрузка логов
#### Симптомы
- Долгая загрузка страниц
- Медленное получение логов
- Высокая нагрузка на CPU
#### Диагностика
```bash
# Проверка ресурсов системы
htop
iostat 1
df -h
# Проверка настроек производительности
grep -E "TAIL|INTERVAL" .env
```
#### Решения
1. **Оптимизация настроек**
```bash
# Уменьшение количества строк логов
LOGBOARD_TAIL=100
# Увеличение интервала обновления
LOGBOARD_AJAX_UPDATE_INTERVAL=5000
# Перезапуск приложения
make restart
```
2. **Ограничение ресурсов**
```bash
# Настройка лимитов в docker-compose.yml
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
```
3. **Оптимизация Docker**
```bash
# Очистка неиспользуемых ресурсов
docker system prune -f
# Ограничение логов контейнеров
docker run --log-opt max-size=10m --log-opt max-file=3 ...
```
### Высокое потребление памяти
#### Симптомы
- Контейнер LogBoard+ потребляет много памяти
- Ошибки "Out of memory"
- Медленная работа системы
#### Диагностика
```bash
# Проверка использования памяти
docker stats logboard
# Проверка процессов в контейнере
docker exec logboard ps aux
# Проверка логов приложения
make logs | grep -i memory
```
#### Решения
1. **Ограничение памяти**
```bash
# Установка лимитов памяти
# В docker-compose.yml
deploy:
resources:
limits:
memory: 512M
```
2. **Оптимизация кода**
```bash
# Уменьшение размера буферов
# Уменьшение количества одновременных соединений
MAX_CONNECTIONS=50
```
3. **Очистка кэша**
```bash
# Перезапуск приложения
make restart
# Очистка Docker кэша
docker system prune -f
```
## Проблемы с сетью
### Недоступность веб-интерфейса
#### Симптомы
- Не удается открыть веб-интерфейс
- Ошибка "Connection refused"
- Таймаут при подключении
#### Диагностика
```bash
# Проверка статуса контейнера
make status
# Проверка портов
netstat -tlnp | grep 9001
# Проверка доступности
curl -I http://localhost:9001
```
#### Решения
1. **Проблема с портом**
```bash
# Проверка занятости порта
sudo lsof -i :9001
# Изменение порта
LOGBOARD_PORT=9002
make restart
```
2. **Проблема с сетевыми настройками**
```bash
# Проверка Docker сетей
docker network ls
# Пересоздание сетей
docker compose down
docker compose up -d
```
3. **Проблема с файрволом**
```bash
# Проверка файрвола
sudo ufw status
# Разрешение порта
sudo ufw allow 9001
```
### Проблемы с внешним доступом
#### Симптомы
- Доступ только с localhost
- Не работает с внешним IP
- Проблемы с reverse proxy
#### Диагностика
```bash
# Проверка привязки к интерфейсам
netstat -tlnp | grep 9001
# Проверка конфигурации Docker
docker inspect logboard | grep -A 10 "NetworkSettings"
```
#### Решения
1. **Настройка привязки к интерфейсам**
```yaml
# В docker-compose.yml
ports:
- "0.0.0.0:9001:9001"
```
2. **Настройка reverse proxy**
```nginx
# Nginx конфигурация
location / {
proxy_pass http://localhost:9001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
```
3. **Настройка файрвола**
```bash
# Разрешение внешнего доступа
sudo ufw allow from 192.168.1.0/24 to any port 9001
```
## Диагностика и логи
### Просмотр логов приложения
```bash
# Логи в реальном времени
make logs -f
# Логи с фильтрацией
make logs | grep ERROR
# Логи последних 100 строк
make logs | tail -100
```
### Просмотр логов Docker
```bash
# Логи контейнера LogBoard+
docker logs logboard
# Логи с временными метками
docker logs -t logboard
# Логи последних 50 строк
docker logs --tail 50 logboard
```
### Проверка состояния системы
```bash
# Статус сервисов
make status
# Использование ресурсов
docker stats logboard
# Информация о контейнере
docker inspect logboard
```
### Отладка API
```bash
# Проверка health check
curl http://localhost:9001/healthz
# Проверка аутентификации
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}'
# Проверка API с токеном
TOKEN="your-token"
curl -X GET "http://localhost:9001/api/services" \
-H "Authorization: Bearer $TOKEN"
```
### Создание отчета о проблеме
```bash
# Создание диагностического отчета
cat > diagnostic_report.txt << EOF
=== LogBoard+ Diagnostic Report ===
Date: $(date)
Version: 1.0.0
=== System Information ===
OS: $(uname -a)
Docker: $(docker --version)
Docker Compose: $(docker compose version)
=== LogBoard+ Status ===
$(make status)
=== Configuration ===
$(grep -v "^#" .env | grep -v "^$")
=== Recent Logs ===
$(make logs | tail -50)
=== Docker Information ===
$(docker inspect logboard | jq '.[] | {State: .State, NetworkSettings: .NetworkSettings}')
=== System Resources ===
$(free -h)
$(df -h /)
EOF
echo "Diagnostic report saved to diagnostic_report.txt"
```
### Частые команды для диагностики
```bash
# Быстрая диагностика
make env-check && make validate && make status
# Проверка подключения к Docker
docker ps
# Проверка доступности API
curl -s http://localhost:9001/healthz
# Проверка аутентификации
curl -s -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | jq .
# Проверка списка контейнеров (требует токен)
TOKEN=$(curl -s -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | jq -r '.access_token')
curl -s -X GET "http://localhost:9001/api/services" \
-H "Authorization: Bearer $TOKEN" | jq 'length'
```

913
docs/websocket.md Normal file
View File

@@ -0,0 +1,913 @@
# WebSocket API LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Содержание
1. [Обзор WebSocket API](#обзор-websocket-api)
2. [Аутентификация](#аутентификация)
3. [Endpoints](#endpoints)
4. [Примеры использования](#примеры-использования)
5. [Обработка ошибок](#обработка-ошибок)
6. [Лучшие практики](#лучшие-практики)
## Обзор WebSocket API
WebSocket API LogBoard+ предоставляет возможность получения логов Docker контейнеров в реальном времени. Это позволяет создавать интерактивные приложения для мониторинга и отладки микросервисов.
### Преимущества WebSocket
- **Real-time данные** - мгновенное получение новых логов
- **Эффективность** - меньше накладных расходов по сравнению с polling
- **Масштабируемость** - поддержка множественных соединений
- **Фильтрация** - получение логов только нужных контейнеров
### Поддерживаемые протоколы
- **ws://** - для HTTP соединений
- **wss://** - для HTTPS соединений (рекомендуется для продакшена)
## Аутентификация
Все WebSocket endpoints требуют JWT токен для аутентификации. Токен передается как параметр запроса `token`.
### Получение токена
```bash
# Получение JWT токена через REST API
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}'
```
### Использование токена
```javascript
const token = "your-jwt-token";
const ws = new WebSocket(`ws://localhost:9001/ws/logs/container-id?token=${token}`);
```
## Endpoints
### ws://host:port/ws/logs/{container_id}
Получение логов отдельного контейнера в реальном времени.
#### Параметры
| Параметр | Тип | Обязательный | Описание |
|----------|-----|--------------|----------|
| `container_id` | string | Да | ID контейнера (первые 12 символов) |
| `token` | string | Да | JWT токен аутентификации |
| `tail` | number | Нет | Количество начальных строк (по умолчанию 500) |
| `service` | string | Нет | Имя сервиса (для информации) |
| `project` | string | Нет | Имя проекта (для информации) |
#### Пример подключения
```javascript
const containerId = "abc123def456";
const token = "your-jwt-token";
const ws = new WebSocket(`ws://localhost:9001/ws/logs/${containerId}?token=${token}&tail=100`);
ws.onopen = function() {
console.log('WebSocket соединение установлено');
};
ws.onmessage = function(event) {
console.log('Получены логи:', event.data);
};
ws.onerror = function(error) {
console.error('WebSocket ошибка:', error);
};
ws.onclose = function(event) {
console.log('WebSocket соединение закрыто:', event.code, event.reason);
};
```
#### Формат сообщений
При подключении сервер отправляет приветственное сообщение:
```
Connected to container: myproject_web_1
```
Затем отправляются логи в формате:
```
2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker processes
2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker process 1234
```
### ws://host:port/ws/fan/{service_name}
Получение логов всех реплик сервиса Docker Compose (fan-in).
#### Параметры
| Параметр | Тип | Обязательный | Описание |
|----------|-----|--------------|----------|
| `service_name` | string | Да | Имя сервиса Docker Compose |
| `token` | string | Да | JWT токен аутентификации |
| `tail` | number | Нет | Количество начальных строк (по умолчанию 500) |
| `project` | string | Нет | Имя проекта (для фильтрации) |
#### Пример подключения
```javascript
const serviceName = "web";
const token = "your-jwt-token";
const ws = new WebSocket(`ws://localhost:9001/ws/fan/${serviceName}?token=${token}&tail=100`);
ws.onmessage = function(event) {
// Логи приходят с префиксом ID контейнера
console.log('Логи сервиса:', event.data);
};
```
#### Формат сообщений
Логи приходят с префиксом короткого ID контейнера:
```
[abc123de] 2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker processes
[def456gh] 2024-01-15T10:30:16.123456789Z 2024/01/15 10:30:16 [notice] 1#1: start worker processes
```
### ws://host:port/ws/fan_group
Получение логов группы сервисов одновременно.
#### Параметры
| Параметр | Тип | Обязательный | Описание |
|----------|-----|--------------|----------|
| `services` | string | Да | Имена сервисов через запятую |
| `token` | string | Да | JWT токен аутентификации |
| `tail` | number | Нет | Количество начальных строк (по умолчанию 500) |
| `project` | string | Нет | Имя проекта (для фильтрации) |
#### Пример подключения
```javascript
const services = "web,db,redis";
const token = "your-jwt-token";
const ws = new WebSocket(`ws://localhost:9001/ws/fan_group?services=${services}&token=${token}&tail=100`);
ws.onmessage = function(event) {
// Логи приходят с префиксом ID контейнера и имени сервиса
console.log('Логи группы сервисов:', event.data);
};
```
#### Формат сообщений
Логи приходят с префиксом ID контейнера и имени сервиса:
```
[abc123de web] 2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker processes
[def456gh db] 2024-01-15T10:30:16.123456789Z 2024/01/15 10:30:16 [info] database system is ready to accept connections
[ghi789jk redis] 2024-01-15T10:30:17.123456789Z 2024/01/15 10:30:17 [notice] Ready to accept connections
```
## Примеры использования
### JavaScript (Browser)
```javascript
class LogBoardWebSocket {
constructor(baseUrl, token) {
this.baseUrl = baseUrl;
this.token = token;
this.connections = new Map();
}
// Подключение к логам контейнера
connectToContainer(containerId, options = {}) {
const { tail = 100, onMessage, onError, onClose } = options;
const url = `ws://${this.baseUrl.replace('http://', '')}/ws/logs/${containerId}?token=${this.token}&tail=${tail}`;
const ws = new WebSocket(url);
ws.onopen = () => {
console.log(`Подключение к контейнеру ${containerId} установлено`);
};
ws.onmessage = (event) => {
if (onMessage) onMessage(event.data);
};
ws.onerror = (error) => {
console.error(`Ошибка WebSocket для контейнера ${containerId}:`, error);
if (onError) onError(error);
};
ws.onclose = (event) => {
console.log(`Соединение с контейнером ${containerId} закрыто:`, event.code, event.reason);
if (onClose) onClose(event);
};
this.connections.set(containerId, ws);
return ws;
}
// Подключение к логам сервиса
connectToService(serviceName, options = {}) {
const { tail = 100, project, onMessage, onError, onClose } = options;
let url = `ws://${this.baseUrl.replace('http://', '')}/ws/fan/${serviceName}?token=${this.token}&tail=${tail}`;
if (project) url += `&project=${project}`;
const ws = new WebSocket(url);
ws.onopen = () => {
console.log(`Подключение к сервису ${serviceName} установлено`);
};
ws.onmessage = (event) => {
if (onMessage) onMessage(event.data);
};
ws.onerror = (error) => {
console.error(`Ошибка WebSocket для сервиса ${serviceName}:`, error);
if (onError) onError(error);
};
ws.onclose = (event) => {
console.log(`Соединение с сервисом ${serviceName} закрыто:`, event.code, event.reason);
if (onClose) onClose(event);
};
this.connections.set(serviceName, ws);
return ws;
}
// Подключение к группе сервисов
connectToServiceGroup(services, options = {}) {
const { tail = 100, project, onMessage, onError, onClose } = options;
let url = `ws://${this.baseUrl.replace('http://', '')}/ws/fan_group?services=${services}&token=${this.token}&tail=${tail}`;
if (project) url += `&project=${project}`;
const ws = new WebSocket(url);
ws.onopen = () => {
console.log(`Подключение к группе сервисов ${services} установлено`);
};
ws.onmessage = (event) => {
if (onMessage) onMessage(event.data);
};
ws.onerror = (error) => {
console.error(`Ошибка WebSocket для группы сервисов ${services}:`, error);
if (onError) onError(error);
};
ws.onclose = (event) => {
console.log(`Соединение с группой сервисов ${services} закрыто:`, event.code, event.reason);
if (onClose) onClose(event);
};
this.connections.set(`group:${services}`, ws);
return ws;
}
// Закрытие соединения
disconnect(identifier) {
const ws = this.connections.get(identifier);
if (ws) {
ws.close();
this.connections.delete(identifier);
}
}
// Закрытие всех соединений
disconnectAll() {
for (const [identifier, ws] of this.connections) {
ws.close();
}
this.connections.clear();
}
}
// Использование
async function main() {
// Получение токена
const loginResponse = await fetch('http://localhost:9001/api/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: 'admin',
password: 'your-password'
})
});
const {access_token} = await loginResponse.json();
// Создание WebSocket клиента
const wsClient = new LogBoardWebSocket('http://localhost:9001', access_token);
// Подключение к контейнеру
wsClient.connectToContainer('abc123def456', {
tail: 100,
onMessage: (data) => {
console.log('Логи контейнера:', data);
// Добавление в UI
appendToLogView(data);
},
onError: (error) => {
console.error('Ошибка:', error);
}
});
// Подключение к сервису
wsClient.connectToService('web', {
tail: 100,
onMessage: (data) => {
console.log('Логи сервиса:', data);
// Парсинг префикса для группировки
const match = data.match(/^\[([a-f0-9]+)\]\s+(.+)$/);
if (match) {
const [, containerId, logMessage] = match;
appendToServiceLogView(containerId, logMessage);
}
}
});
// Подключение к группе сервисов
wsClient.connectToServiceGroup('web,db,redis', {
tail: 100,
onMessage: (data) => {
console.log('Логи группы:', data);
// Парсинг префикса для группировки
const match = data.match(/^\[([a-f0-9]+)\s+(\w+)\]\s+(.+)$/);
if (match) {
const [, containerId, serviceName, logMessage] = match;
appendToGroupLogView(serviceName, containerId, logMessage);
}
}
});
}
// Функции для обновления UI
function appendToLogView(message) {
const logContainer = document.getElementById('log-container');
const logLine = document.createElement('div');
logLine.className = 'log-line';
logLine.textContent = message;
logContainer.appendChild(logLine);
logContainer.scrollTop = logContainer.scrollHeight;
}
function appendToServiceLogView(containerId, message) {
// Реализация для отображения логов сервиса
}
function appendToGroupLogView(serviceName, containerId, message) {
// Реализация для отображения логов группы сервисов
}
main().catch(console.error);
```
### Python
```python
import asyncio
import websockets
import json
import requests
class LogBoardWebSocket:
def __init__(self, base_url, token):
self.base_url = base_url.replace('http://', 'ws://')
self.token = token
self.connections = {}
async def connect_to_container(self, container_id, tail=100, callback=None):
"""Подключение к логам контейнера"""
uri = f"{self.base_url}/ws/logs/{container_id}?token={self.token}&tail={tail}"
try:
async with websockets.connect(uri) as websocket:
print(f"Подключение к контейнеру {container_id} установлено")
async for message in websocket:
if callback:
await callback(container_id, message)
else:
print(f"[{container_id}] {message}")
except websockets.exceptions.ConnectionClosed:
print(f"Соединение с контейнером {container_id} закрыто")
except Exception as e:
print(f"Ошибка подключения к контейнеру {container_id}: {e}")
async def connect_to_service(self, service_name, tail=100, project=None, callback=None):
"""Подключение к логам сервиса"""
uri = f"{self.base_url}/ws/fan/{service_name}?token={self.token}&tail={tail}"
if project:
uri += f"&project={project}"
try:
async with websockets.connect(uri) as websocket:
print(f"Подключение к сервису {service_name} установлено")
async for message in websocket:
if callback:
await callback(service_name, message)
else:
print(f"[{service_name}] {message}")
except websockets.exceptions.ConnectionClosed:
print(f"Соединение с сервисом {service_name} закрыто")
except Exception as e:
print(f"Ошибка подключения к сервису {service_name}: {e}")
async def connect_to_service_group(self, services, tail=100, project=None, callback=None):
"""Подключение к логам группы сервисов"""
uri = f"{self.base_url}/ws/fan_group?services={services}&token={self.token}&tail={tail}"
if project:
uri += f"&project={project}"
try:
async with websockets.connect(uri) as websocket:
print(f"Подключение к группе сервисов {services} установлено")
async for message in websocket:
if callback:
await callback(services, message)
else:
print(f"[{services}] {message}")
except websockets.exceptions.ConnectionClosed:
print(f"Соединение с группой сервисов {services} закрыто")
except Exception as e:
print(f"Ошибка подключения к группе сервисов {services}: {e}")
# Функции обратного вызова
async def container_log_callback(container_id, message):
"""Обработка логов контейнера"""
print(f"[{container_id}] {message}")
async def service_log_callback(service_name, message):
"""Обработка логов сервиса"""
print(f"[{service_name}] {message}")
async def group_log_callback(services, message):
"""Обработка логов группы сервисов"""
print(f"[{services}] {message}")
async def main():
# Получение токена
response = requests.post('http://localhost:9001/api/auth/login', json={
'username': 'admin',
'password': 'your-password'
})
token = response.json()['access_token']
# Создание WebSocket клиента
ws_client = LogBoardWebSocket('http://localhost:9001', token)
# Создание задач для одновременного подключения
tasks = [
ws_client.connect_to_container('abc123def456', tail=100, callback=container_log_callback),
ws_client.connect_to_service('web', tail=100, callback=service_log_callback),
ws_client.connect_to_service_group('web,db,redis', tail=100, callback=group_log_callback)
]
# Запуск всех подключений одновременно
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
```
### Node.js
```javascript
const WebSocket = require('ws');
const axios = require('axios');
class LogBoardWebSocket {
constructor(baseUrl, token) {
this.baseUrl = baseUrl.replace('http://', 'ws://');
this.token = token;
this.connections = new Map();
}
// Подключение к логам контейнера
connectToContainer(containerId, options = {}) {
const { tail = 100, onMessage, onError, onClose } = options;
const url = `${this.baseUrl}/ws/logs/${containerId}?token=${this.token}&tail=${tail}`;
const ws = new WebSocket(url);
ws.on('open', () => {
console.log(`Подключение к контейнеру ${containerId} установлено`);
});
ws.on('message', (data) => {
const message = data.toString();
if (onMessage) onMessage(message);
else console.log(`[${containerId}] ${message}`);
});
ws.on('error', (error) => {
console.error(`Ошибка WebSocket для контейнера ${containerId}:`, error);
if (onError) onError(error);
});
ws.on('close', (code, reason) => {
console.log(`Соединение с контейнером ${containerId} закрыто:`, code, reason);
if (onClose) onClose(code, reason);
});
this.connections.set(containerId, ws);
return ws;
}
// Подключение к логам сервиса
connectToService(serviceName, options = {}) {
const { tail = 100, project, onMessage, onError, onClose } = options;
let url = `${this.baseUrl}/ws/fan/${serviceName}?token=${this.token}&tail=${tail}`;
if (project) url += `&project=${project}`;
const ws = new WebSocket(url);
ws.on('open', () => {
console.log(`Подключение к сервису ${serviceName} установлено`);
});
ws.on('message', (data) => {
const message = data.toString();
if (onMessage) onMessage(message);
else console.log(`[${serviceName}] ${message}`);
});
ws.on('error', (error) => {
console.error(`Ошибка WebSocket для сервиса ${serviceName}:`, error);
if (onError) onError(error);
});
ws.on('close', (code, reason) => {
console.log(`Соединение с сервисом ${serviceName} закрыто:`, code, reason);
if (onClose) onClose(code, reason);
});
this.connections.set(serviceName, ws);
return ws;
}
// Закрытие соединения
disconnect(identifier) {
const ws = this.connections.get(identifier);
if (ws) {
ws.close();
this.connections.delete(identifier);
}
}
// Закрытие всех соединений
disconnectAll() {
for (const [identifier, ws] of this.connections) {
ws.close();
}
this.connections.clear();
}
}
async function main() {
try {
// Получение токена
const loginResponse = await axios.post('http://localhost:9001/api/auth/login', {
username: 'admin',
password: 'your-password'
});
const token = loginResponse.data.access_token;
// Создание WebSocket клиента
const wsClient = new LogBoardWebSocket('http://localhost:9001', token);
// Подключение к контейнеру
wsClient.connectToContainer('abc123def456', {
tail: 100,
onMessage: (message) => {
console.log('Логи контейнера:', message);
}
});
// Подключение к сервису
wsClient.connectToService('web', {
tail: 100,
onMessage: (message) => {
console.log('Логи сервиса:', message);
}
});
// Обработка сигналов завершения
process.on('SIGINT', () => {
console.log('Закрытие соединений...');
wsClient.disconnectAll();
process.exit(0);
});
} catch (error) {
console.error('Ошибка:', error.message);
}
}
main();
```
## Обработка ошибок
### Коды ошибок WebSocket
| Код | Описание |
|-----|----------|
| 1000 | Нормальное закрытие |
| 1001 | Удаленная сторона закрыла соединение |
| 1002 | Ошибка протокола |
| 1003 | Неподдерживаемый тип данных |
| 1006 | Аномальное закрытие |
| 1011 | Внутренняя ошибка сервера |
### Обработка ошибок аутентификации
```javascript
ws.onmessage = function(event) {
if (event.data.startsWith('ERROR:')) {
const error = event.data.substring(6);
console.error('Ошибка аутентификации:', error);
if (error.includes('token required') || error.includes('invalid token')) {
// Переподключение с новым токеном
reconnectWithNewToken();
}
} else {
// Обработка обычных логов
console.log('Логи:', event.data);
}
};
```
### Автоматическое переподключение
```javascript
class ReconnectingWebSocket {
constructor(url, options = {}) {
this.url = url;
this.options = options;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
this.reconnectInterval = options.reconnectInterval || 1000;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket соединение установлено');
this.reconnectAttempts = 0;
};
this.ws.onclose = (event) => {
console.log('WebSocket соединение закрыто:', event.code, event.reason);
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`Попытка переподключения ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
setTimeout(() => {
this.connect();
}, this.reconnectInterval * this.reconnectAttempts);
} else {
console.error('Превышено максимальное количество попыток переподключения');
}
};
this.ws.onerror = (error) => {
console.error('WebSocket ошибка:', error);
};
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
}
}
close() {
this.ws.close();
}
}
```
## Лучшие практики
### 1. Управление соединениями
```javascript
// Создание пула соединений
class WebSocketPool {
constructor() {
this.connections = new Map();
this.maxConnections = 10;
}
connect(identifier, url, options = {}) {
if (this.connections.size >= this.maxConnections) {
console.warn('Достигнут лимит соединений');
return null;
}
const ws = new WebSocket(url);
this.connections.set(identifier, ws);
ws.onclose = () => {
this.connections.delete(identifier);
};
return ws;
}
disconnect(identifier) {
const ws = this.connections.get(identifier);
if (ws) {
ws.close();
this.connections.delete(identifier);
}
}
}
```
### 2. Обработка больших объемов данных
```javascript
// Буферизация сообщений
class LogBuffer {
constructor(maxSize = 1000) {
this.buffer = [];
this.maxSize = maxSize;
}
add(message) {
this.buffer.push(message);
if (this.buffer.length > this.maxSize) {
this.buffer.shift(); // Удаляем старые сообщения
}
}
getMessages() {
return [...this.buffer];
}
clear() {
this.buffer = [];
}
}
// Использование
const logBuffer = new LogBuffer(1000);
ws.onmessage = function(event) {
logBuffer.add(event.data);
// Обновление UI каждые 100ms
if (!updateScheduled) {
updateScheduled = setTimeout(() => {
updateUI(logBuffer.getMessages());
updateScheduled = null;
}, 100);
}
};
```
### 3. Фильтрация логов
```javascript
// Фильтр по уровню логирования
class LogFilter {
constructor() {
this.filters = {
level: 'all', // debug, info, warn, error, all
service: null,
container: null,
text: null
};
}
setFilter(type, value) {
this.filters[type] = value;
}
shouldDisplay(message) {
// Фильтр по уровню
if (this.filters.level !== 'all') {
const levelMatch = message.toLowerCase().includes(`level=${this.filters.level}`);
if (!levelMatch) return false;
}
// Фильтр по сервису
if (this.filters.service) {
const serviceMatch = message.includes(`[${this.filters.service}]`);
if (!serviceMatch) return false;
}
// Фильтр по контейнеру
if (this.filters.container) {
const containerMatch = message.includes(`[${this.filters.container}]`);
if (!containerMatch) return false;
}
// Фильтр по тексту
if (this.filters.text) {
const textMatch = message.toLowerCase().includes(this.filters.text.toLowerCase());
if (!textMatch) return false;
}
return true;
}
}
// Использование
const logFilter = new LogFilter();
logFilter.setFilter('level', 'error');
ws.onmessage = function(event) {
if (logFilter.shouldDisplay(event.data)) {
console.log('Отфильтрованные логи:', event.data);
}
};
```
### 4. Мониторинг состояния соединений
```javascript
class ConnectionMonitor {
constructor() {
this.stats = {
totalMessages: 0,
totalBytes: 0,
connectionTime: null,
lastMessageTime: null,
errors: 0
};
}
onConnect() {
this.stats.connectionTime = new Date();
this.stats.totalMessages = 0;
this.stats.totalBytes = 0;
this.stats.errors = 0;
}
onMessage(message) {
this.stats.totalMessages++;
this.stats.totalBytes += message.length;
this.stats.lastMessageTime = new Date();
}
onError() {
this.stats.errors++;
}
getStats() {
return {
...this.stats,
uptime: this.stats.connectionTime ?
Date.now() - this.stats.connectionTime.getTime() : 0,
messagesPerSecond: this.stats.totalMessages /
(this.stats.uptime / 1000) || 0
};
}
}
```
## Ограничения и рекомендации
### Ограничения
- **Максимальное количество соединений:** 100 одновременных WebSocket соединений
- **Таймаут соединения:** 60 секунд бездействия
- **Размер сообщения:** до 1 MB на сообщение
- **Частота сообщений:** до 1000 сообщений в секунду
### Рекомендации
1. **Используйте переподключение** при разрыве соединений
2. **Ограничивайте количество соединений** для одного клиента
3. **Фильтруйте логи** на стороне клиента для снижения нагрузки
4. **Мониторьте состояние соединений** для диагностики проблем
5. **Используйте буферизацию** для больших объемов данных