#!/bin/bash # 移除 set -e,改为手动控制错误,防止意外退出 set -o pipefail # ================= 1. 加载环境变量 (.env) ================= SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="${SCRIPT_DIR}/.env" load_env_file() { if [ -f "$ENV_FILE" ]; then while IFS= read -r line || [[ -n "$line" ]]; do # 去除首尾空白 line=$(echo "$line" | xargs) # 跳过空行和注释 [[ -z "$line" || "$line" == \#* ]] && continue # 简单的格式校验 (KEY=VALUE) if [[ "$line" =~ ^([A-Za-z_][A-Za-z0-9_]*)= ]]; then key="${BASH_REMATCH[1]}" # 只有当该变量尚未在环境中设置时,才从文件加载 (支持命令行覆盖) if [ -z "${!key}" ]; then export "$line" fi fi done < "$ENV_FILE" echo -e "\033[0;36m[CONFIG]\033[0m 已加载配置:$ENV_FILE" else # 如果文件不存在,不报错,依赖后续检查或命令行传入 : fi } # 执行加载 load_env_file # ================= 2. 颜色与日志 ================= RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_step() { echo -e "${BLUE}[STEP]${NC} $1"; } log_success() { echo -e "${CYAN}[OK]${NC} $1"; } log_header() { echo "" echo "========================================" echo -e "${BLUE}$1${NC}" echo "========================================" } # ================= 3. 配置与初始化 ================= HOST_FILE="${SCRIPT_DIR}/host_list.txt" SCRIPT_JUICEFS="${SCRIPT_DIR}/4.1.deploy_cluster.sh" # 核心二进制文件和服务文件列表 CORE_FILES=("juicefs" "juicefs.service") # ================= 4. 关键变量预检 ================= log_header "������ MinIO 集群全自动部署启动" # 检查必要的环境变量 if [ -z "$JUICEFS_USER" ]; then log_error "❌ 缺少环境变量 JUICEFS_USER" log_info "请在 ${ENV_FILE} 中配置,或使用命令运行: JUICEFS_USER=admin ./2.deploy_juicefs.sh" exit 1 fi if [ -z "$JUICEFS_PASSWORD" ]; then log_error "❌ 缺少环境变量 JUICEFS_PASSWORD" log_info "请在 ${ENV_FILE} 中配置,或使用命令运行: JUICEFS_PASSWORD=你的密码 ./2.deploy_juicefs.sh" exit 1 fi log_info "已加载账号:JUICEFS_USER=$JUICEFS_USER" log_info "已加载密码:JUICEFS_PASSWORD=****** (长度:${#JUICEFS_PASSWORD})" # ================= 5. 前置文件检查 ================= # 1. 检查 host_list.txt if [ ! -f "$HOST_FILE" ]; then log_error "找不到主机列表文件:$HOST_FILE" exit 1 fi log_info "主机列表:$HOST_FILE" log_info "工作目录:$SCRIPT_DIR" # 定义函数:提取指定区块的节点 get_section_nodes() { local target_section="$1" local current_section="" local in_target=false while IFS= read -r line || [[ -n "$line" ]]; do # 跳过空行 [[ -z "${line// /}" ]] && continue # 跳过注释行 [[ "$line" =~ ^[[:space:]]*# ]] && continue # 检测区块标记 if [[ "$line" =~ ^\[([a-zA-Z0-9_-]+)\]$ ]]; then current_section="${BASH_REMATCH[1]}" if [ "$current_section" == "$target_section" ]; then in_target=true else in_target=false fi continue fi # 只在目标区块内输出数据 if [ "$in_target" == true ]; then echo "$line" fi done < "$HOST_FILE" } # ================= 按区块解析主机列表 ================= log_step "解析 [metadata] 区块主机列表..." declare -a META_NAMES META_COUNT=0 while IFS= read -r line || [[ -n "$line" ]]; do # 使用 awk 提取,避免 shell 词法解析特殊字符的问题 name=$(echo "$line" | awk '{print $1}') if [ -z "$name" ] ; then log_warn "跳过格式错误的行 (缺少列): $line" continue fi # 存入数组 META_NAMES+=("$name") ((META_COUNT++)) done < <(get_section_nodes "metadata") if [ $META_COUNT -eq 0 ]; then log_error "未找到 [metadata] 区块的有效节点配置,请检查 $HOST_FILE 格式" exit 1 fi log_success "共解析到 $META_COUNT 个 Metadata 节点" # 显示解析到的节点 echo "" log_info "Metadata 节点列表:" for i in "${!META_NAMES[@]}"; do echo " $i: ${META_NAMES[$i]} " mc alias set minio_cluster http://${META_NAMES[$i]}:9000 ${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD} mc mb minio_cluster/${JUICEFS_BUCKET} juicefs format \ --storage s3 \ --bucket http://${META_NAMES[$i]}:9000/${JUICEFS_BUCKET} \ --access-key ${MINIO_ROOT_USER} \ --secret-key ${MINIO_ROOT_PASSWORD} \ redis://@${META_NAMES[$i]}:6379/1 \ ${JUICEFS_BUCKET} done echo "" # ================= 3. 配置与初始化 ================= HOST_FILE="${SCRIPT_DIR}/host_list.txt" SCRIPT_JUICEFS="${SCRIPT_DIR}/4.1.deploy_cluster.sh" # 核心二进制文件和服务文件列表 CORE_FILES=("juicefs" "juicefs.service") # ================= 4. 关键变量预检 ================= log_header " MinIO 集群全自动部署启动" # 检查必要的环境变量 if [ -z "$JUICEFS_USER" ]; then log_error "❌ 缺少环境变量 JUICEFS_USER" log_info "请在 ${ENV_FILE} 中配置" exit 1 fi if [ -z "$JUICEFS_PASSWORD" ]; then log_error "❌ 缺少环境变量 JUICEFS_PASSWORD" log_info "请在 ${ENV_FILE} 中配置" exit 1 fi log_info "已加载账号:JUICEFS_USER=$JUICEFS_USER" log_info "已加载密码:JUICEFS_PASSWORD=****** (长度:${#JUICEFS_PASSWORD})" # ================= 5. 前置文件检查 ================= # 1. 检查 host_list.txt if [ ! -f "$HOST_FILE" ]; then log_error "找不到主机列表文件:$HOST_FILE" exit 1 fi log_info "主机列表:$HOST_FILE" log_info "工作目录:$SCRIPT_DIR" # ================= 按区块解析主机列表 ================= log_step "解析 [juicefs] 区块主机列表..." declare -a NODE_NAMES declare -a NODE_IPS declare -a NODE_USERS declare -a NODE_PASSES COUNT=0 while IFS= read -r line || [[ -n "$line" ]]; do # 使用 awk 提取,避免 shell 词法解析特殊字符的问题 name=$(echo "$line" | awk '{print $1}') ip=$(echo "$line" | awk '{print $2}') user=$(echo "$line" | awk '{print $3}') pass=$(echo "$line" | awk '{print $4}') if [ -z "$name" ] || [ -z "$ip" ] || [ -z "$user" ] || [ -z "$pass" ] ; then log_warn "跳过格式错误的行 (缺少列): $line" continue fi # 存入数组 NODE_NAMES+=("$name") NODE_IPS+=("$ip") NODE_USERS+=("$user") NODE_PASSES+=("$pass") ((COUNT++)) done < <(get_section_nodes "juicefs") if [ $COUNT -eq 0 ]; then log_error "未找到 [juicefs] 区块的有效节点配置,请检查 $HOST_FILE 格式" exit 1 fi log_success "共解析到 $COUNT 个 Juicefs 节点" # 显示解析到的节点 echo "" log_info "Juicefs 节点列表:" for i in "${!NODE_NAMES[@]}"; do echo " $i: ${NODE_NAMES[$i]} (${NODE_IPS[$i]}) " done echo "" TOTAL_NODES=$COUNT FAILED_COUNT=0 # ================= Juicefs-Gateway 部署 ================= log_header " 部署 Juicefs-Gateway 服务" for i in "${!NODE_NAMES[@]}"; do name="${NODE_NAMES[$i]}" user="${NODE_USERS[$i]}" log_step "正在部署 Juicefs-Gateway: $name" TARGET="${user}@${name}" # 传递从 .env 或命令行获取的账号密码 if "$SCRIPT_JUICEFS" "$TARGET" "$JUICEFS_USER" "$JUICEFS_PASSWORD" "$REDIS_PASSWORD" "${META_NAMES[$i]}"; then log_success "$name Juicefs-Gateway 服务启动成功" else log_error "$name Juicefs-Gateway 部署失败" ((FAILED_COUNT++)) fi done echo "========================================"