FROM python:3.11-slim # ==== 基本設定 ==== ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PIP_NO_CACHE_DIR=1 \ DEBIAN_FRONTEND=noninteractive WORKDIR /app # ==== ネイティブ拡張が要らなければこの層は省略可 ==== RUN apt-get update \ && apt-get install -y --no-install-recommends build-essential \ && rm -rf /var/lib/apt/lists/* # ==== リポジトリ全体コピー ==== COPY . /app # ==== (1) コロン連結ファイル名を本来のディレクトリに復元 ==== # 例: "backend:app:main.py" -> "backend/app/main.py" RUN python - <<'PY' import os, shutil root = "/app" for name in list(os.listdir(root)): p = os.path.join(root, name) if os.path.isfile(p) and ":" in name: dst = os.path.join(root, name.replace(":", "/")) os.makedirs(os.path.dirname(dst), exist_ok=True) shutil.move(p, dst) PY # ==== (2) 依存インストール(backend/requirements.txt → requirements.txt → 直接指定) ==== RUN bash -lc '\ set -euo pipefail; \ if [ -f backend/requirements.txt ]; then \ pip install --no-cache-dir -r backend/requirements.txt; \ elif [ -f requirements.txt ]; then \ pip install --no-cache-dir -r requirements.txt; \ else \ echo "[info] requirements.txt が無いため最小依存を直接インストールします"; \ pip install --no-cache-dir \ fastapi==0.112.0 \ uvicorn[standard]==0.30.6 \ pydantic==2.8.2 \ python-dotenv==1.0.1 \ httpx==0.27.0 \ openai==1.50.0; \ fi' # ==== (3) ルートの app.py があれば退避して “app” パッケージと衝突しないようにする ==== RUN bash -lc '\ set -euo pipefail; \ if [ -f /app/app.py ]; then \ echo "[warn] /app/app.py を _app_legacy.py へリネームしてモジュール衝突を回避します"; \ mv /app/app.py /app/_app_legacy.py; \ fi' # ==== (4) アプリ配置の正規化(backend/app → /app/app) ==== RUN bash -lc '\ set -euo pipefail; \ if [ -d /app/backend/app ]; then \ rm -rf /app/app && mv /app/backend/app /app/app; \ fi' # ==== (5) エントリ確認(必須: /app/app/main.py に FastAPI インスタンス app ) ==== RUN bash -lc '\ set -e; \ if [ ! -f /app/app/main.py ]; then \ echo "[error] Missing /app/app/main.py(FastAPI エントリが見つかりません)"; \ echo "----- /app tree -----"; \ ls -R /app || true; \ exit 1; \ fi' # ==== 起動 ==== EXPOSE 8000 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]