feat: dockerize app and convert to pyproject setup

- Add pyproject.toml with proper metadata and dependency groups
- Create multi-stage Dockerfile for backend
- Add docker-compose.yml with dev/prod profiles
- Create frontend Dockerfile with nginx
- Add .dockerignore for optimized builds
- Update README with Docker instructions and troubleshooting
- Remove requirements.txt in favor of pyproject.toml
- Ensure data persistence with Docker volumes
This commit is contained in:
2026-05-11 22:50:11 +02:00
parent abeb64637e
commit cc694e71b4
15 changed files with 632 additions and 21 deletions
+50
View File
@@ -0,0 +1,50 @@
# Stage 1: Builder
FROM python:3.14 AS builder
WORKDIR /app
# Install build dependencies
RUN pip install --no-cache-dir setuptools wheel
# Copy pyproject.toml first for better layer caching
COPY pyproject.toml ./
# Copy source code
COPY app/ ./app/
COPY backup/ ./backup/
COPY alembic/ ./alembic/
COPY alembic.ini ./
# Build the package with dev dependencies
RUN pip install --no-cache-dir -e ".[dev]"
# Stage 2: Runtime
FROM python:3.14-slim
WORKDIR /app
# Create non-root user
RUN groupadd -r backup-tool && useradd -r -g backup-tool backup-tool
# Copy installed packages from builder
COPY --from=builder /usr/local/lib/python3.14/site-packages/ /usr/local/lib/python3.14/site-packages/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
# Copy application code
COPY --from=builder /app/ ./
# Create data directory for SQLite and backups
RUN mkdir -p /app/data /app/backups && \
chown -R backup-tool:backup-tool /app
USER backup-tool
# Expose port
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')" || exit 1
# Default command
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
+4
View File
@@ -43,6 +43,10 @@ app.include_router(dashboard.router)
async def health_check():
return {"status": "healthy"}
def main():
import uvicorn
uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)
# Static files for production
frontend_dist = os.path.join(os.path.dirname(__file__), "../../frontend/dist")
if os.path.exists(frontend_dist):
+68
View File
@@ -0,0 +1,68 @@
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "backup-tool"
version = "0.1.0"
description = "Web-based backup management tool for small teams and SMBs"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.11"
authors = [
{name = "Backup Tool Team"}
]
keywords = ["backup", "restore", "scheduler", "web"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: System :: Archiving :: Backup",
]
dependencies = [
"fastapi>=0.115.0",
"uvicorn[standard]>=0.34.0",
"sqlalchemy[asyncio]>=2.0.0",
"aiosqlite>=0.21.0",
"alembic>=1.15.0",
"pydantic>=2.13.0",
"pydantic-settings>=2.9.0",
"apscheduler>=3.11.0",
"paramiko>=3.5.0",
"aiofiles>=23.2.0",
"httpx>=0.28.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.3.0",
"pytest-asyncio>=0.26.0",
]
prod = [
"gunicorn>=23.0.0",
]
[project.scripts]
backup-tool = "app.main:main"
[project.urls]
Homepage = "https://github.com/backup-tool/backup-tool"
Documentation = "https://github.com/backup-tool/backup-tool#readme"
Repository = "https://github.com/backup-tool/backup-tool.git"
[tool.setuptools.packages.find]
where = ["."]
include = ["app*", "backup*", "alembic*"]
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
pythonpath = [".", "app", "backup"]
[tool.setuptools.package-data]
alembic = ["*.ini", "*.py", "*.mako"]
-12
View File
@@ -1,12 +0,0 @@
fastapi==0.109.0
uvicorn[standard]==0.27.0
sqlalchemy[asyncio]==2.0.25
aiosqlite==0.19.0
alembic==1.13.1
pydantic==2.5.3
pydantic-settings==2.1.0
apscheduler==3.10.4
paramiko==3.4.0
pytest==7.4.4
pytest-asyncio==0.21.1
httpx==0.26.0