Просмотр исходного кода

fix: 替换 mariadb-client 为官方 MySQL 客户端安装脚本

问题: Debian Trixie 默认 mariadb-client 使用 --ssl=0 语法,
与 MySQL 官方 --ssl-mode=DISABLED 不兼容

修复:
- 检测 MariaDB 客户端并自动替换
- 方式一: MySQL 官方 APT 仓库安装
- 方式二: 直接下载二进制 + xz/Python lzma 双解压方案
- 方式三: 手动安装指引兜底
Matrix Developer 1 месяц назад
Родитель
Сommit
e336a76225
1 измененных файлов с 318 добавлено и 33 удалено
  1. 318 33
      setup-mysql-cli.sh

+ 318 - 33
setup-mysql-cli.sh

@@ -1,45 +1,330 @@
 #!/bin/bash
+# ============================================
+# MySQL CLI 工具安装脚本(官方 MySQL 客户端)
+# 从 Oracle MySQL 官方仓库安装真正的 MySQL 客户端
+# 替代 Debian Trixie 默认的 mariadb-client
+# ============================================
 
-# MySQL CLI工具安装脚本
-# 用于安装MySQL客户端工具
+set -e
 
-# 检查MySQL客户端是否已安装
-if command -v mysql >/dev/null 2>&1; then
-    echo "✅ MySQL CLI 工具已安装"
-    echo "📊 版本:$(mysql --version)"
-else
-    echo "📥 开始安装 MySQL CLI 工具..."
+MYSQL_VERSION="8.4.4"
+BIN_INSTALL_DIR="/usr/local/bin"
+
+# 颜色定义
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+RED='\033[0;31m'
+NC='\033[0m'
+
+info()  { echo -e "${GREEN}[info]${NC} $1"; }
+warn()  { echo -e "${YELLOW}[warn]${NC} $1"; }
+error() { echo -e "${RED}[error]${NC} $1"; }
 
