Simplify homepage, show chapter counts, display directory, trim bottom nav, in-page match feature, move marketing content, and enhance "My" page. #VERCEL_SKIP Co-authored-by: undefined <undefined+undefined@users.noreply.github.com>
326 lines
9.5 KiB
Bash
326 lines
9.5 KiB
Bash
#!/bin/bash
|
||
# ============================================
|
||
# Soul创业实验项目 - NAS部署脚本
|
||
# 用途: 自动部署Next.js应用到NAS-2
|
||
# ============================================
|
||
|
||
set -e
|
||
|
||
# 配置
|
||
NAS_USER="fnvtk"
|
||
NAS_IP="192.168.2.201"
|
||
NAS_PASSWORD="Zhiqun1984"
|
||
SUDO_PASSWORD="Zhiqun1984"
|
||
DOCKER_CMD="/volume1/@appstore/ContainerManager/usr/bin/docker"
|
||
DOCKER_COMPOSE_CMD="/volume1/@appstore/ContainerManager/usr/bin/docker-compose"
|
||
PROJECT_NAME="soul-book"
|
||
PROJECT_DIR="/volume1/docker/${PROJECT_NAME}"
|
||
LOCAL_PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
LOG_FILE="/tmp/soul_deploy_$(date +%Y%m%d_%H%M%S).log"
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m'
|
||
|
||
echo "==========================================" | tee -a $LOG_FILE
|
||
echo "Soul创业实验项目 - NAS部署脚本" | tee -a $LOG_FILE
|
||
echo "开始时间: $(date)" | tee -a $LOG_FILE
|
||
echo "==========================================" | tee -a $LOG_FILE
|
||
echo ""
|
||
|
||
print_step() {
|
||
echo -e "${GREEN}[步骤 $1]${NC} $2" | tee -a $LOG_FILE
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}[错误]${NC} $1" | tee -a $LOG_FILE
|
||
}
|
||
|
||
print_warn() {
|
||
echo -e "${YELLOW}[警告]${NC} $1" | tee -a $LOG_FILE
|
||
}
|
||
|
||
# 检查 expect
|
||
if ! command -v expect &> /dev/null; then
|
||
print_error "expect 未安装,请先安装: brew install expect"
|
||
exit 1
|
||
fi
|
||
|
||
# ============================================
|
||
# 步骤 1: 检查网络连通性
|
||
# ============================================
|
||
print_step "1" "检查网络连通性..."
|
||
|
||
if ping -c 1 $NAS_IP > /dev/null 2>&1; then
|
||
echo "✅ NAS-2 在线" | tee -a $LOG_FILE
|
||
else
|
||
print_error "无法连接到 NAS-2 ($NAS_IP)"
|
||
exit 1
|
||
fi
|
||
|
||
# ============================================
|
||
# 步骤 2: 创建项目目录
|
||
# ============================================
|
||
print_step "2" "创建项目目录..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 30
|
||
spawn ssh -t -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "sudo mkdir -p ${PROJECT_DIR} && sudo chown -R ${NAS_USER}:users ${PROJECT_DIR} && echo '目录创建完成'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"Password:" {
|
||
send "$SUDO_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"目录创建完成" {
|
||
puts "✅ 目录创建成功"
|
||
}
|
||
timeout {
|
||
puts "❌ 超时"
|
||
exit 1
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# ============================================
|
||
# 步骤 3: 检查nas-network是否存在
|
||
# ============================================
|
||
print_step "3" "检查Docker网络..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 30
|
||
spawn ssh -t -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "sudo $DOCKER_CMD network inspect nas-network > /dev/null 2>&1 || sudo $DOCKER_CMD network create nas-network && echo '网络检查完成'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"Password:" {
|
||
send "$SUDO_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"网络检查完成" {
|
||
puts "✅ 网络检查成功"
|
||
}
|
||
timeout {
|
||
puts "⚠️ 超时,但继续执行"
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# ============================================
|
||
# 步骤 4: 传输项目文件(排除node_modules和.git)
|
||
# ============================================
|
||
print_step "4" "传输项目文件到NAS(这可能需要几分钟)..."
|
||
|
||
# 创建临时排除文件
|
||
EXCLUDE_FILE=$(mktemp)
|
||
cat > $EXCLUDE_FILE << 'EXCLUDES'
|
||
node_modules/
|
||
.git/
|
||
.next/
|
||
.DS_Store
|
||
*.log
|
||
.env.local
|
||
.env*.local
|
||
EXCLUDES
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 600
|
||
spawn rsync -avz --progress --exclude-from=$EXCLUDE_FILE -e "ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc" "$LOCAL_PROJECT_DIR/" $NAS_USER@$NAS_IP:${PROJECT_DIR}/
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
timeout {
|
||
puts "⚠️ 传输可能超时,但继续执行"
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
rm -f $EXCLUDE_FILE
|
||
|
||
# ============================================
|
||
# 步骤 5: 在NAS上安装依赖和构建
|
||
# ============================================
|
||
print_step "5" "在NAS上安装依赖(使用pnpm)..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 300
|
||
spawn ssh -t -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "cd ${PROJECT_DIR} && if ! command -v pnpm &> /dev/null; then npm install -g pnpm; fi && pnpm install --frozen-lockfile && echo '依赖安装完成'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"Password:" {
|
||
send "$SUDO_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"依赖安装完成" {
|
||
puts "✅ 依赖安装成功"
|
||
}
|
||
timeout {
|
||
puts "⚠️ 安装可能超时,但继续执行"
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# ============================================
|
||
# 步骤 6: 停止并删除旧容器(如果存在)
|
||
# ============================================
|
||
print_step "6" "停止并删除旧容器(如果存在)..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 60
|
||
spawn ssh -t -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "cd ${PROJECT_DIR} && sudo $DOCKER_COMPOSE_CMD down 2>/dev/null || true && sudo $DOCKER_CMD rm -f ${PROJECT_NAME} 2>/dev/null || true && echo '旧容器清理完成'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"Password:" {
|
||
send "$SUDO_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"旧容器清理完成" {
|
||
puts "✅ 旧容器清理成功"
|
||
}
|
||
timeout {
|
||
puts "⚠️ 清理可能超时,但继续执行"
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# ============================================
|
||
# 步骤 7: 构建Docker镜像
|
||
# ============================================
|
||
print_step "7" "构建Docker镜像(这可能需要5-10分钟)..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 1200
|
||
spawn ssh -t -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "cd ${PROJECT_DIR} && sudo $DOCKER_COMPOSE_CMD build --no-cache && echo '镜像构建完成'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"Password:" {
|
||
send "$SUDO_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"镜像构建完成" {
|
||
puts "✅ 镜像构建成功"
|
||
}
|
||
timeout {
|
||
puts "⚠️ 构建可能超时,但继续执行"
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# ============================================
|
||
# 步骤 8: 启动容器
|
||
# ============================================
|
||
print_step "8" "启动容器..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 120
|
||
spawn ssh -t -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "cd ${PROJECT_DIR} && sudo $DOCKER_COMPOSE_CMD up -d && echo '容器启动完成'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"Password:" {
|
||
send "$SUDO_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"容器启动完成" {
|
||
puts "✅ 容器启动成功"
|
||
}
|
||
timeout {
|
||
puts "⚠️ 启动可能超时"
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# 等待服务启动
|
||
echo "等待服务启动(30秒)..." | tee -a $LOG_FILE
|
||
sleep 30
|
||
|
||
# ============================================
|
||
# 步骤 9: 检查容器状态
|
||
# ============================================
|
||
print_step "9" "检查容器状态..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 30
|
||
spawn ssh -t -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "sudo $DOCKER_CMD ps --filter name=${PROJECT_NAME} --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"Password:" {
|
||
send "$SUDO_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# ============================================
|
||
# 步骤 10: 检查服务健康状态
|
||
# ============================================
|
||
print_step "10" "检查服务健康状态..."
|
||
|
||
expect << EOF | tee -a $LOG_FILE
|
||
set timeout 30
|
||
spawn ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 -o Ciphers=+aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc $NAS_USER@$NAS_IP "curl -s -o /dev/null -w '%{http_code}' http://localhost:3000 || echo '服务未响应'"
|
||
expect {
|
||
"password:" {
|
||
send "$NAS_PASSWORD\r"
|
||
exp_continue
|
||
}
|
||
"200" {
|
||
puts "✅ 服务运行正常"
|
||
}
|
||
"服务未响应" {
|
||
puts "⚠️ 服务可能还在启动中"
|
||
}
|
||
}
|
||
expect eof
|
||
EOF
|
||
|
||
# ============================================
|
||
# 完成
|
||
# ============================================
|
||
echo "" | tee -a $LOG_FILE
|
||
echo "==========================================" | tee -a $LOG_FILE
|
||
echo "✅ 部署脚本执行完成!" | tee -a $LOG_FILE
|
||
echo "完成时间: $(date)" | tee -a $LOG_FILE
|
||
echo "日志文件: $LOG_FILE" | tee -a $LOG_FILE
|
||
echo "==========================================" | tee -a $LOG_FILE
|
||
echo ""
|
||
echo "访问地址:"
|
||
echo " http://${NAS_IP}:3000"
|
||
echo ""
|
||
echo "下一步操作:"
|
||
echo "1. 查看容器日志: ssh $NAS_USER@$NAS_IP 'sudo $DOCKER_CMD logs -f ${PROJECT_NAME}'"
|
||
echo "2. 查看容器状态: ssh $NAS_USER@$NAS_IP 'sudo $DOCKER_CMD ps --filter name=${PROJECT_NAME}'"
|
||
echo "3. 重启容器: ssh $NAS_USER@$NAS_IP 'cd ${PROJECT_DIR} && sudo $DOCKER_COMPOSE_CMD restart'"
|
||
echo "4. 停止容器: ssh $NAS_USER@$NAS_IP 'cd ${PROJECT_DIR} && sudo $DOCKER_COMPOSE_CMD down'"
|