From 08dd783bd37be2d88138499830fbccb0725164bb Mon Sep 17 00:00:00 2001 From: vet Date: Mon, 13 Apr 2026 13:10:38 +0700 Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E7=BD=AEgonode=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 00-init-tools.sh | 291 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100755 00-init-tools.sh diff --git a/00-init-tools.sh b/00-init-tools.sh new file mode 100755 index 0000000..6843769 --- /dev/null +++ b/00-init-tools.sh @@ -0,0 +1,291 @@ +#!/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' + + 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}"