fix: resolve static files and import issues

- Fix static files not loading due to volume mount conflict
- Remove problematic volume mount from docker-compose.yml
- Add __init__.py files to make Python packages
- Fix all import statements to use relative imports
- Update start.sh to use correct module name
- Update config.py with correct default paths and values
- Ensure all environment variables are properly loaded from .env file
This commit is contained in:
Сергей Антропов 2025-08-20 18:14:35 +03:00
parent 9ecfb9f360
commit 9d4add2a7d
20 changed files with 76 additions and 31 deletions

View File

@ -10,6 +10,9 @@ COPY app/app.py /app/app.py
COPY app/excluded_containers.json /app/excluded_containers.json COPY app/excluded_containers.json /app/excluded_containers.json
COPY ./app/templates /app/templates COPY ./app/templates /app/templates
COPY ./app/static /app/static COPY ./app/static /app/static
COPY ./app/core /app/core
COPY ./app/api /app/api
COPY ./app/models /app/models
# Создаем пользователя и добавляем в группу docker # Создаем пользователя и добавляем в группу docker
RUN useradd -m appuser && \ RUN useradd -m appuser && \

7
app/__init__.py Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LogBoard+ - Основной пакет приложения
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

7
app/api/__init__.py Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LogBoard+ - API модули приложения
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

7
app/api/v1/__init__.py Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LogBoard+ - API v1 модули приложения
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

View File

@ -0,0 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LogBoard+ - API endpoints модули приложения
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

View File

@ -12,14 +12,14 @@ from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, status, Response from fastapi import APIRouter, Depends, HTTPException, status, Response
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from app.core.auth import ( from core.auth import (
authenticate_user, authenticate_user,
create_access_token, create_access_token,
verify_token, verify_token,
get_current_user, get_current_user,
ACCESS_TOKEN_EXPIRE_MINUTES ACCESS_TOKEN_EXPIRE_MINUTES
) )
from app.models.auth import UserLogin, Token from models.auth import UserLogin, Token
router = APIRouter() router = APIRouter()

View File

