初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,47 @@
|
||||
# ==============================
|
||||
# 灵台 · 魂镜后端镜像(Backend / FastAPI):Python 3.12 + uv
|
||||
# 启动入口 entrypoint.sh:先按 *_ENABLED 开关用 wait-for-it 等待依赖就绪,再 uv run python -m app.main
|
||||
# 工作目录 /app/backend,使 .env 中的相对路径 ../db ../logs ../config ../storage 解析到 /app 下。
|
||||
# ==============================
|
||||
FROM python:3.12-slim
|
||||
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
UV_LINK_MODE=copy \
|
||||
UV_COMPILE_BYTECODE=1 \
|
||||
TZ=Asia/Shanghai
|
||||
|
||||
WORKDIR /app/backend
|
||||
|
||||
# 系统依赖:
|
||||
# build-essential / libpq-dev —— 编译 asyncpg、argon2 等 C 扩展
|
||||
# curl —— 容器健康检查
|
||||
# tzdata —— 时区数据
|
||||
# netcat-openbsd —— wait-for-it 端口探测
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential libpq-dev curl tzdata netcat-openbsd \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" > /etc/timezone
|
||||
|
||||
# 安装 uv(沿用 backend/pyproject.toml 的清华镜像源,加速国内构建)
|
||||
RUN pip install --no-cache-dir uv -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# 先复制依赖清单,最大化 Docker 层缓存命中
|
||||
COPY backend/pyproject.toml backend/uv.lock ./
|
||||
|
||||
# 安装生产依赖(排除 dev 组、暂不安装项目本体)
|
||||
RUN uv sync --frozen --no-dev --no-install-project
|
||||
|
||||
# 复制后端源码并安装项目本体
|
||||
COPY backend/ ./
|
||||
RUN uv sync --frozen --no-dev
|
||||
|
||||
# 启动顺序:wait-for-it(端口探测工具)+ entrypoint.sh(按开关动态等待依赖后启动应用)
|
||||
COPY docker/backend/wait-for-it.sh /usr/local/bin/wait-for-it.sh
|
||||
COPY docker/backend/entrypoint.sh /app/backend/entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/wait-for-it.sh /app/backend/entrypoint.sh
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
# entrypoint 等待依赖就绪后 exec 应用;如需覆盖启动命令,覆盖此 ENTRYPOINT 即可
|
||||
ENTRYPOINT ["/app/backend/entrypoint.sh"]
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
# 后端启动入口:按 *_ENABLED 开关动态等待依赖就绪,再启动应用。
|
||||
# 仅等待「实际启用」的依赖,避免硬等待未启用的可选服务(与 environment-config-design 一致)。
|
||||
# 某依赖超时未就绪只告警不阻断——应用自身应具备连接重试逻辑。
|
||||
set -e
|
||||
|
||||
WAIT_TIMEOUT="${WAIT_TIMEOUT:-60}"
|
||||
WAIT=""
|
||||
|
||||
# postgres:正式环境(DATABASE_TYPE=pgsql)必需依赖
|
||||
if [ "${DATABASE_TYPE}" = "pgsql" ]; then
|
||||
WAIT="$WAIT ${POSTGRES_HOST:-hunjing-postgres}:${POSTGRES_PORT:-5432}"
|
||||
fi
|
||||
|
||||
# 可选依赖:仅在对应开关启用时等待
|
||||
if [ "${REDIS_ENABLED}" = "true" ]; then
|
||||
WAIT="$WAIT ${REDIS_HOST:-hunjing-redis}:${REDIS_PORT:-6379}"
|
||||
fi
|
||||
if [ "${VECTOR_DB_ENABLED}" = "true" ] && [ "${VECTOR_DB_TYPE}" = "milvus" ]; then
|
||||
WAIT="$WAIT ${MILVUS_HOST:-hunjing-milvus}:${MILVUS_PORT:-19530}"
|
||||
fi
|
||||
if [ "${GRAPH_DB_ENABLED}" = "true" ]; then
|
||||
case "${GRAPH_DB_TYPE}" in
|
||||
neo4j) WAIT="$WAIT ${NEO4J_HOST:-hunjing-neo4j}:7687" ;;
|
||||
nebulagraph) WAIT="$WAIT ${NEBULAGRAPH_HOST:-hunjing-nebula-graphd}:${NEBULAGRAPH_PORT:-9669}" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for target in $WAIT; do
|
||||
echo "[entrypoint] 等待依赖就绪: $target"
|
||||
/usr/local/bin/wait-for-it.sh "$target" -t "$WAIT_TIMEOUT" \
|
||||
|| echo "[entrypoint] 警告: $target 未就绪,继续启动(应用应具备连接重试)"
|
||||
done
|
||||
|
||||
echo "[entrypoint] 启动后端: uv run python -m app.main"
|
||||
exec uv run python -m app.main
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
# 等待 TCP host:port 就绪的工具(wait-for-it 自包含实现)。
|
||||
# 思路来自 https://github.com/vishnubob/wait-for-it(MIT),精简为项目内置脚本,
|
||||
# 避免依赖已废弃的 compose/wait-for-it 镜像。
|
||||
#
|
||||
# 用法:
|
||||
# wait-for-it.sh host:port [-t timeout] [-s] [-q] [-- command...]
|
||||
# -t / --timeout 超时秒数(默认 15)
|
||||
# -s / --strict 探测失败时不执行后续命令、返回非零
|
||||
# -q / --quiet 不输出状态
|
||||
# -- command... 探测成功后执行的命令
|
||||
set -o pipefail
|
||||
|
||||
cmdname=$(basename "$0")
|
||||
echoerr() { [ "${QUIET:-0}" != 1 ] && echo "$@" 1>&2; }
|
||||
|
||||
usage() {
|
||||
cat <<EOF >&2
|
||||
Usage: $cmdname host:port [-t timeout] [-s] [-q] [-- command...]
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
HOST=""
|
||||
PORT=""
|
||||
TIMEOUT=15
|
||||
STRICT=0
|
||||
QUIET=0
|
||||
CLI=()
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
*:*) HOST=${1%%:*}; PORT=${1##*:}; shift ;;
|
||||
-h) HOST="$2"; shift 2 ;;
|
||||
--host=*) HOST="${1#*=}"; shift ;;
|
||||
-p) PORT="$2"; shift 2 ;;
|
||||
--port=*) PORT="${1#*=}"; shift ;;
|
||||
-t) TIMEOUT="$2"; shift 2 ;;
|
||||
--timeout=*) TIMEOUT="${1#*=}"; shift ;;
|
||||
-s|--strict) STRICT=1; shift ;;
|
||||
-q|--quiet) QUIET=1; shift ;;
|
||||
--) shift; CLI=("$@"); break ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$HOST" ] || [ -z "$PORT" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
# 探测方式:优先 nc,否则用 bash 内建 /dev/tcp(python:3.12-slim 自带 bash)。
|
||||
USE_NC=0
|
||||
if command -v nc >/dev/null 2>&1; then
|
||||
USE_NC=1
|
||||
fi
|
||||
|
||||
probe() {
|
||||
if [ "$USE_NC" -eq 1 ]; then
|
||||
nc -z "$HOST" "$PORT"
|
||||
else
|
||||
(echo > "/dev/tcp/$HOST/$PORT")
|
||||
fi
|
||||
}
|
||||
|
||||
echoerr "$cmdname: 等待 $HOST:$PORT(超时 ${TIMEOUT}s)"
|
||||
start=$(date +%s)
|
||||
while :; do
|
||||
if probe >/dev/null 2>&1; then
|
||||
echoerr "$cmdname: $HOST:$PORT 就绪(耗时 $(($(date +%s) - start))s)"
|
||||
if [ "${#CLI[@]}" -gt 0 ]; then
|
||||
exec "${CLI[@]}"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
if [ "$TIMEOUT" -ge 0 ] && [ "$(date +%s)" -gt $((start + TIMEOUT)) ]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echoerr "$cmdname: $HOST:$PORT 在 ${TIMEOUT}s 内未就绪"
|
||||
if [ "${#CLI[@]}" -gt 0 ]; then
|
||||
if [ "$STRICT" -eq 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
exec "${CLI[@]}"
|
||||
fi
|
||||
exit 1
|
||||
Reference in new issue
Block a user