219 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Bash
		
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Bash
		
	
	
	
| #!/bin/bash
 | ||
| 
 | ||
| # 函数:显示帮助信息
 | ||
| show_help() {
 | ||
|     echo "股票基础分析应用管理脚本"
 | ||
|     echo ""
 | ||
|     echo "用法: $0 [命令] [参数]"
 | ||
|     echo ""
 | ||
|     echo "命令:"
 | ||
|     echo "  list                 列出所有运行的实例"
 | ||
|     echo "  start [实例ID]        启动指定实例或所有实例"
 | ||
|     echo "  stop [实例ID]         停止指定实例或所有实例"
 | ||
|     echo "  restart [实例ID]      重启指定实例或所有实例"
 | ||
|     echo "  logs [实例ID]         实时查看指定实例的日志 (Ctrl+C 退出)"
 | ||
|     echo "  status               显示实例状态概览"
 | ||
|     echo "  remove [实例ID]       删除指定实例或所有实例"
 | ||
|     echo "  rebuild [数量]        重新构建镜像并部署指定数量的实例"
 | ||
|     echo "  update               热更新代码(不重建镜像,仅复制src目录)"
 | ||
|     echo ""
 | ||
|     echo "示例:"
 | ||
|     echo "  $0 list              列出所有实例"
 | ||
|     echo "  $0 start 2           启动实例2"
 | ||
|     echo "  $0 stop all          停止所有实例"
 | ||
|     echo "  $0 logs 1            查看实例1的日志"
 | ||
|     echo "  $0 rebuild 2         重新构建并部署2个实例"
 | ||
|     echo "  $0 update            热更新所有实例的代码"
 | ||
|     exit 1
 | ||
| }
 | ||
| 
 | ||
| # 函数:列出所有实例
 | ||
| list_instances() {
 | ||
|     echo "正在运行的实例:"
 | ||
|     docker ps --filter "name=stock-app-" --format "表格 {{.Names}}\t{{.Status}}\t{{.Ports}}"
 | ||
| }
 | ||
| 
 | ||
| # 函数:启动实例
 | ||
| start_instance() {
 | ||
|     if [ "$1" = "all" ]; then
 | ||
|         echo "启动所有实例..."
 | ||
|         docker start $(docker ps -a --filter "name=stock-app-" -q)
 | ||
|     else
 | ||
|         echo "启动实例 $1..."
 | ||
|         docker start stock-app-$1
 | ||
|     fi
 | ||
| }
 | ||
| 
 | ||
| # 函数:停止实例
 | ||
| stop_instance() {
 | ||
|     if [ "$1" = "all" ]; then
 | ||
|         echo "停止所有实例..."
 | ||
|         docker stop $(docker ps --filter "name=stock-app-" -q)
 | ||
|     else
 | ||
|         echo "停止实例 $1..."
 | ||
|         docker stop stock-app-$1
 | ||
|     fi
 | ||
| }
 | ||
| 
 | ||
| # 函数:重启实例
 | ||
| restart_instance() {
 | ||
|     if [ "$1" = "all" ]; then
 | ||
|         echo "重启所有实例..."
 | ||
|         docker restart $(docker ps --filter "name=stock-app-" -q)
 | ||
|     else
 | ||
|         echo "重启实例 $1..."
 | ||
|         docker restart stock-app-$1
 | ||
|     fi
 | ||
| }
 | ||
| 
 | ||
| # 函数:查看实例日志
 | ||
| view_logs() {
 | ||
|     echo "正在实时显示实例 $1 的日志 (按 Ctrl+C 退出):"
 | ||
|     echo "----------------------------------------"
 | ||
|     docker logs -f stock-app-$1
 | ||
| }
 | ||
| 
 | ||
| # 函数:显示状态概览
 | ||
| show_status() {
 | ||
|     echo "实例状态概览:"
 | ||
|     echo "-----------------"
 | ||
|     echo "实例总数: $(docker ps -a --filter "name=stock-app-" --format "{{.Names}}" | wc -l)"
 | ||
|     echo "运行中: $(docker ps --filter "name=stock-app-" --format "{{.Names}}" | wc -l)"
 | ||
|     echo "已停止: $(docker ps -a --filter "name=stock-app-" --filter "status=exited" --format "{{.Names}}" | wc -l)"
 | ||
|     echo "-----------------"
 | ||
|     docker ps -a --filter "name=stock-app-" --format "表格 {{.Names}}\t{{.Status}}\t{{.Ports}}"
 | ||
| }
 | ||
| 
 | ||
| # 函数:删除实例
 | ||
| remove_instance() {
 | ||
|     if [ "$1" = "all" ]; then
 | ||
|         echo "删除所有实例..."
 | ||
|         docker rm -f $(docker ps -a --filter "name=stock-app-" -q)
 | ||
|     else
 | ||
|         echo "删除实例 $1..."
 | ||
|         docker rm -f stock-app-$1
 | ||
|     fi
 | ||
| }
 | ||
| 
 | ||
| # 函数:重新构建并部署
 | ||