@ -11,8 +11,8 @@ from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, Body from fastapi import APIRouter, Depends, HTTPException, Query, Body
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from app.core.auth import get_current_user from core.auth import get_current_user
from app.core.docker import ( from core.docker import (
load_excluded_containers, load_excluded_containers,
save_excluded_containers, save_excluded_containers,
get_all_projects, get_all_projects,

View File

@ -15,9 +15,9 @@ from fastapi.responses import JSONResponse
import docker import docker
from app.core.auth import get_current_user from core.auth import get_current_user
from app.core.docker import docker_client, DEFAULT_TAIL from core.docker import docker_client, DEFAULT_TAIL
from app.core.logger import api_logger from core.logger import api_logger
router = APIRouter() router = APIRouter()
@ -206,7 +206,7 @@ def api_snapshot(
): ):
"""Сохранить снимок логов""" """Сохранить снимок логов"""
import os import os
from app.core.config import SNAP_DIR from core.config import SNAP_DIR
# Save posted content as a snapshot file # Save posted content as a snapshot file
safe_service = re.sub(r"[^a-zA-Z0-9_.-]+", "_", service or container_id[:12]) safe_service = re.sub(r"[^a-zA-Z0-9_.-]+", "_", service or container_id[:12])

View File

@ -9,8 +9,8 @@ LogBoard+ - Страницы API
from fastapi import APIRouter, Request, Depends, HTTPException from fastapi import APIRouter, Request, Depends, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse, PlainTextResponse from fastapi.responses import HTMLResponse, RedirectResponse, PlainTextResponse
from app.core.auth import verify_token, get_current_user from core.auth import verify_token, get_current_user
from app.core.config import templates, AJAX_UPDATE_INTERVAL, DEFAULT_TAIL, SKIP_UNHEALTHY from core.config import templates, AJAX_UPDATE_INTERVAL, DEFAULT_TAIL, SKIP_UNHEALTHY
router = APIRouter() router = APIRouter()

View File

@ -8,8 +8,8 @@ LogBoard+ - Настройки API
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from app.core.auth import get_current_user from core.auth import get_current_user
from app.core.config import AJAX_UPDATE_INTERVAL, DEFAULT_TAIL, SKIP_UNHEALTHY from core.config import AJAX_UPDATE_INTERVAL, DEFAULT_TAIL, SKIP_UNHEALTHY
router = APIRouter() router = APIRouter()

View File

@ -12,9 +12,9 @@ from typing import Optional
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query, Depends from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query, Depends
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from app.core.auth import verify_token, get_current_user from core.auth import verify_token, get_current_user
from app.core.docker import docker_client, DEFAULT_TAIL from core.docker import docker_client, DEFAULT_TAIL
from app.core.logger import websocket_logger from core.logger import websocket_logger
from datetime import datetime from datetime import datetime
router = APIRouter() router = APIRouter()

View File

@ -11,9 +11,9 @@ from fastapi import FastAPI, Request, HTTPException
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from app.core.config import DEBUG_MODE, SNAP_DIR, STATIC_DIR, APP_PORT from core.config import DEBUG_MODE, SNAP_DIR, STATIC_DIR, APP_PORT
from app.api.v1.router import api_router, pages_router from api.v1.router import api_router, pages_router
from app.core.logger import app_logger from core.logger import app_logger
# Инициализация FastAPI # Инициализация FastAPI
app = FastAPI( app = FastAPI(

7
app/core/__init__.py Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LogBoard+ - Основные модули приложения
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

View File

@ -15,7 +15,7 @@ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from passlib.context import CryptContext from passlib.context import CryptContext
import jwt import jwt
from app.core.config import ( from core.config import (
SECRET_KEY, SECRET_KEY,
ALGORITHM, ALGORITHM,
ACCESS_TOKEN_EXPIRE_MINUTES, ACCESS_TOKEN_EXPIRE_MINUTES,

View File

@ -12,16 +12,16 @@ from fastapi.templating import Jinja2Templates
# Настройки приложения # Настройки приложения
APP_PORT = int(os.getenv("LOGBOARD_PORT", "9001")) APP_PORT = int(os.getenv("LOGBOARD_PORT", "9001"))
DEFAULT_TAIL = int(os.getenv("LOGBOARD_TAIL", "500")) DEFAULT_TAIL = int(os.getenv("LOGBOARD_TAIL", "500"))
DEFAULT_PROJECT = os.getenv("COMPOSE_PROJECT_NAME") DEFAULT_PROJECT = os.getenv("COMPOSE_PROJECT_NAME", "myproj")
DEFAULT_PROJECTS = os.getenv("LOGBOARD_PROJECTS") DEFAULT_PROJECTS = os.getenv("LOGBOARD_PROJECTS", "")
SKIP_UNHEALTHY = os.getenv("LOGBOARD_SKIP_UNHEALTHY", "true").lower() == "true" SKIP_UNHEALTHY = os.getenv("LOGBOARD_SKIP_UNHEALTHY", "true").lower() == "true"
CONTAINER_LIST_TIMEOUT = int(os.getenv("LOGBOARD_CONTAINER_LIST_TIMEOUT", "10")) CONTAINER_LIST_TIMEOUT = int(os.getenv("LOGBOARD_CONTAINER_LIST_TIMEOUT", "10"))
CONTAINER_INFO_TIMEOUT = int(os.getenv("LOGBOARD_CONTAINER_INFO_TIMEOUT", "3")) CONTAINER_INFO_TIMEOUT = int(os.getenv("LOGBOARD_CONTAINER_INFO_TIMEOUT", "3"))
HEALTH_CHECK_TIMEOUT = int(os.getenv("LOGBOARD_HEALTH_CHECK_TIMEOUT", "2")) HEALTH_CHECK_TIMEOUT = int(os.getenv("LOGBOARD_HEALTH_CHECK_TIMEOUT", "2"))
# Настройки безопасности # Настройки безопасности
SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-here-change-in-production") SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key-here")
ENCRYPTION_KEY = os.getenv("ENCRYPTION_KEY", "your-encryption-key-here-change-in-production") ENCRYPTION_KEY = os.getenv("ENCRYPTION_KEY", "your-encryption-key-here")
ALGORITHM = "HS256" ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("SESSION_TIMEOUT", "3600")) // 60 # 1 час по умолчанию ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("SESSION_TIMEOUT", "3600")) // 60 # 1 час по умолчанию
@ -39,8 +39,8 @@ DEBUG_MODE = os.getenv("DEBUG_MODE", "false").lower() == "true"
templates = Jinja2Templates(directory="app/templates") templates = Jinja2Templates(directory="app/templates")
# Директории # Директории
SNAP_DIR = os.getenv("LOGBOARD_SNAPSHOT_DIR", "./snapshots") SNAP_DIR = os.getenv("LOGBOARD_SNAPSHOT_DIR", "/app/snapshots")
STATIC_DIR = os.getenv("LOGBOARD_STATIC_DIR", "./app/static") STATIC_DIR = os.getenv("LOGBOARD_STATIC_DIR", "/app/static")
INDEX_HTML = os.getenv("LOGBOARD_INDEX_HTML", "./app/templates/index.html") INDEX_HTML = os.getenv("LOGBOARD_INDEX_HTML", "./app/templates/index.html")
# Настройки веб-интерфейса # Настройки веб-интерфейса
@ -72,6 +72,7 @@ DOCKER_CERT_PATH = os.getenv("DOCKER_CERT_PATH", "")
DOCKER_NETWORKS = os.getenv("DOCKER_NETWORKS", "iaas,infrastructure_iaas") DOCKER_NETWORKS = os.getenv("DOCKER_NETWORKS", "iaas,infrastructure_iaas")
# Настройки логирования # Настройки логирования
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
LOG_FORMAT = os.getenv("LOG_FORMAT", "json") LOG_FORMAT = os.getenv("LOG_FORMAT", "json")
# Временная зона # Временная зона

View File

@ -12,13 +12,13 @@ from typing import List, Dict, Optional
import docker import docker
from app.core.config import ( from core.config import (
DEFAULT_TAIL, DEFAULT_TAIL,
DEFAULT_PROJECT, DEFAULT_PROJECT,
DEFAULT_PROJECTS, DEFAULT_PROJECTS,
SKIP_UNHEALTHY SKIP_UNHEALTHY
) )
from app.core.logger import docker_logger from core.logger import docker_logger
# Инициализация Docker клиента # Инициализация Docker клиента
docker_client = docker.from_env() docker_client = docker.from_env()

View File

@ -11,7 +11,7 @@ import sys
from typing import Optional from typing import Optional
import os import os
from app.core.config import DEBUG_MODE from core.config import DEBUG_MODE
def setup_logger(name: str = "logboard", level: Optional[str] = None) -> logging.Logger: def setup_logger(name: str = "logboard", level: Optional[str] = None) -> logging.Logger:
""" """

7
app/models/__init__.py Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LogBoard+ - Модели данных приложения
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""

View File

@ -9,7 +9,6 @@ services:
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
- ./snapshots:/app/snapshots - ./snapshots:/app/snapshots
- ./:/app
restart: unless-stopped restart: unless-stopped
user: 0:0 user: 0:0
networks: networks:

View File

@ -20,7 +20,7 @@ if [ "$DEBUG_MODE" = "true" ]; then
echo "Swagger UI: http://0.0.0.0:$LOGBOARD_PORT/docs" echo "Swagger UI: http://0.0.0.0:$LOGBOARD_PORT/docs"
echo "ReDoc: http://0.0.0.0:$LOGBOARD_PORT/redoc" echo "ReDoc: http://0.0.0.0:$LOGBOARD_PORT/redoc"
exec uvicorn app.app:app \ exec uvicorn app:app \
--host 0.0.0.0 \ --host 0.0.0.0 \
--port $LOGBOARD_PORT \ --port $LOGBOARD_PORT \
--reload \ --reload \
@ -28,7 +28,7 @@ if [ "$DEBUG_MODE" = "true" ]; then
else else
echo "Starting in PRODUCTION mode..." echo "Starting in PRODUCTION mode..."
exec uvicorn app.app:app \ exec uvicorn app:app \
--host 0.0.0.0 \ --host 0.0.0.0 \
--port $LOGBOARD_PORT \ --port $LOGBOARD_PORT \
--log-level info --log-level info