deploy(docker): support deploy with docker

This commit is contained in:
MingxuanGame
2025-08-10 08:28:01 +00:00
parent 8c18c8e519
commit 314fbf827b
9 changed files with 260 additions and 142 deletions

View File

@@ -1,5 +1,10 @@
# 数据库 URL # 数据库设置
DATABASE_URL="mysql+aiomysql://root:password@127.0.0.1:3306/osu_api" MYSQL_HOST="localhost"
MYSQL_PORT=3306
MYSQL_DATABASE="osu_api"
MYSQL_USER="osu_api"
MYSQL_PASSWORD="password"
MYSQL_ROOT_PASSWORD="password"
# Redis URL # Redis URL
REDIS_URL="redis://127.0.0.1:6379/0" REDIS_URL="redis://127.0.0.1:6379/0"

View File

@@ -1,28 +1,38 @@
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
WORKDIR /app WORKDIR /app
ENV UV_PROJECT_ENVIRONMENT=syncvenv
RUN apt-get update && apt-get install -y \
# 安装系统依赖 gcc \
RUN apt-get update && apt-get install -y \ pkg-config \
gcc \ default-libmysqlclient-dev \
pkg-config \ curl \
default-libmysqlclient-dev \ netcat-openbsd \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# 复制依赖文件 RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
COPY uv.lock . ENV PATH="/root/.cargo/bin:${PATH}"
COPY pyproject.toml .
COPY requirements.txt . ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# 安装Python依赖 ENV UV_PROJECT_ENVIRONMENT=/app/.venv
RUN pip install -r requirements.txt
COPY pyproject.toml uv.lock ./
# 复制应用代码 COPY packages/ ./packages/
COPY . .
RUN uv sync --frozen --no-dev
# 暴露端口
EXPOSE 8000 RUN uv pip install rosu-pp-py
# 启动命令 COPY . .
CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
ENTRYPOINT ["/app/docker-entrypoint.sh"]
CMD ["uv", "run", "--no-sync", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

39
Dockerfile-osurx Normal file
View File

@@ -0,0 +1,39 @@
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
gcc \
pkg-config \
default-libmysqlclient-dev \
curl \
netcat-openbsd \
git \
&& rm -rf /var/lib/apt/lists/*
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
ENV UV_PROJECT_ENVIRONMENT=/app/.venv
COPY pyproject.toml uv.lock ./
COPY packages/ ./packages/
RUN uv sync --frozen --no-dev
RUN uv pip install git+https://github.com/ppy-sb/rosu-pp-py.git
COPY . .
COPY docker-entrypoint.sh /app/docker-entrypoint.sh
RUN chmod +x /app/docker-entrypoint.sh
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
ENTRYPOINT ["/app/docker-entrypoint.sh"]
CMD ["uv", "run", "--no-sync", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -10,9 +10,18 @@ class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
# 数据库设置 # 数据库设置
database_url: str = "mysql+aiomysql://root:password@127.0.0.1:3306/osu_api" mysql_host: str = "localhost"
mysql_port: int = 3306
mysql_database: str = "osu_api"
mysql_user: str = "osu_api"
mysql_password: str = "password"
mysql_root_password: str = "password"
redis_url: str = "redis://127.0.0.1:6379/0" redis_url: str = "redis://127.0.0.1:6379/0"
@property
def database_url(self) -> str:
return f"mysql+aiomysql://{self.mysql_user}:{self.mysql_password}@{self.mysql_host}:{self.mysql_port}/{self.mysql_database}"
# JWT 设置 # JWT 设置
secret_key: str = Field(default="your-secret-key-here", alias="jwt_secret_key") secret_key: str = Field(default="your-secret-key-here", alias="jwt_secret_key")
algorithm: str = "HS256" algorithm: str = "HS256"

77
docker-compose-osurx.yml Normal file
View File

@@ -0,0 +1,77 @@
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile-osurx
container_name: osu_api_server_osurx
ports:
- "8000:8000"
environment:
- MYSQL_HOST=mysql
- MYSQL_PORT=3306
- REDIS_URL=redis://redis:6379/0
- ENABLE_OSU_RX=true
- ENABLE_OSU_AP=true
- ENABLE_ALL_MODS_PP=true
- ENABLE_SUPPORTER_FOR_ALL_USERS=true
- ENABLE_ALL_BEATMAP_LEADERBOARD=true
env_file:
- .env
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./replays:/app/replays
- ./static:/app/static
restart: unless-stopped
networks:
- osu-network
mysql:
image: mysql:8.0
container_name: osu_api_mysql_osurx
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
- ./mysql-init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
interval: 10s
start_period: 40s
restart: unless-stopped
networks:
- osu-network
redis:
image: redis:7-alpine
container_name: osu_api_redis_osurx
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 5s
retries: 5
interval: 10s
start_period: 10s
restart: unless-stopped
networks:
- osu-network
command: redis-server --appendonly yes
volumes:
mysql_data:
redis_data:
networks:
osu-network:
driver: bridge

View File

@@ -1,50 +1,72 @@
version: '3.8' version: '3.8'
services: services:
mysql: app:
image: mysql:8.0 build:
container_name: osu_api_mysql context: .
environment: dockerfile: Dockerfile
MYSQL_ROOT_PASSWORD: password container_name: osu_api_server
MYSQL_DATABASE: osu_api ports:
MYSQL_USER: osu_user - "8000:8000"
MYSQL_PASSWORD: osu_password environment:
ports: - MYSQL_HOST=mysql
- "3306:3306" - MYSQL_PORT=3306
volumes: - REDIS_URL=redis://redis:6379/0
- mysql_data:/var/lib/mysql env_file:
- ./mysql-init:/docker-entrypoint-initdb.d - .env
restart: unless-stopped depends_on:
mysql:
redis: condition: service_healthy
image: redis:7-alpine redis:
container_name: osu_api_redis condition: service_healthy
ports: volumes:
- "6379:6379" - ./replays:/app/replays
volumes: - ./static:/app/static
- redis_data:/data restart: unless-stopped
restart: unless-stopped networks:
command: redis-server --appendonly yes - osu-network
api: mysql:
build: . image: mysql:8.0
container_name: osu_api_server container_name: osu_api_mysql
ports: environment:
- "8000:8000" - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
environment: - MYSQL_DATABASE=${MYSQL_DATABASE}
DATABASE_URL: mysql+aiomysql://osu_user:osu_password@mysql:3306/osu_api - MYSQL_USER=${MYSQL_USER}
REDIS_URL: redis://redis:6379/0 - MYSQL_PASSWORD=${MYSQL_PASSWORD}
SECRET_KEY: your-production-secret-key-here volumes:
OSU_CLIENT_ID: "5" - mysql_data:/var/lib/mysql
OSU_CLIENT_SECRET: "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk" - ./mysql-init:/docker-entrypoint-initdb.d
depends_on: healthcheck:
- mysql test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
- redis timeout: 20s
restart: unless-stopped retries: 10
volumes: interval: 10s
- ./:/app start_period: 40s
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload restart: unless-stopped
networks:
volumes: - osu-network
mysql_data:
redis_data: redis:
image: redis:7-alpine
container_name: osu_api_redis
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 5s
retries: 5
interval: 10s
start_period: 10s
restart: unless-stopped
networks:
- osu-network
command: redis-server --appendonly yes
volumes:
mysql_data:
redis_data:
networks:
osu-network:
driver: bridge

13
docker-entrypoint.sh Normal file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
set -e
echo "Waiting for database connection..."
while ! nc -z $MYSQL_HOST $MYSQL_PORT; do
sleep 1
done
echo "Database connected"
echo "Running alembic..."
uv run --no-sync alembic upgrade head
exec "$@"

View File

@@ -2,8 +2,8 @@ from __future__ import annotations
import asyncio import asyncio
from logging.config import fileConfig from logging.config import fileConfig
import os
from app.config import settings
from app.database import * # noqa: F403 from app.database import * # noqa: F403
from alembic import context from alembic import context
@@ -45,7 +45,8 @@ def run_migrations_offline() -> None:
script output. script output.
""" """
url = os.environ.get("DATABASE_URL", config.get_main_option("sqlalchemy.url")) url = settings.database_url
print(url)
context.configure( context.configure(
url=url, url=url,
target_metadata=target_metadata, target_metadata=target_metadata,
@@ -73,8 +74,7 @@ async def run_async_migrations() -> None:
""" """
sa_config = config.get_section(config.config_ini_section, {}) sa_config = config.get_section(config.config_ini_section, {})
if db_url := os.environ.get("DATABASE_URL"): sa_config["sqlalchemy.url"] = settings.database_url
sa_config["sqlalchemy.url"] = db_url
connectable = async_engine_from_config( connectable = async_engine_from_config(
sa_config, sa_config,
prefix="sqlalchemy.", prefix="sqlalchemy.",

View File

@@ -1,57 +0,0 @@
aiomysql==0.2.0
alembic==1.16.4
annotated-types==0.7.0
anyio==4.9.0
bcrypt==4.3.0
certifi==2025.7.14
cffi==1.17.1
cfgv==3.4.0
click==8.2.1
cryptography==45.0.5
distlib==0.4.0
dnspython==2.7.0
ecdsa==0.19.1
email-validator==2.2.0
fastapi==0.116.1
filelock==3.18.0
greenlet==3.2.3
h11==0.16.0
httpcore==1.0.9
httptools==0.6.4
httpx==0.28.1
identify==2.6.12
idna==3.10
loguru==0.7.3
mako==1.3.10
markupsafe==3.0.2
maturin==1.9.2
-e file:///workspaces/osu_lazer_api/packages/msgpack_lazer_api
nodeenv==1.9.1
passlib==1.7.4
platformdirs==4.3.8
pre-commit==4.2.0
pyasn1==0.6.1
pycparser==2.22
pydantic==2.11.7
pydantic-core==2.33.2
pymysql==1.1.1
python-dotenv==1.1.1
python-jose==3.5.0
python-multipart==0.0.20
pyyaml==6.0.2
redis==6.2.0
rosu-pp-py==3.1.0
rsa==4.9.1
ruff==0.12.4
six==1.17.0
sniffio==1.3.1
sqlalchemy==2.0.41
sqlmodel==0.0.24
starlette==0.47.2
typing-extensions==4.14.1
typing-inspection==0.4.1
uvicorn==0.35.0
uvloop==0.21.0
virtualenv==20.32.0
watchfiles==1.1.0
websockets==15.0.1