-    # 更新软件包列表
-    if ! apt-get update; then
-        echo "❌ 软件包列表更新失败"
-        exit 1
+# ------------------------------------------
+# 检查是否已安装正确的 MySQL 客户端
+# ------------------------------------------
+check_mysql_client() {
+  if command -v mysql >/dev/null 2>&1; then
+    local ver
+    ver=$(mysql --version 2>&1)
+
+    if echo "$ver" | grep -qi "mariadb"; then
+      warn "当前是 MariaDB 客户端: $ver"
+      warn "(MariaDB 用 --ssl=0,MySQL 用 --ssl-mode=DISABLED)"
+      warn "将替换为官方 MySQL 客户端..."
+      return 1
     fi
 
-    # 在Debian Trixie中,mysql-client已被mariadb-client-compat替代
-    # 安装mariadb-client,它提供mysql命令行工具
-    echo "📦 安装mariadb-client..."
-    if ! apt-get install -y mariadb-client; then
-        echo "❌ mariadb-client 安装失败"
-        echo "🔄 尝试备用安装方案..."
-
-        # 备用方案:安装默认的MySQL客户端
-        if ! apt-get install -y default-mysql-client; then
-            echo "❌ 所有安装方案都失败了"
-            exit 1
-        fi
+    if mysql --help 2>&1 | grep -q "ssl-mode"; then
+      info "✅ 官方 MySQL 客户端已安装: $ver"
+      return 0
+    else
+      warn "MySQL 客户端版本过旧,不支持 --ssl-mode"
+      return 1
     fi
+  fi
+  return 1
+}
+
+# ------------------------------------------
+# 清理磁盘空间
+# ------------------------------------------
+cleanup_space() {
+  local needed_kb=${1:-51200}  # 默认需要 50MB
+
+  local avail_kb
+  avail_kb=$(df /var/cache/apt/archives/ 2>/dev/null | awk 'NR==2 {print $4}')  # 单位 KB
+
+  if [ -z "$avail_kb" ] || [ "$avail_kb" -lt "$needed_kb" ]; then
+    warn "磁盘空间不足,尝试清理..."
+    apt-get clean 2>/dev/null || true
+    rm -rf /tmp/* /var/tmp/* 2>/dev/null || true
+
+    avail_kb=$(df /var/cache/apt/archives/ 2>/dev/null | awk 'NR==2 {print $4}')
+    if [ -n "$avail_kb" ] && [ "$avail_kb" -lt "$needed_kb" ]; then
+      warn "清理后空间仍不足 ($((avail_kb / 1024)) MB 可用)"
+      return 1
+    fi
+  fi
+  return 0
+}
+
+# ------------------------------------------
+# 方式一:从 MySQL 官方 APT 仓库安装
+# ------------------------------------------
+install_from_apt() {
+  info "方式一:从 MySQL 官方 APT 仓库安装..."
+
+  # 检查磁盘空间
+  if ! cleanup_space; then
+    warn "磁盘空间不足,跳过 APT 安装方式"
+    return 1
+  fi
+
+  # 确保 wget 可用
+  if ! command -v wget >/dev/null 2>&1; then
+    apt-get update -qq && apt-get install -y -qq wget 2>/dev/null || {
+      warn "wget 不可用,跳过 APT 安装方式"
+      return 1
+    }
+  fi
+
+  local mysql_repo_deb="/tmp/mysql-apt-config.deb"
+
+  # 清理旧配置
+  rm -f /etc/apt/sources.list.d/mysql.list /etc/apt/sources.list.d/mysql-*.list
+
+  # 下载 MySQL APT 配置包
+  info "下载 MySQL APT 配置包..."
+  wget -q "https://repo.mysql.com/mysql-apt-config_0.8.33-1_all.deb" -O "$mysql_repo_deb" || {
+    warn "下载 MySQL APT 配置包失败"
+    return 1
+  }
+
+  # 非交互式安装配置包
+  DEBIAN_FRONTEND=noninteractive dpkg -i "$mysql_repo_deb" 2>/dev/null || true
+
+  # 修正 sources.list 中的 codename
+  # MySQL APT 仓库不支持 Debian Trixie,强制使用 bookworm
+  if [ -f /etc/apt/sources.list.d/mysql.list ]; then
+    sed -i "s/$(lsb_release -sc 2>/dev/null || echo 'unknown')/bookworm/g" \
+      /etc/apt/sources.list.d/mysql.list 2>/dev/null || true
+  fi
+
+  # 更新 APT 缓存
+  info "更新 APT 缓存..."
+  apt-get update -qq 2>/dev/null || {
+    warn "APT 更新失败"
+    return 1
+  }
+
+  # 安装 MySQL 客户端(优先 mysql-client,备用 mysql-community-client)
+  info "安装 mysql-client..."
+  apt-get install -y -qq mysql-client 2>/dev/null || {
+    warn "mysql-client 安装失败,尝试 mysql-community-client..."
+    apt-get install -y -qq mysql-community-client 2>/dev/null || {
+      warn "APT 安装 MySQL 客户端失败"
+      return 1
+    }
+  }
+
+  return 0
+}
+
+# ------------------------------------------
+# 方式二:直接下载 MySQL 客户端二进制
+# ------------------------------------------
+install_from_binary() {
+  info "方式二:直接下载 MySQL 客户端二进制..."
+
+  # 检查磁盘空间(二进制包大约 300MB 解压,但只需要 2 个文件 ~5MB)
+  local needed_kb=102400  # 100MB for download + extract
+  local avail_kb
+  avail_kb=$(df /tmp 2>/dev/null | awk 'NR==2 {print $4}')
+  if [ -n "$avail_kb" ] && [ "$avail_kb" -lt "$needed_kb" ]; then
+    error "磁盘空间不足 ($((avail_kb / 1024)) MB 可用,需要 ~100 MB)"
+    return 1
+  fi
+
+  # 确保 wget 可用
+  if ! command -v wget >/dev/null 2>&1; then
+    error "wget 不可用,无法下载"
+    return 1
+  fi
 
-    # 验证MySQL客户端安装是否成功
-    if command -v mysql >/dev/null 2>&1; then
-        echo "✅ MySQL CLI 工具安装成功"
-        echo "📊 版本:$(mysql --version)"
+  local tmp_dir
+  tmp_dir=$(mktemp -d)
+  local tarball="${tmp_dir}/mysql-${MYSQL_VERSION}-linux-glibc2.28-x86_64.tar.xz"
+  local base_url="https://dev.mysql.com/get/Downloads/MySQL-8.4"
+
+  info "下载 MySQL ${MYSQL_VERSION} 客户端 (约 300MB)..."
+  wget -q --show-progress "${base_url}/$(basename "$tarball")" -O "$tarball" || {
+    error "下载失败"
+    rm -rf "$tmp_dir"
+    return 1
+  }
+
+  # 确保 xz 解压工具可用(.tar.xz 格式需要)
+  if ! command -v xz >/dev/null 2>&1; then
+    warn "xz 未安装,尝试安装 xz-utils..."
+    apt-get install -y -qq xz-utils 2>/dev/null || {
+      warn "apt 安装 xz-utils 失败,改用 Python lzma 模块解压..."
+      # Python 内置了 lzma 模块,无需额外安装
+    }
+  fi
+
+  info "解压(仅提取 mysql 和 mysqladmin)..."
+  local mysql_bin mysqladmin_bin
+  local extract_dir="${tmp_dir}/extract"
+  mkdir -p "$extract_dir"
+
+  if command -v xz >/dev/null 2>&1; then
+    # 有 xz:直接用 tar 解压
+    mysql_bin=$(tar -tJf "$tarball" 2>/dev/null | grep -E 'bin/mysql$' | head -1)
+    mysqladmin_bin=$(tar -tJf "$tarball" 2>/dev/null | grep -E 'bin/mysqladmin$' | head -1)
+    if [ -n "$mysql_bin" ] && [ -n "$mysqladmin_bin" ]; then
+      tar -xJf "$tarball" -C "$extract_dir" "$mysql_bin" "$mysqladmin_bin"
     else
-        echo "❌ MySQL CLI 工具安装失败"
-        exit 1
+      tar -xJf "$tarball" -C "$extract_dir"
+    fi
+  else
+    # 没有 xz:用 Python lzma 模块解压
+    info "使用 Python lzma 模块解压..."
+    python3 -c "
+import lzma, tarfile, sys, os
+
+tarball = '$tarball'
+extract_to = '$extract_dir'
+
+with lzma.open(tarball) as f:
+    with tarfile.open(fileobj=f, mode='r|') as tar:
+        for member in tar:
+            # 只提取 bin/mysql 和 bin/mysqladmin
+            if member.name.endswith('/bin/mysql') or member.name.endswith('/bin/mysqladmin'):
+                tar.extract(member, path=extract_to)
+" 2>/dev/null || {
+      # 如果 Python 也失败,解压全部
+      info "Python 选择性提取失败,解压全部文件..."
+      python3 -c "
+import lzma, tarfile
+
+tarball = '$tarball'
+extract_to = '$extract_dir'
+
+with lzma.open(tarball) as f:
+    with tarfile.open(fileobj=f, mode='r|') as tar:
+        tar.extractall(path=extract_to)
+" 2>/dev/null || {
+        error "Python 解压也失败"
+        rm -rf "$tmp_dir"
+        return 1
+      }
+    }
+  fi
+
+  # 从解压目录复制二进制文件
+  local mysql_src mysqladmin_src
+  mysql_src=$(find "$extract_dir" -name 'mysql' -type f -path '*/bin/mysql' | head -1)
+  mysqladmin_src=$(find "$extract_dir" -name 'mysqladmin' -type f -path '*/bin/mysqladmin' | head -1)
+
+  if [ -n "$mysql_src" ] && [ -n "$mysqladmin_src" ]; then
+    cp "$mysql_src" "${BIN_INSTALL_DIR}/mysql"
+    cp "$mysqladmin_src" "${BIN_INSTALL_DIR}/mysqladmin"
+  else
+    # 最后尝试:直接找任何 mysql 二进制
+    mysql_src=$(find "$extract_dir" -name 'mysql' -type f | head -1)
+    mysqladmin_src=$(find "$extract_dir" -name 'mysqladmin' -type f | head -1)
+    if [ -z "$mysql_src" ]; then
+      error "解压后找不到 mysql 二进制文件"
+      rm -rf "$tmp_dir"
+      return 1
     fi
+    cp "$mysql_src" "${BIN_INSTALL_DIR}/mysql"
+    [ -n "$mysqladmin_src" ] && cp "$mysqladmin_src" "${BIN_INSTALL_DIR}/mysqladmin"
+  fi
+
+  chmod +x "${BIN_INSTALL_DIR}/mysql" "${BIN_INSTALL_DIR}/mysqladmin"
+  rm -rf "$tmp_dir"
+
+  info "二进制安装完成"
+  return 0
+}
+
+# ------------------------------------------
+# 方式三:提示手动安装
+# ------------------------------------------
+manual_install_hint() {
+  echo ""
+  warn "============================================"
+  warn "  自动安装均失败,请手动下载安装:"
+  warn "============================================"
+  echo ""
+  echo "  1. 进入容器:   docker compose exec dev bash"
+  echo ""
+  echo "  2. 下载二进制:"
+  echo "     wget https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-${MYSQL_VERSION}-linux-glibc2.28-x86_64.tar.xz"
+  echo ""
+  echo "  3. 解压并复制:"
+  echo "     tar -xf mysql-${MYSQL_VERSION}-linux-glibc2.28-x86_64.tar.xz \\"
+  echo "       --strip-components 1 -C /usr/local/bin \\"
+  echo "       mysql-${MYSQL_VERSION}-linux-glibc2.28-x86_64/bin/mysql \\"
+  echo "       mysql-${MYSQL_VERSION}-linux-glibc2.28-x86_64/bin/mysqladmin"
+  echo ""
+  echo "  4. 验证:"
+  echo "     mysql --version"
+  echo "     # 应输出: mysql  Ver 8.4.4 for Linux on x86_64 ..."
+  echo ""
+  echo "  5. 连接测试:"
+  echo "     mysql -h mysql -P 3306 -u root -proot --ssl-mode=DISABLED"
+  echo ""
+}
+
+# ==========================================
+# 主流程
+# ==========================================
+echo ""
+echo "======================================"
+echo "  MySQL CLI 安装 (官方客户端)"
+echo "======================================"
+echo ""
+
+# 步骤 1:检查是否已安装正确的版本
+if check_mysql_client; then
+  exit 0
+fi
+
+# 步骤 2:清理旧版 MariaDB 客户端(确保后续 mysql 命令走新版本)
+if dpkg -l mariadb-client 2>/dev/null | grep -q "^ii"; then
+  info "移除旧版 MariaDB 客户端..."
+  apt-get remove -y -qq mariadb-client mariadb-client-core 2>/dev/null || true
 fi
 
