jshells/install_jsite.sh
2025-08-07 21:42:25 +08:00

519 lines
14 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# jsite前端自动化部署脚本
# 基于next.js + traefik开发
#
# 后端调用示例:
# 1. 基本部署: ./install_jsite.sh
# 2. 指定项目: ./install_jsite.sh -p myproject -r http://git.example.com/myproject
# 3. 跳过Docker: ./install_jsite.sh --skip-docker
# 4. 跳过Traefik: ./install_jsite.sh --skip-traefik
# 5. 强制更新: ./install_jsite.sh --force-update
# 6. 完整参数: ./install_jsite.sh -p myproject -r http://git.example.com/myproject -n 18 --skip-docker --force-update
#
# 返回码:
# 0 - 成功
# 1 - 参数错误
# 2 - 权限错误
# 3 - 其他错误
set -e # 遇到错误时退出
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 默认参数
PROJECT_NAME="jingrow"
GIT_REPO="http://git.jingrow.com:3000/jsite/jingrow"
NODE_VERSION="22"
SKIP_DOCKER=false
SKIP_TRAEFIK=false
SKIP_DEPENDENCIES=false
FORCE_UPDATE=false
# .env文件参数
SITE_URL="http://192.168.2.200:3001"
REVALIDATE_TOKEN="535bc122f3e364c"
SITE_NAME="jingrow"
SERVER_URL="https://admin.jingrow.com"
API_KEY="535bc122f3e364c"
API_SECRET="8629a3b12fc1cc2"
# 显示帮助信息
show_help() {
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " -p, --project-name NAME 项目名称 (默认: jingrow)"
echo " -r, --repo URL Git仓库地址"
echo " -n, --node-version VERSION Node.js版本 (默认: 22)"
echo " --skip-docker 跳过Docker安装"
echo " --skip-traefik 跳过Traefik安装和启动"
echo " --skip-dependencies 跳过项目依赖安装"
echo " --force-update 强制更新项目(如果已存在)"
echo ""
echo ".env文件配置:"
echo " --site-url URL 网站URL (默认: http://192.168.2.200:3001)"
echo " --revalidate-token TOKEN 重新验证令牌 (默认: 535bc122f3e364c)"
echo " --site-name NAME 站点名称 (默认: jingrow)"
echo " --server-url URL 服务器URL (默认: https://admin.jingrow.com)"
echo " --api-key KEY API密钥 (默认: 535bc122f3e364c)"
echo " --api-secret SECRET API密钥 (默认: 8629a3b12fc1cc2)"
echo ""
echo " -h, --help 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 -p myproject -r http://git.example.com/myproject"
echo " $0 --skip-docker --skip-traefik"
echo " $0 --force-update"
echo " $0 --site-url http://example.com --site-name myproject"
}
# 解析命令行参数
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
-p|--project-name)
PROJECT_NAME="$2"
shift 2
;;
-r|--repo)
GIT_REPO="$2"
shift 2
;;
-n|--node-version)
NODE_VERSION="$2"
shift 2
;;
--skip-docker)
SKIP_DOCKER=true
shift
;;
--skip-traefik)
SKIP_TRAEFIK=true
shift
;;
--skip-dependencies)
SKIP_DEPENDENCIES=true
shift
;;
--force-update)
FORCE_UPDATE=true
shift
;;
--site-url)
SITE_URL="$2"
shift 2
;;
--revalidate-token)
REVALIDATE_TOKEN="$2"
shift 2
;;
--site-name)
SITE_NAME="$2"
shift 2
;;
--server-url)
SERVER_URL="$2"
shift 2
;;
--api-key)
API_KEY="$2"
shift 2
;;
--api-secret)
API_SECRET="$2"
shift 2
;;
-h|--help)
show_help
exit 0
;;
*)
echo -e "${RED}[ERROR]${NC} 未知参数: $1"
show_help
exit 1
;;
esac
done
}
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查是否为root用户
check_root() {
if [[ $EUID -eq 0 ]]; then
log_info "以root用户身份运行脚本"
else
log_error "请以root用户身份运行此脚本"
exit 1
fi
}
# 1. 创建jingrow用户
create_jingrow_user() {
log_info "开始创建jingrow用户..."
if id "jingrow" &>/dev/null; then
log_warning "用户jingrow已存在"
else
useradd -m -s /bin/bash jingrow
log_success "用户jingrow创建成功"
fi
# 确保home目录存在
if [ ! -d "/home/jingrow" ]; then
mkdir -p /home/jingrow
chown jingrow:jingrow /home/jingrow
log_success "创建/home/jingrow目录"
fi
}
# 2. 安装nvm和node.js
install_nodejs() {
log_info "开始安装nvm和node.js..."
# 切换到jingrow用户目录
cd /home/jingrow
# 下载并安装nvm
if [ ! -d "/home/jingrow/.nvm" ]; then
log_info "下载并安装nvm..."
su - jingrow -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash"
log_success "nvm安装完成"
else
log_warning "nvm已存在"
fi
# 加载nvm并安装node.js
log_info "安装Node.js v$NODE_VERSION..."
su - jingrow -c "
export NVM_DIR=\"\$HOME/.nvm\"
[ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\"
nvm install $NODE_VERSION
nvm use $NODE_VERSION
nvm alias default $NODE_VERSION
"
# 验证安装
NODE_VERSION_OUTPUT=$(su - jingrow -c 'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && node -v')
NPM_VERSION=$(su - jingrow -c 'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && npm -v')
log_success "Node.js版本: $NODE_VERSION_OUTPUT"
log_success "npm版本: $NPM_VERSION"
}
# 3. 克隆jsite项目
clone_jsite_project() {
log_info "开始克隆jsite项目: $PROJECT_NAME..."
cd /home/jingrow
# 创建jsite目录如果不存在
if [ ! -d "/home/jingrow/jsite" ]; then
mkdir -p /home/jingrow/jsite
chown jingrow:jingrow /home/jingrow/jsite
log_success "创建jsite目录"
fi
# 检查项目子目录是否已存在
if [ -d "/home/jingrow/jsite/$PROJECT_NAME" ]; then
if [ "$FORCE_UPDATE" = true ]; then
log_warning "项目目录已存在,强制更新..."
rm -rf "/home/jingrow/jsite/$PROJECT_NAME"
cd /home/jingrow/jsite
su - jingrow -c "cd /home/jingrow/jsite && git clone $GIT_REPO $PROJECT_NAME"
log_success "jsite/$PROJECT_NAME项目更新完成"
else
log_warning "jsite/$PROJECT_NAME目录已存在,跳过克隆"
fi
else
cd /home/jingrow/jsite
su - jingrow -c "cd /home/jingrow/jsite && git clone $GIT_REPO $PROJECT_NAME"
log_success "jsite/$PROJECT_NAME项目克隆完成"
fi
}
# 4. 创建.env文件
create_env_file() {
log_info "创建.env文件..."
cd /home/jingrow/jsite/$PROJECT_NAME
# 检查.env文件是否已存在
if [ -f "/home/jingrow/jsite/$PROJECT_NAME/.env" ]; then
if [ "$FORCE_UPDATE" = true ]; then
log_warning ".env文件已存在强制更新..."
else
log_warning ".env文件已存在跳过创建"
return
fi
fi
# 创建.env文件
cat > "/home/jingrow/jsite/$PROJECT_NAME/.env" << EOF
PUBLIC_SITE_URL=$SITE_URL
REVALIDATE_TOKEN=$REVALIDATE_TOKEN
JINGROW_SITE_NAME=$SITE_NAME
JINGROW_SERVER_URL=$SERVER_URL
JINGROW_API_KEY=$API_KEY
JINGROW_API_SECRET=$API_SECRET
EOF
# 设置文件权限
chown jingrow:jingrow "/home/jingrow/jsite/$PROJECT_NAME/.env"
chmod 600 "/home/jingrow/jsite/$PROJECT_NAME/.env"
log_success ".env文件创建完成"
}
# 5. 安装traefik
install_traefik() {
log_info "开始安装traefik..."
cd /home/jingrow
# 创建traefik目录结构
if [ ! -d "/home/jingrow/traefik" ]; then
mkdir -p /home/jingrow/traefik/conf.d
log_success "创建traefik目录结构"
fi
# 创建acme.json文件
if [ ! -f "/home/jingrow/traefik/acme.json" ]; then
touch /home/jingrow/traefik/acme.json
chmod 600 /home/jingrow/traefik/acme.json
log_success "创建acme.json文件"
fi
# 创建traefik.yml配置文件
cat > /home/jingrow/traefik/traefik.yml << 'EOF'
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
api:
dashboard: true
insecure: true # 生产环境建议关闭
providers:
docker:
exposedByDefault: false
file:
directory: /etc/traefik/conf.d
watch: true
certificatesResolvers:
myresolver:
acme:
email: support@jingrow.com
storage: acme.json
httpChallenge:
entryPoint: web
EOF
log_success "创建traefik.yml配置文件"
# 创建docker-compose.yml文件
cat > /home/jingrow/traefik/docker-compose.yml << 'EOF'
services:
traefik:
# The official v3 Traefik docker image
image: traefik:v3.4
container_name: traefik
restart: always
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:
# The HTTP port
- "80:80"
- "443:443"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./conf.d:/etc/traefik/conf.d:ro
- ./acme.json:/etc/traefik/acme.json
EOF
log_success "创建docker-compose.yml文件"
# 设置目录权限
chown -R jingrow:jingrow /home/jingrow/traefik
log_success "设置traefik目录权限"
}
# 6. 安装Docker如果未安装
install_docker() {
log_info "检查Docker安装状态..."
if command -v docker &> /dev/null; then
log_warning "Docker已安装"
else
log_info "开始安装Docker..."
# 更新包索引
apt-get update
# 安装必要的包
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 设置稳定版仓库
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# 更新包索引
apt-get update
# 安装Docker Engine
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 启动Docker服务
systemctl start docker
systemctl enable docker
log_success "Docker安装完成"
fi
# 将jingrow用户添加到docker组
usermod -aG docker jingrow
log_success "将jingrow用户添加到docker组"
}
# 7. 启动traefik
start_traefik() {
log_info "启动traefik服务..."
cd /home/jingrow/traefik
# 使用jingrow用户启动traefik
su - jingrow -c "cd /home/jingrow/traefik && docker compose up -d"
log_success "traefik服务启动完成"
}
# 8. 安装项目依赖
install_project_dependencies() {
log_info "安装jsite/$PROJECT_NAME项目依赖..."
cd /home/jingrow/jsite/$PROJECT_NAME
su - jingrow -c "
export NVM_DIR=\"\$HOME/.nvm\"
[ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\"
cd /home/jingrow/jsite/$PROJECT_NAME
npm install
"
log_success "项目依赖安装完成"
}
# 9. 显示部署信息
show_deployment_info() {
log_success "=== 部署完成 ==="
echo ""
log_info "部署信息:"
echo " - 用户: jingrow"
echo " - jsite目录: /home/jingrow/jsite"
echo " - 项目目录: /home/jingrow/jsite/$PROJECT_NAME"
echo " - Traefik目录: /home/jingrow/traefik"
echo " - Traefik管理界面: http://localhost:8080"
echo ""
log_info ".env文件配置"
echo " - PUBLIC_SITE_URL: $SITE_URL"
echo " - JINGROW_SITE_NAME: $SITE_NAME"
echo " - JINGROW_SERVER_URL: $SERVER_URL"
echo " - REVALIDATE_TOKEN: $REVALIDATE_TOKEN"
echo " - JINGROW_API_KEY: $API_KEY"
echo " - JINGROW_API_SECRET: $API_SECRET"
echo ""
log_info "下一步操作:"
echo " 1. 进入项目目录: cd /home/jingrow/jsite/$PROJECT_NAME"
echo " 2. 启动开发服务器: npm run dev"
echo " 3. 访问Traefik管理界面: http://localhost:8080"
echo ""
log_warning "注意请确保防火墙允许80、443、8080端口访问"
}
# 主函数
main() {
log_info "开始jsite前端自动化部署..."
echo ""
log_info "部署参数:"
echo " - 项目名称: $PROJECT_NAME"
echo " - Git仓库: $GIT_REPO"
echo " - Node.js版本: $NODE_VERSION"
echo " - 跳过Docker: $SKIP_DOCKER"
echo " - 跳过Traefik: $SKIP_TRAEFIK"
echo " - 跳过依赖安装: $SKIP_DEPENDENCIES"
echo " - 强制更新: $FORCE_UPDATE"
echo ""
log_info ".env文件参数:"
echo " - 网站URL: $SITE_URL"
echo " - 站点名称: $SITE_NAME"
echo " - 服务器URL: $SERVER_URL"
echo " - 重新验证令牌: $REVALIDATE_TOKEN"
echo " - API密钥: $API_KEY"
echo " - API密钥: $API_SECRET"
echo ""
check_root
create_jingrow_user
if [ "$SKIP_DOCKER" = false ]; then
install_docker
else
log_warning "跳过Docker安装"
fi
install_nodejs
clone_jsite_project
create_env_file
if [ "$SKIP_TRAEFIK" = false ]; then
install_traefik
start_traefik
else
log_warning "跳过Traefik安装和启动"
fi
if [ "$SKIP_DEPENDENCIES" = false ]; then
install_project_dependencies
else
log_warning "跳过项目依赖安装"
fi
show_deployment_info
log_success "部署脚本执行完成!"
}
# 执行主函数
parse_arguments "$@"
main "$@"