deploy(docker): support deploy with docker
This commit is contained in:
@@ -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"
|
||||||
|
|
||||||
|
|||||||
66
Dockerfile
66
Dockerfile
@@ -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
39
Dockerfile-osurx
Normal 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"]
|
||||||
@@ -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
77
docker-compose-osurx.yml
Normal 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
|
||||||
@@ -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
13
docker-entrypoint.sh
Normal 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 "$@"
|
||||||
@@ -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.",
|
||||||
|
|||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user