241 lines
6.6 KiB
Bash
Executable File
241 lines
6.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
cd "$SCRIPT_DIR"
|
||
|
||
COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.yml}"
|
||
ENV_FILE="${ENV_FILE:-.env}"
|
||
PROJECT_NAME="${PROJECT_NAME:-ai-trading}"
|
||
|
||
if ! command -v docker >/dev/null 2>&1; then
|
||
echo "[ERROR] docker 未安装,请先安装 Docker。"
|
||
exit 1
|
||
fi
|
||
|
||
if ! docker compose version >/dev/null 2>&1; then
|
||
echo "[ERROR] docker compose 不可用,请升级 Docker Desktop 或安装 compose 插件。"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ ! -f "$COMPOSE_FILE" ]]; then
|
||
echo "[ERROR] 未找到 $COMPOSE_FILE"
|
||
exit 1
|
||
fi
|
||
|
||
MODE="${1:-local}"
|
||
ACTION="${2:-up}"
|
||
QUERY="${3:-}"
|
||
|
||
compose_cmd=(
|
||
docker compose
|
||
-p "$PROJECT_NAME"
|
||
-f "$COMPOSE_FILE"
|
||
)
|
||
|
||
if [[ -n "$ENV_FILE" ]]; then
|
||
if [[ -f "$ENV_FILE" ]]; then
|
||
compose_cmd+=(--env-file "$ENV_FILE")
|
||
else
|
||
echo "[WARN] 未找到 env 文件: ${ENV_FILE}, 已跳过 --env-file"
|
||
fi
|
||
fi
|
||
|
||
show_help() {
|
||
cat <<'EOF'
|
||
用法:
|
||
./start.sh [mode] [action]
|
||
|
||
mode:
|
||
local 本地开发(默认)
|
||
prod 生产部署
|
||
|
||
action:
|
||
up 启动服务(默认)
|
||
down 停止并删除容器/网络
|
||
restart 重启服务
|
||
quick 一键清理并启动(cleanup + up + web)
|
||
logs 查看日志(Ctrl+C 退出)
|
||
status 查看服务状态
|
||
pull 拉取基础镜像
|
||
build 构建镜像
|
||
quote 股票速查(代码/名称)
|
||
web 启动前端页面(信息+曲线+买卖点)
|
||
cleanup 清理历史遗留容器/项目(推荐迁移后执行一次)
|
||
|
||
示例:
|
||
./start.sh local up
|
||
./start.sh local logs
|
||
./start.sh local quote 600519
|
||
./start.sh local quote 贵州茅台
|
||
./start.sh local web
|
||
./start.sh prod up
|
||
./start.sh prod restart
|
||
|
||
可选环境变量:
|
||
COMPOSE_FILE 指定 compose 文件(默认 docker-compose.yml)
|
||
ENV_FILE 指定环境变量文件(默认 .env)
|
||
PROJECT_NAME compose 项目名(默认 ai-trading)
|
||
EOF
|
||
}
|
||
|
||
run_local() {
|
||
case "$ACTION" in
|
||
up)
|
||
"${compose_cmd[@]}" up --build -d redis go-service
|
||
;;
|
||
down)
|
||
"${compose_cmd[@]}" down
|
||
;;
|
||
restart)
|
||
"${compose_cmd[@]}" down
|
||
"${compose_cmd[@]}" up --build -d
|
||
;;
|
||
quick)
|
||
"${compose_cmd[@]}" down --remove-orphans || true
|
||
docker compose -p aitrading -f "$COMPOSE_FILE" down --remove-orphans 2>/dev/null || true
|
||
stale_run_ids="$(docker ps -aq --filter "name=^ai-trading-python-app-run-")"
|
||
if [[ -n "$stale_run_ids" ]]; then
|
||
docker rm -f $stale_run_ids >/dev/null 2>&1 || true
|
||
fi
|
||
docker rm -f ai-trading-redis >/dev/null 2>&1 || true
|
||
"${compose_cmd[@]}" up --build -d redis go-service web
|
||
echo "[INFO] Quick 启动完成: http://localhost:8000"
|
||
;;
|
||
logs)
|
||
"${compose_cmd[@]}" logs -f --tail=200
|
||
;;
|
||
status)
|
||
"${compose_cmd[@]}" ps
|
||
;;
|
||
pull)
|
||
"${compose_cmd[@]}" pull || true
|
||
;;
|
||
build)
|
||
"${compose_cmd[@]}" build
|
||
;;
|
||
quote)
|
||
if [[ -z "$QUERY" ]]; then
|
||
"${compose_cmd[@]}" run --rm --no-deps python-app python app/stock_lookup.py
|
||
else
|
||
"${compose_cmd[@]}" run --rm --no-deps python-app python app/stock_lookup.py "$QUERY"
|
||
fi
|
||
;;
|
||
web)
|
||
"${compose_cmd[@]}" up --build -d web
|
||
echo "[INFO] Web 已启动: http://localhost:8000"
|
||
;;
|
||
cleanup)
|
||
# 1) 优先清理当前 compose 项目里的孤儿资源
|
||
"${compose_cmd[@]}" down --remove-orphans || true
|
||
|
||
# 2) 清理历史旧项目名(未显式 -p 时常见)
|
||
docker compose -p aitrading -f "$COMPOSE_FILE" down --remove-orphans 2>/dev/null || true
|
||
|
||
# 3) 清理遗留临时容器(例如 ai-trading-python-app-run-xxxxx)
|
||
stale_run_ids="$(docker ps -aq --filter "name=^ai-trading-python-app-run-")"
|
||
if [[ -n "$stale_run_ids" ]]; then
|
||
docker rm -f $stale_run_ids >/dev/null 2>&1 || true
|
||
fi
|
||
|
||
# 4) 清理曾经手动起的固定 redis 容器
|
||
docker rm -f ai-trading-redis >/dev/null 2>&1 || true
|
||
echo "[INFO] 清理完成,建议执行: ./start.sh local up && ./start.sh local web"
|
||
;;
|
||
*)
|
||
echo "[ERROR] 不支持的 action: $ACTION"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
run_prod() {
|
||
case "$ACTION" in
|
||
up)
|
||
"${compose_cmd[@]}" pull || true
|
||
"${compose_cmd[@]}" up -d --build --remove-orphans redis go-service
|
||
;;
|
||
down)
|
||
"${compose_cmd[@]}" down
|
||
;;
|
||
restart)
|
||
"${compose_cmd[@]}" up -d --build --force-recreate --remove-orphans
|
||
;;
|
||
quick)
|
||
"${compose_cmd[@]}" down --remove-orphans || true
|
||
docker compose -p aitrading -f "$COMPOSE_FILE" down --remove-orphans 2>/dev/null || true
|
||
stale_run_ids="$(docker ps -aq --filter "name=^ai-trading-python-app-run-")"
|
||
if [[ -n "$stale_run_ids" ]]; then
|
||
docker rm -f $stale_run_ids >/dev/null 2>&1 || true
|
||
fi
|
||
docker rm -f ai-trading-redis >/dev/null 2>&1 || true
|
||
"${compose_cmd[@]}" pull || true
|
||
"${compose_cmd[@]}" up -d --build --remove-orphans redis go-service web
|
||
echo "[INFO] Quick 启动完成: http://localhost:8000"
|
||
;;
|
||
logs)
|
||
"${compose_cmd[@]}" logs -f --tail=300
|
||
;;
|
||
status)
|
||
"${compose_cmd[@]}" ps
|
||
;;
|
||
pull)
|
||
"${compose_cmd[@]}" pull || true
|
||
;;
|
||
build)
|
||
"${compose_cmd[@]}" build --pull
|
||
;;
|
||
quote)
|
||
if [[ -z "$QUERY" ]]; then
|
||
"${compose_cmd[@]}" run --rm --no-deps python-app python app/stock_lookup.py
|
||
else
|
||
"${compose_cmd[@]}" run --rm --no-deps python-app python app/stock_lookup.py "$QUERY"
|
||
fi
|
||
;;
|
||
web)
|
||
"${compose_cmd[@]}" up -d --build --remove-orphans web
|
||
echo "[INFO] Web 已启动: http://localhost:8000"
|
||
;;
|
||
cleanup)
|
||
"${compose_cmd[@]}" down --remove-orphans || true
|
||
docker compose -p aitrading -f "$COMPOSE_FILE" down --remove-orphans 2>/dev/null || true
|
||
stale_run_ids="$(docker ps -aq --filter "name=^ai-trading-python-app-run-")"
|
||
if [[ -n "$stale_run_ids" ]]; then
|
||
docker rm -f $stale_run_ids >/dev/null 2>&1 || true
|
||
fi
|
||
docker rm -f ai-trading-redis >/dev/null 2>&1 || true
|
||
echo "[INFO] 清理完成,建议执行: ./start.sh prod up && ./start.sh prod web"
|
||
;;
|
||
*)
|
||
echo "[ERROR] 不支持的 action: $ACTION"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
if [[ "$MODE" == "-h" || "$MODE" == "--help" ]]; then
|
||
show_help
|
||
exit 0
|
||
fi
|
||
|
||
echo "[INFO] mode=$MODE action=$ACTION compose=$COMPOSE_FILE env=$ENV_FILE project=$PROJECT_NAME"
|
||
|
||
case "$MODE" in
|
||
local)
|
||
run_local
|
||
;;
|
||
prod)
|
||
run_prod
|
||
;;
|
||
*)
|
||
echo "[ERROR] 不支持的 mode: $MODE"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
echo "[INFO] 完成: mode=$MODE action=$ACTION"
|