| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- #!/bin/bash
- # Cloudpods 一键启动脚本 V2
- # 分阶段启动,先启动keystone,再启动其他服务
- set -e
- # 颜色定义
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[1;33m'
- NC='\033[0m'
- # 检测操作系统
- OS_TYPE="$(uname -s)"
- case "$OS_TYPE" in
- Darwin*) OS="macos" ;;
- Linux*) OS="linux" ;;
- CYGWIN*|MINGW*|MSYS*)
- echo -e "${RED}检测到 Windows 系统${NC}"
- echo -e "${YELLOW}建议使用 WSL (Windows Subsystem for Linux) 运行此项目${NC}"
- echo ""
- echo "如果您在 WSL 中运行,请忽略此消息"
- echo "如果您在原生 Windows 中运行,请:"
- echo " 1. 安装 WSL: https://docs.microsoft.com/zh-cn/windows/wsl/install"
- echo " 2. 在 WSL 中重新运行此脚本"
- exit 1
- ;;
- *) echo -e "${RED}不支持的操作系统: $OS_TYPE${NC}"; exit 1 ;;
- esac
- # 脚本目录
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
- BACKEND_DIR="$(dirname "$SCRIPT_DIR")"
- PROJECT_ROOT="$(dirname "$BACKEND_DIR")"
- BIN_DIR="$BACKEND_DIR/_output/bin"
- LOG_DIR="$BACKEND_DIR/logs"
- PID_DIR="$BACKEND_DIR/logs"
- ENV_FILE="$PROJECT_ROOT/.env.local"
- echo -e "${GREEN}=== Cloudpods 服务启动脚本 V2 ===${NC}"
- echo ""
- # 加载环境变量
- if [ ! -f "$ENV_FILE" ]; then
- echo -e "${RED}错误: 找不到环境变量文件 $ENV_FILE${NC}"
- exit 1
- fi
- source "$ENV_FILE"
- # 检查必要的环境变量
- if [ -z "$DB_HOST" ] || [ -z "$DB_PORT" ] || [ -z "$DB_USER" ]; then
- echo -e "${RED}错误: 数据库配置不完整${NC}"
- exit 1
- fi
- # 构建数据库连接字符串
- if [ -z "$DB_PASSWORD" ]; then
- SQL_CONNECTION="mysql+pymysql://${DB_USER}@${DB_HOST}:${DB_PORT}/yunioncloud?charset=utf8"
- else
- SQL_CONNECTION="mysql+pymysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/yunioncloud?charset=utf8"
- fi
- # Keystone认证URL
- AUTH_URL="http://localhost:35357/v3"
- echo -e "${GREEN}配置信息:${NC}"
- echo " 数据库: $DB_HOST:$DB_PORT"
- echo " 认证URL: $AUTH_URL"
- echo " 系统: $OS"
- echo ""
- # 创建必要的目录
- mkdir -p "$LOG_DIR" "$PID_DIR"
- # 检查服务是否运行
- is_service_running() {
- local service_name=$1
- local pid_file="$PID_DIR/${service_name}.pid"
-
- if [ -f "$pid_file" ]; then
- local pid=$(cat "$pid_file")
- if ps -p "$pid" > /dev/null 2>&1; then
- return 0
- fi
- fi
- return 1
- }
- # 启动keystone服务
- start_keystone() {
- local service_name="keystone"
- local port=35357
- local bin_path="$BIN_DIR/$service_name"
- local log_file="$LOG_DIR/${service_name}.log"
- local pid_file="$PID_DIR/${service_name}.pid"
-
- if is_service_running "$service_name"; then
- echo -e "${YELLOW}Keystone 已在运行${NC}"
- return 0
- fi
-
- echo -e "${GREEN}启动 Keystone (认证服务)...${NC}"
-
- > "$log_file"
-
- nohup "$bin_path" \
- --sql-connection "$SQL_CONNECTION" \
- --port $port \
- --admin-port 35358 \
- --auto-sync-table \
- --bootstrap-admin-user-password sysadmin \
- --region region0 \
- --enable-default-policy \
- --no-policy-violation-check \
- > "$log_file" 2>&1 &
-
- local pid=$!
- echo $pid > "$pid_file"
-
- # 等待keystone启动
- local max_wait=20
- local waited=0
-
- while [ $waited -lt $max_wait ]; do
- sleep 1
- waited=$((waited + 1))
-
- if ! ps -p "$pid" > /dev/null 2>&1; then
- echo -e "${RED}✗ Keystone 启动失败${NC}"
- tail -10 "$log_file"
- return 1
- fi
-
- if grep -q "Start listen on" "$log_file" 2>/dev/null; then
- echo -e "${GREEN}✓ Keystone 启动成功 (PID: $pid)${NC}"
- return 0
- fi
-
- if grep -q "\[fatal\]" "$log_file" 2>/dev/null; then
- echo -e "${RED}✗ Keystone 启动失败${NC}"
- grep "\[fatal\]" "$log_file" | tail -1
- return 1
- fi
- done
-
- echo -e "${YELLOW}⚠ Keystone 启动超时${NC}"
- return 1
- }
- # 启动其他服务
- start_service() {
- local service_name=$1
- local port=$2
- local need_auth=${3:-true}
- local need_db=${4:-true}
-
- local bin_path="$BIN_DIR/$service_name"
- local log_file="$LOG_DIR/${service_name}.log"
- local pid_file="$PID_DIR/${service_name}.pid"
-
- if is_service_running "$service_name"; then
- echo -e "${YELLOW} $service_name 已在运行${NC}"
- return 0
- fi
-
- echo -e "${GREEN}启动 $service_name (端口: $port)...${NC}"
-
- > "$log_file"
-
- # 构建启动命令
- local cmd="$bin_path --port $port"
-
- if [ "$need_db" = "true" ]; then
- cmd="$cmd --sql-connection \"$SQL_CONNECTION\" --auto-sync-table"
- fi
-
- if [ "$need_auth" = "true" ]; then
- cmd="$cmd --auth-url $AUTH_URL --admin-user sysadmin --admin-password sysadmin --admin-project system"
- fi
-
- # glance特殊配置
- if [ "$service_name" = "glance" ]; then
- mkdir -p "$BACKEND_DIR/data/glance"
- cmd="$cmd --filesystem-store-datadir $BACKEND_DIR/data/glance"
- fi
-
- # region特殊配置 (需要etcd)
- if [ "$service_name" = "region" ]; then
- cmd="$cmd --etcd-endpoints http://localhost:2379"
- fi
-
- nohup bash -c "$cmd" > "$log_file" 2>&1 &
-
- local pid=$!
- echo $pid > "$pid_file"
-
- # 等待服务启动
- local max_wait=15
- local waited=0
-
- while [ $waited -lt $max_wait ]; do
- sleep 1
- waited=$((waited + 1))
-
- if ! ps -p "$pid" > /dev/null 2>&1; then
- echo -e "${RED} ✗ $service_name 启动失败${NC}"
- echo -e "${YELLOW} 错误信息:${NC}"
- tail -3 "$log_file" | sed 's/^/ /'
- return 1
- fi
-
- if grep -q "Start listen on" "$log_file" 2>/dev/null; then
- echo -e "${GREEN} ✓ $service_name 启动成功 (PID: $pid)${NC}"
- return 0
- fi
-
- if grep -q "\[fatal\]" "$log_file" 2>/dev/null; then
- echo -e "${RED} ✗ $service_name 启动失败${NC}"
- grep "\[fatal\]" "$log_file" | tail -1 | sed 's/^/ /'
- return 1
- fi
- done
-
- echo -e "${YELLOW} ⚠ $service_name 可能正在启动 (PID: $pid)${NC}"
- return 0
- }
- # 停止服务
- stop_service() {
- local service_name=$1
- local pid_file="$PID_DIR/${service_name}.pid"
-
- if [ -f "$pid_file" ]; then
- local pid=$(cat "$pid_file")
- if ps -p "$pid" > /dev/null 2>&1; then
- echo -e "${YELLOW}停止 $service_name (PID: $pid)...${NC}"
- kill "$pid" 2>/dev/null || true
- sleep 1
- if ps -p "$pid" > /dev/null 2>&1; then
- kill -9 "$pid" 2>/dev/null || true
- fi
- rm -f "$pid_file"
- else
- rm -f "$pid_file"
- fi
- fi
- }
- # 启动所有服务
- start_all() {
- echo -e "${GREEN}=== 启动所有服务 ===${NC}"
- echo ""
-
- # 第0阶段:启动etcd
- echo -e "${YELLOW}阶段 0: 启动etcd${NC}"
- if [ -f "$SCRIPT_DIR/start-etcd.sh" ]; then
- bash "$SCRIPT_DIR/start-etcd.sh" || {
- echo -e "${RED}etcd 启动失败${NC}"
- exit 1
- }
- else
- echo -e "${YELLOW}未找到 start-etcd.sh,跳过etcd启动${NC}"
- fi
- echo ""
-
- # 第一阶段:启动keystone
- echo -e "${YELLOW}阶段 1: 启动认证服务${NC}"
- if ! start_keystone; then
- echo -e "${RED}Keystone 启动失败,无法继续${NC}"
- exit 1
- fi
- echo ""
-
- # 等待keystone完全就绪
- echo -e "${YELLOW}等待 Keystone 完全就绪...${NC}"
- sleep 3
- echo ""
-
- # 初始化RBAC策略
- echo -e "${YELLOW}初始化RBAC策略...${NC}"
- if [ -f "$SCRIPT_DIR/init-admin-policy.sh" ]; then
- bash "$SCRIPT_DIR/init-admin-policy.sh" 2>&1 | grep -v "Warning" || true
- fi
- echo ""
-
- # 注册服务到service catalog
- echo -e "${YELLOW}注册服务到Service Catalog...${NC}"
- if [ -f "$SCRIPT_DIR/register-services.sh" ]; then
- bash "$SCRIPT_DIR/register-services.sh" 2>&1 | grep -v "Warning" | grep -E "✓|已注册" || true
- fi
- echo ""
-
- # 第二阶段:启动业务服务
- echo -e "${YELLOW}阶段 2: 启动业务服务${NC}"
-
- # region: 计算服务 (需要认证、数据库和etcd)
- start_service "region" 30888 true true
-
- # glance: 镜像服务 (需要认证和数据库)
- start_service "glance" 9292 true true
-
- # yunionconf: 配置服务 (需要认证和数据库)
- start_service "yunionconf" 30889 true true
-
- # monitor: 监控服务 (需要认证和数据库) - 暂时跳过,需要influxdb
- # start_service "monitor" 30093 true true
- echo -e "${YELLOW} 跳过 monitor (需要 influxdb/victoria-metrics)${NC}"
-
- # scheduledtask: 定时任务服务 (需要认证和数据库)
- start_service "scheduledtask" 30891 true true
-
- echo ""
-
- # 第三阶段:启动API网关 (需要认证,不需要数据库)
- echo -e "${YELLOW}阶段 3: 启动API网关${NC}"
- start_service "apigateway" 30300 true false
-
- echo ""
- echo -e "${GREEN}=== 服务启动完成 ===${NC}"
- echo ""
- echo -e "${GREEN}访问地址:${NC}"
- echo " API Gateway: http://localhost:30300"
- echo " Keystone: http://localhost:35357"
- echo ""
- echo -e "${YELLOW}查看日志: tail -f $LOG_DIR/<service>.log${NC}"
- }
- # 停止所有服务
- stop_all() {
- echo -e "${YELLOW}=== 停止所有服务 ===${NC}"
- echo ""
-
- local services=("scheduledtask" "monitor" "yunionconf" "scheduler" "apigateway" "glance" "region" "keystone")
-
- for service in "${services[@]}"; do
- stop_service "$service"
- done
-
- echo ""
- echo -e "${GREEN}=== 所有服务已停止 ===${NC}"
- }
- # 查看服务状态
- status_all() {
- echo -e "${GREEN}=== 服务状态 ===${NC}"
- echo ""
-
- # 检查etcd
- if [ -f "$BACKEND_DIR/logs/etcd.pid" ]; then
- local pid=$(cat "$BACKEND_DIR/logs/etcd.pid")
- if ps -p "$pid" > /dev/null 2>&1; then
- echo -e "${GREEN} ✓ etcd${NC} (PID: $pid, Port: 2379)"
- else
- echo -e "${RED} ✗ etcd${NC} (未运行)"
- fi
- else
- echo -e "${RED} ✗ etcd${NC} (未运行)"
- fi
-
- local services=("keystone:35357" "region:30888" "glance:9292" "apigateway:30300" "scheduler:30888" "yunionconf:30889" "monitor:30093" "scheduledtask:30891")
-
- for service_info in "${services[@]}"; do
- local service_name="${service_info%%:*}"
- local port="${service_info##*:}"
-
- if is_service_running "$service_name"; then
- local pid=$(cat "$PID_DIR/${service_name}.pid")
- echo -e "${GREEN} ✓ $service_name${NC} (PID: $pid, Port: $port)"
- else
- echo -e "${RED} ✗ $service_name${NC} (未运行)"
- fi
- done
- echo ""
- }
- # 主函数
- case "${1:-}" in
- start)
- start_all
- ;;
- stop)
- stop_all
- ;;
- restart)
- stop_all
- sleep 2
- start_all
- ;;
- status)
- status_all
- ;;
- *)
- echo "用法: $0 {start|stop|restart|status}"
- echo ""
- echo "命令:"
- echo " start - 启动所有服务"
- echo " stop - 停止所有服务"
- echo " restart - 重启所有服务"
- echo " status - 查看服务状态"
- exit 1
- ;;
- esac
|