Files
soul/deploy_to_nas.sh

326 lines
9.5 KiB
Bash
Raw Normal View History

#!/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'"