| 
									
										
										
										
											2025-05-14 08:54:56 +08:00
										 |  |  |  | #!/bin/bash
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | # 函数:显示帮助信息 | 
					
						
							|  |  |  |  | show_help() { | 
					
						
							|  |  |  |  |     echo "股票基础分析应用管理脚本" | 
					
						
							|  |  |  |  |     echo "" | 
					
						
							|  |  |  |  |     echo "用法: $0 [命令] [参数]" | 
					
						
							|  |  |  |  |     echo "" | 
					
						
							|  |  |  |  |     echo "命令:" | 
					
						
							|  |  |  |  |     echo "  list                 列出所有运行的实例" | 
					
						
							|  |  |  |  |     echo "  start [实例ID]        启动指定实例或所有实例" | 
					
						
							|  |  |  |  |     echo "  stop [实例ID]         停止指定实例或所有实例" | 
					
						
							|  |  |  |  |     echo "  restart [实例ID]      重启指定实例或所有实例" | 
					
						
							| 
									
										
										
										
											2025-10-11 14:05:18 +08:00
										 |  |  |  |     echo "  logs [实例ID]         查看最新10条日志并实时跟踪新日志" | 
					
						
							|  |  |  |  |     echo "  logs-follow [实例ID]  实时查看指定实例的日志 (Ctrl+C 退出)" | 
					
						
							| 
									
										
										
										
											2025-05-14 08:54:56 +08:00
										 |  |  |  |     echo "  status               显示实例状态概览" | 
					
						
							|  |  |  |  |     echo "  remove [实例ID]       删除指定实例或所有实例" | 
					
						
							|  |  |  |  |     echo "  rebuild [数量]        重新构建镜像并部署指定数量的实例" | 
					
						
							|  |  |  |  |     echo "  update               热更新代码(不重建镜像,仅复制src目录)" | 
					
						
							|  |  |  |  |     echo "" | 
					
						
							|  |  |  |  |     echo "示例:" | 
					
						
							|  |  |  |  |     echo "  $0 list              列出所有实例" | 
					
						
							|  |  |  |  |     echo "  $0 start 2           启动实例2" | 
					
						
							|  |  |  |  |     echo "  $0 stop all          停止所有实例" | 
					
						
							| 
									
										
										
										
											2025-10-11 14:05:18 +08:00
										 |  |  |  |     echo "  $0 logs 1            查看实例1最新10条日志并实时跟踪" | 
					
						
							|  |  |  |  |     echo "  $0 logs-follow 1     实时跟踪实例1的日志" | 
					
						
							| 
									
										
										
										
											2025-05-14 08:54:56 +08:00
										 |  |  |  |     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() { | 
					
						
							| 
									
										
										
										
											2025-10-11 14:05:18 +08:00
										 |  |  |  |     echo "显示实例 $1 的最新10条日志,然后实时跟踪新日志 (按 Ctrl+C 退出):" | 
					
						
							|  |  |  |  |     echo "----------------------------------------" | 
					
						
							|  |  |  |  |     docker logs --tail 10 -f stock-app-$1 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | # 函数:实时查看实例日志 | 
					
						
							|  |  |  |  | view_logs_follow() { | 
					
						
							| 
									
										
										
										
											2025-08-15 16:57:53 +08:00
										 |  |  |  |     echo "正在实时显示实例 $1 的日志 (按 Ctrl+C 退出):" | 
					
						
							|  |  |  |  |     echo "----------------------------------------" | 
					
						
							|  |  |  |  |     docker logs -f stock-app-$1 | 
					
						
							| 
									
										
										
										
											2025-05-14 08:54:56 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | # 函数:显示状态概览 | 
					
						
							|  |  |  |  | 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 | 
					
						
							|  |  |  |  |         ;; | 
					
						
							| 
									
										
										
										
											2025-10-11 14:05:18 +08:00
										 |  |  |  |     logs-follow) | 
					
						
							|  |  |  |  |         if [ "$#" -lt 2 ]; then | 
					
						
							|  |  |  |  |             echo "错误: 缺少实例ID参数" | 
					
						
							|  |  |  |  |             show_help | 
					
						
							|  |  |  |  |         fi | 
					
						
							|  |  |  |  |         view_logs_follow $2 | 
					
						
							|  |  |  |  |         ;; | 
					
						
							| 
									
										
										
										
											2025-05-14 08:54:56 +08:00
										 |  |  |  |     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  |