| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- #!/bin/bash
- # ============================================
- # MySQL CLI 工具安装脚本(官方 MySQL 客户端)
- # 从 Oracle MySQL 官方仓库安装真正的 MySQL 客户端
- # 替代 Debian Trixie 默认的 mariadb-client
- # ============================================
- set -e
- 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"; }
- # ------------------------------------------
- # 检查是否已安装正确的 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
- 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
- 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
- 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
- # 步骤 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
|