| rebuild_instances() {
 | ||
|     NUM_INSTANCES=$1
 | ||
|     
 | ||
|     echo "开始全面重建流程..."
 | ||
|     
 | ||
|     # 1. 停止所有实例
 | ||
|     echo "停止所有实例..."
 | ||
|     docker stop $(docker ps --filter "name=stock-app-" -q) 2>/dev/null
 | ||
|     
 | ||
|     # 2. 删除所有实例
 | ||
|     echo "删除所有实例..."
 | ||
|     docker rm -f $(docker ps -a --filter "name=stock-app-" -q) 2>/dev/null
 | ||
|     
 | ||
|     # 3. 重新构建镜像
 | ||
|     echo "重新构建镜像..."
 | ||
|     docker-compose build
 | ||
|     
 | ||
|     # 4. 部署新实例
 | ||
|     echo "部署 $NUM_INSTANCES 个新实例..."
 | ||
|     ./deploy-multiple.sh $NUM_INSTANCES
 | ||
|     
 | ||
|     echo "重建完成!"
 | ||
| }
 | ||
| 
 | ||
| # 函数:热更新代码
 | ||
| update_code() {
 | ||
|     # 获取所有正在运行的实例
 | ||
|     RUNNING_INSTANCES=$(docker ps --filter "name=stock-app-" -q)
 | ||
|     
 | ||
|     if [ -z "$RUNNING_INSTANCES" ]; then
 | ||
|         echo "没有发现正在运行的实例!"
 | ||
|         return 1
 | ||
|     fi
 | ||
|     
 | ||
|     echo "发现 $(echo "$RUNNING_INSTANCES" | wc -l) 个实例需要更新..."
 | ||
|     
 | ||
|     # 更新每个实例的代码
 | ||
|     for CONTAINER_ID in $RUNNING_INSTANCES; do
 | ||
|         CONTAINER_NAME=$(docker inspect --format='{{.Name}}' $CONTAINER_ID | sed 's/\///')
 | ||
|         echo "更新 $CONTAINER_NAME 的代码..."
 | ||
|         
 | ||
|         # 复制 src 目录到容器
 | ||
|         docker cp ./src/. $CONTAINER_ID:/app/src/
 | ||
|         
 | ||
|         # 重启 Flask 应用(如果使用的是gunicorn等进程管理器,需要向进程发送信号)
 | ||
|         echo "重启 $CONTAINER_NAME 中的应用..."
 | ||
|         docker exec $CONTAINER_ID sh -c "pkill -f 'python src/app.py' && nohup python src/app.py > /app/logs/app.log 2>&1 &"
 | ||
|     done
 | ||
|     
 | ||
|     echo "所有实例代码已更新,并尝试重启应用!"
 | ||
|     echo "注意:如果应用启动方式不是 'python src/app.py',可能需要手动重启容器:"
 | ||
|     echo "./manage-instances.sh restart all"
 | ||
| }
 | ||
| 
 | ||
| # 主逻辑
 | ||
| if [ "$#" -lt 1 ]; then
 | ||
|     show_help
 | ||
| fi
 | ||
| 
 | ||
| case "$1" in
 | ||
|     list)
 | ||
|         list_instances
 | ||
|         ;;
 | ||
|     start)
 | ||
|         if [ "$#" -lt 2 ]; then
 | ||
|             echo "错误: 缺少实例ID参数"
 | ||
|             show_help
 | ||
|         fi
 | ||
|         start_instance $2
 | ||
|         ;;
 | ||
|     stop)
 | ||
|         if [ "$#" -lt 2 ]; then
 | ||
|             echo "错误: 缺少实例ID参数"
 | ||
|             show_help
 | ||
|         fi
 | ||
|         stop_instance $2
 | ||
|         ;;
 | ||
|     restart)
 | ||
|         if [ "$#" -lt 2 ]; then
 | ||
|             echo "错误: 缺少实例ID参数"
 | ||
|             show_help
 | ||
|         fi
 | ||
|         restart_instance $2
 | ||
|         ;;
 | ||
|     logs)
 | ||
|         if [ "$#" -lt 2 ]; then
 | ||
|             echo "错误: 缺少实例ID参数"
 | ||
|             show_help
 | ||
|         fi
 | ||
|         view_logs $2
 | ||
|         ;;
 | ||
|     status)
 | ||
|         show_status
 | ||
|         ;;
 | ||
|     remove)
 | ||
|         if [ "$#" -lt 2 ]; then
 | ||
|             echo "错误: 缺少实例ID参数"
 | ||
|             show_help
 | ||
|         fi
 | ||
|         remove_instance $2
 | ||
|         ;;
 | ||
|     rebuild)
 | ||
|         if [ "$#" -lt 2 ]; then
 | ||
|             echo "错误: 缺少实例数量参数"
 | ||
|             show_help
 | ||
|         fi
 | ||
|         rebuild_instances $2
 | ||
|         ;;
 | ||
|     update)
 | ||
|         update_code
 | ||
|         ;;
 | ||
|     help|--help|-h)
 | ||
|         show_help
 | ||
|         ;;
 | ||
|     *)
 | ||
|         echo "错误: 未知命令 '$1'"
 | ||
|         show_help
 | ||
|         ;;
 | ||
| esac
 | ||
| 
 | ||
| exit 0  |