-echo "📋 使用说明:"
-echo "   连接命令: mysql -h <主机> -P <端口> -u <用户名> -p"
-echo "   本地连接: mysql -h localhost -P 3306 -u root -p"
+# 步骤 3:优先从官方 APT 仓库安装
+if install_from_apt; then
+  info "✅ 方式一成功:从 APT 仓库安装"
+else
+  warn "方式一失败,尝试方式二(二进制下载)..."
+  if install_from_binary; then
+    info "✅ 方式二成功:从二进制下载安装"
+  else
+    error "❌ 所有安装方案均失败"
+    manual_install_hint
+    exit 1
+  fi
+fi
+
+# 步骤 4:最终验证
+echo ""
+if command -v mysql >/dev/null 2>&1; then
+  mysql_ver=$(mysql --version)
+  info "✅ MySQL 客户端已就绪"
+  info "📊 版本: $mysql_ver"
+  echo ""
+  echo "📋 使用说明:"
+  echo "   连接命令: mysql -h <主机> -P <端口> -u <用户> -p<密码> --ssl-mode=DISABLED"
+  echo "   Docker 内连接: mysql -h mysql -P 3306 -u root -proot --ssl-mode=DISABLED"
+  echo ""
+else
+  error "❌ MySQL 客户端安装失败(未知错误)"
+  exit 1
+fi