#!/bin/bash # STARK Todo List - Docker 快速更新脚本 # 用于快速停止、重新构建并启动 Docker 容器 set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color # 默认配置 USE_CACHE=true PULL_CODE=true SHOW_LOGS=false # 帮助信息 show_help() { echo -e "${CYAN}STARK Todo List - Docker 快速更新脚本${NC}" echo "" echo "用法: ./docker-update.sh [选项]" echo "" echo "选项:" echo " -f, --full 完全重建(不使用缓存,较慢但更彻底)" echo " -q, --quick 快速更新(跳过 git pull,使用缓存)" echo " -l, --logs 更新完成后显示日志" echo " -h, --help 显示帮助信息" echo "" echo "示例:" echo " ./docker-update.sh # 默认:拉取代码 + 使用缓存构建" echo " ./docker-update.sh -f # 完全重建(不使用缓存)" echo " ./docker-update.sh -q # 快速模式(跳过 git pull)" echo " ./docker-update.sh -q -l # 快速模式 + 显示日志" echo "" } # 解析命令行参数 while [[ $# -gt 0 ]]; do case $1 in -f|--full) USE_CACHE=false shift ;; -q|--quick) PULL_CODE=false shift ;; -l|--logs) SHOW_LOGS=true shift ;; -h|--help) show_help exit 0 ;; *) echo -e "${RED}未知选项: $1${NC}" show_help exit 1 ;; esac done echo "" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${CYAN} 🔄 STARK Todo List - Docker 更新${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" # 显示当前配置 echo -e "${BLUE}📋 更新配置:${NC}" if [ "$PULL_CODE" = true ]; then echo -e " • Git Pull: ${GREEN}是${NC}" else echo -e " • Git Pull: ${YELLOW}跳过${NC}" fi if [ "$USE_CACHE" = true ]; then echo -e " • 构建缓存: ${GREEN}启用${NC} (快速)" else echo -e " • 构建缓存: ${YELLOW}禁用${NC} (完全重建)" fi echo "" # 记录开始时间 START_TIME=$(date +%s) # 1. 拉取最新代码 if [ "$PULL_CODE" = true ] && [ -d ".git" ]; then echo -e "${BLUE}📥 正在获取远程最新代码...${NC}" CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) echo -e " 当前分支: ${CYAN}$CURRENT_BRANCH${NC}" if git pull origin "$CURRENT_BRANCH" 2>&1; then echo -e "${GREEN} ✓ 代码已更新${NC}" else echo -e "${RED} ✗ 代码拉取失败!${NC}" echo -e "${YELLOW} 💡 提示: 运行 'git reset --hard origin/$CURRENT_BRANCH' 强制覆盖本地更改${NC}" exit 1 fi echo "" fi # 2. 停止现有容器(保留数据卷) echo -e "${BLUE}📦 停止现有容器...${NC}" # 注意:不使用 -v 参数,以保留 todos-data 卷中的 todos.json 和 stats.json docker compose down --remove-orphans 2>/dev/null || true echo -e "${GREEN} ✓ 容器已停止 (数据卷已保留)${NC}" echo "" # 3. 构建镜像 echo -e "${BLUE}🏗️ 构建 Docker 镜像...${NC}" if [ "$USE_CACHE" = true ]; then # 使用缓存构建(快速) if docker compose build 2>&1 | while read line; do echo -e " $line"; done; then echo -e "${GREEN} ✓ 镜像构建成功${NC}" else echo -e "${RED} ✗ 镜像构建失败!${NC}" exit 1 fi else # 不使用缓存(完全重建) echo -e "${YELLOW} (完全重建模式,可能需要几分钟...)${NC}" docker compose down --rmi local 2>/dev/null || true if docker compose build --no-cache 2>&1 | while read line; do echo -e " $line"; done; then echo -e "${GREEN} ✓ 镜像构建成功${NC}" else echo -e "${RED} ✗ 镜像构建失败!${NC}" exit 1 fi fi echo "" # 4. 启动新容器 echo -e "${BLUE}🚀 启动新容器...${NC}" docker compose up -d --force-recreate echo -e "${GREEN} ✓ 容器已启动${NC}" echo "" # 5. 验证数据持久化 echo -e "${BLUE}📊 验证数据持久化...${NC}" sleep 2 # 等待容器完全启动 CONTAINER_ID=$(docker compose ps -q app 2>/dev/null) if [ -n "$CONTAINER_ID" ]; then # 检查 todos.json TODOS_COUNT=$(docker exec "$CONTAINER_ID" sh -c 'cat /app/data/todos.json 2>/dev/null | grep -o "\"id\"" | wc -l' 2>/dev/null || echo "0") # 检查 stats.json STATS=$(docker exec "$CONTAINER_ID" sh -c 'cat /app/data/stats.json 2>/dev/null' 2>/dev/null || echo '{"pv":0,"uv":0}') PV=$(echo "$STATS" | grep -o '"pv":[0-9]*' | grep -o '[0-9]*' || echo "0") UV=$(echo "$STATS" | grep -o '"uv":[0-9]*' | grep -o '[0-9]*' || echo "0") echo -e "${GREEN} ✓ 数据卷挂载正常${NC}" echo -e " • Todos 数量: ${CYAN}${TODOS_COUNT}${NC}" echo -e " • 访问量 (PV): ${CYAN}${PV}${NC}" echo -e " • 访客数 (UV): ${CYAN}${UV}${NC}" else echo -e "${YELLOW} ⚠ 无法获取容器信息,请手动验证数据${NC}" fi echo "" # 6. 清理悬空镜像(静默执行) docker image prune -f > /dev/null 2>&1 || true # 计算耗时 END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${GREEN} ✅ 更新完成!${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" echo -e " 📍 访问地址: ${CYAN}http://localhost:4000${NC}" echo -e " ⏱️ 总耗时: ${YELLOW}${DURATION}秒${NC}" echo -e " 💾 数据卷: ${CYAN}todos-data${NC} (todos.json + stats.json)" echo "" # 显示日志 if [ "$SHOW_LOGS" = true ]; then echo -e "${BLUE}📋 显示容器日志 (Ctrl+C 退出)...${NC}" echo "" docker compose logs -f --tail 50 fi