#!/usr/bin/env bash # ============================================================================= # 00-init-tools.sh — 安装并配置服务器基础工具环境 # # 功能: # 1. 安装 Go(默认 1.22.5,可通过参数指定版本) # 2. 配置 GOPROXY(自动测速选最快节点) # 3. 安装 Node.js / npm(前端依赖) # 4. 安装 Docker(基础设施容器) # 5. 写入 /etc/profile.d/deploy-env.sh(永久生效) # # 用法: # ./deploy-test/00-init-tools.sh # 安装全部 # ./deploy-test/00-init-tools.sh go # 只安装/配置 Go # ./deploy-test/00-init-tools.sh node # 只安装 Node.js # ./deploy-test/00-init-tools.sh docker # 只安装 Docker # ./deploy-test/00-init-tools.sh goproxy # 只配置 GOPROXY # # 前置条件: root 或 sudo 权限,Ubuntu/Debian 系统 # # 下一步: ./deploy-test/01-init-env.sh # ============================================================================= set -euo pipefail source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" init_dirs init_script_log # ── 可调参数 ─────────────────────────────────────────────────────────────────── GO_VERSION="${GO_VERSION:-1.22.5}" GO_ARCH="${GO_ARCH:-amd64}" # amd64 / arm64 NODE_VERSION="${NODE_VERSION:-20}" # Node.js LTS 大版本 PROFILE_FILE="/etc/profile.d/deploy-env.sh" TARGET="${1:-all}" header "步骤 0 — 初始化工具环境" echo " 目标: ${TARGET} (Go=${GO_VERSION}, Node=${NODE_VERSION})" # ────────────────────────────────────────────────────────────────────────────── # 辅助函数 # ────────────────────────────────────────────────────────────────────────────── # 检查命令是否存在(不触发 set -e) _has() { command -v "$1" &>/dev/null; } # 追加到全局 profile(幂等:同一行不重复写) _append_profile() { local line="$1" grep -qxF "$line" "$PROFILE_FILE" 2>/dev/null || echo "$line" >> "$PROFILE_FILE" } # 测试 GOPROXY 节点延迟,返回 ms(超时返回 9999) _probe_proxy() { local url="${1%/}/github.com/gin-gonic/gin/@v/list" local ms ms=$(curl -s -o /dev/null -w "%{time_total}" --max-time 5 "$url" 2>/dev/null || echo "9.999") echo "${ms/./}" | sed 's/^0*//' | awk '{printf "%d\n", $1 * 1000 / 1000 + 0}' # 简单地把秒转毫秒并取整 python3 -c "print(int(float('${ms}') * 1000))" 2>/dev/null || echo 9999 } # ────────────────────────────────────────────────────────────────────────────── # 1. Go # ────────────────────────────────────────────────────────────────────────────── _install_go() { step "安装 Go ${GO_VERSION} (linux/${GO_ARCH})" local tarball="go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" local url="https://go.dev/dl/${tarball}" local tmp="/tmp/${tarball}" if _has go; then local cur cur=$(go version | awk '{print $3}' | sed 's/go//') if [[ "$cur" == "$GO_VERSION" ]]; then success " Go ${GO_VERSION} 已安装,跳过" return 0 fi warn " 当前 Go 版本 ${cur},将升级到 ${GO_VERSION}" fi info " 下载 ${url}" curl -fL --progress-bar -o "$tmp" "$url" || { # 备用镜像 warn " go.dev 下载失败,尝试备用镜像..." curl -fL --progress-bar -o "$tmp" "https://golang.google.cn/dl/${tarball}" || { error " 下载失败,请手动安装: https://go.dev/dl/" return 1 } } info " 解压到 /usr/local/go" rm -rf /usr/local/go tar -C /usr/local -xzf "$tmp" rm -f "$tmp" # 写入 profile [[ -f "$PROFILE_FILE" ]] || touch "$PROFILE_FILE" _append_profile 'export PATH=$PATH:/usr/local/go/bin' _append_profile 'export GOPATH=/root/go' _append_profile 'export GOMODCACHE=/root/go/pkg/mod' # 当前会话也生效 export PATH=$PATH:/usr/local/go/bin export GOPATH=/root/go export GOMODCACHE=/root/go/pkg/mod success " Go $(go version | awk '{print $3}') 安装完成 → /usr/local/go/bin/go" } # ────────────────────────────────────────────────────────────────────────────── # 2. GOPROXY — 自动选最快节点 # ────────────────────────────────────────────────────────────────────────────── _config_goproxy() { step "配置 GOPROXY(自动测速)" if ! _has go; then warn " go 未安装,跳过 GOPROXY 配置" return 0 fi declare -A PROXIES=( ["proxy.golang.org"]="https://proxy.golang.org" ["goproxy.cn"]="https://goproxy.cn" ["goproxy.io"]="https://goproxy.io" ) local best_name="goproxy.io" local best_ms=9999 info " 测速中..." for name in "${!PROXIES[@]}"; do local url="${PROXIES[$name]}" local ms ms=$(python3 -c " import urllib.request, time, sys try: t = time.time() urllib.request.urlopen('${url}/github.com/gin-gonic/gin/@v/list', timeout=5) print(int((time.time()-t)*1000)) except: print(9999) " 2>/dev/null) echo " ${name}: ${ms}ms" if (( ms < best_ms )); then best_ms=$ms best_name=$name best_url="${url}" fi done # 构建代理列表:最快的放第一 local proxy_list="${best_url},https://proxy.golang.org,https://goproxy.cn,direct" # 去重 proxy_list=$(echo "$proxy_list" | tr ',' '\n' | awk '!seen[$0]++' | tr '\n' ',' | sed 's/,$//') go env -w GOPROXY="${proxy_list}" go env -w GONOSUMDB="*" go env -w GOFLAGS="" # 同步写入 profile(go env -w 已持久化到 GOENV,这里写 profile 作为双保险) _append_profile "export GOPROXY=${proxy_list}" _append_profile 'export GONOSUMDB=*' success " GOPROXY=${proxy_list}" success " 最快节点: ${best_name} (${best_ms}ms)" } # ────────────────────────────────────────────────────────────────────────────── # 3. Node.js # ────────────────────────────────────────────────────────────────────────────── _install_node() { step "安装 Node.js ${NODE_VERSION}.x LTS" if _has node; then local cur cur=$(node --version) info " 当前 Node.js 版本: ${cur}" # 检查大版本是否匹配 local major major=$(echo "$cur" | sed 's/v//' | cut -d. -f1) if (( major >= NODE_VERSION )); then success " Node.js >= ${NODE_VERSION},跳过" return 0 fi warn " 版本过旧,将升级" fi if _has apt-get; then info " 使用 NodeSource 安装 Node.js ${NODE_VERSION}.x" curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash - apt-get install -y nodejs elif _has yum; then curl -fsSL "https://rpm.nodesource.com/setup_${NODE_VERSION}.x" | bash - yum install -y nodejs else warn " 未找到 apt-get/yum,请手动安装 Node.js: https://nodejs.org/" return 1 fi # 安装常用全局包管理器 npm install -g pnpm yarn 2>/dev/null || true _append_profile 'export PATH=$PATH:/usr/local/bin' # 将 GitHub SSH 地址重写为 HTTPS(服务器通常没有 GitHub SSH 密钥) git config --global url."https://github.com/".insteadOf "git+ssh://git@github.com/" 2>/dev/null || true git config --global url."https://github.com/".insteadOf "ssh://git@github.com/" 2>/dev/null || true git config --global url."https://github.com/".insteadOf "git@github.com:" 2>/dev/null || true success " Node.js $(node --version),npm $(npm --version) 安装完成" _has pnpm && success " pnpm $(pnpm --version)" _has yarn && success " yarn $(yarn --version)" } # ────────────────────────────────────────────────────────────────────────────── # 4. Docker # ────────────────────────────────────────────────────────────────────────────── _install_docker() { step "安装 Docker" if _has docker; then success " Docker $(docker --version | awk '{print $3}' | tr -d ',') 已安装,跳过" return 0 fi if _has apt-get; then info " 使用官方脚本安装 Docker..." curl -fsSL https://get.docker.com | sh elif _has yum; then yum install -y docker systemctl enable docker else warn " 未找到 apt-get/yum,请手动安装 Docker: https://docs.docker.com/engine/install/" return 1 fi # 启动服务 systemctl start docker 2>/dev/null || service docker start 2>/dev/null || true success " Docker $(docker --version | awk '{print $3}' | tr -d ',') 安装完成" } # ────────────────────────────────────────────────────────────────────────────── # 执行 # ────────────────────────────────────────────────────────────────────────────── case "$TARGET" in go) _install_go _config_goproxy ;; goproxy) _config_goproxy ;; node) _install_node ;; docker) _install_docker ;; all) _install_go _config_goproxy _install_node _install_docker ;; *) error "未知目标: $TARGET" echo "用法: $0 [all|go|goproxy|node|docker]" exit 1 ;; esac # ────────────────────────────────────────────────────────────────────────────── # 汇总 # ────────────────────────────────────────────────────────────────────────────── echo "" success "环境初始化完成!" echo "" echo -e "${BOLD}当前工具版本:${NC}" _has go && echo " Go: $(go version | awk '{print $3, $4}')" || echo " Go: 未安装" _has node && echo " Node: $(node --version)" || echo " Node: 未安装" _has npm && echo " npm: $(npm --version)" || echo " npm: 未安装" _has pnpm && echo " pnpm: $(pnpm --version)" || echo " pnpm: 未安装" _has yarn && echo " yarn: $(yarn --version)" || echo " yarn: 未安装" _has docker && echo " Docker: $(docker --version | awk '{print $3}' | tr -d ',')" || echo " Docker: 未安装" echo "" echo -e "${BOLD}GOPROXY 配置:${NC}" _has go && go env GOPROXY || echo " (go 未安装)" echo "" echo -e "${YELLOW}注意: 新终端需执行以下命令使环境变量生效:${NC}" echo -e " ${CYAN}source /etc/profile.d/deploy-env.sh${NC}" echo -e " 或重新登录 SSH" echo "" echo -e "${BOLD}下一步:${NC}" echo -e " ${CYAN}./deploy-test/01-init-env.sh${NC}"