#!/bin/bash
set -e
# 颜色输出
green() { echo -e "\033[32m$1\033[0m"; }
yellow() { echo -e "\033[33m$1\033[0m"; }
red() { echo -e "\033[31m$1\033[0m"; }
blue() { echo -e "\033[34m$1\033[0m"; }
# 检查/data目录是否存在
check_data_directory() {
if [ ! -d "/data" ]; then
red "错误: /data 目录不存在!"
yellow "请先创建并挂载 /data 目录"
exit 1
fi
sudo chmod 755 /data
}
# 准备MySQL主目录(统一存放数据+日志)
prepare_mysql_directory() {
local mysql_dir="/data/mysql"
if [ -d "$mysql_dir" ]; then
yellow "发现已存在的MySQL目录: $mysql_dir"
printf "是否删除现有数据并重新初始化?(y/N): "
read choice
if [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then
sudo rm -rf "$mysql_dir"
fi
fi
sudo mkdir -p "$mysql_dir"
sudo chmod 755 "$mysql_dir"
green "✓ MySQL主目录准备完成: $mysql_dir"
}
# 设置MySQL目录权限
setup_mysql_permissions() {
local mysql_dir="/data/mysql"
yellow "设置MySQL目录权限..."
sleep 2
if ! id "mysql" &>/dev/null; then
red "✗ mysql用户不存在,正在创建..."
sudo groupadd mysql 2>/dev/null || true
sudo useradd -r -g mysql -s /bin/false mysql 2>/dev/null || true
fi
sudo chown -R mysql:mysql "$mysql_dir"
sudo chmod 750 "$mysql_dir"
green "✓ 权限设置完成"
}
# 创建MySQL配置文件(所有路径统一到 /data/mysql)
create_mysql_config() {
yellow "创建MySQL配置文件..."
# 创建配置目录
sudo mkdir -p /etc/mysql/conf.d
sudo mkdir -p /etc/mysql/mysql.conf.d
sudo mkdir -p /var/run/mysqld
# 设置运行时目录权限(兼容性)
sudo chown -R mysql:mysql /var/run/mysqld
sudo chmod 755 /var/run/mysqld
# 主配置文件
sudo tee /etc/mysql/my.cnf > /dev/null <<'EOF'
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
EOF
# mysqld 配置 - 简化版本,避免语法错误
sudo tee /etc/mysql/mysql.conf.d/mysqld.cnf > /dev/null <<'EOF'
[mysqld]
user = mysql
datadir = /data/mysql
socket = /data/mysql/mysqld.sock
pid-file = /data/mysql/mysqld.pid
log_error = /data/mysql/error.log
bind-address = 0.0.0.0
port = 3306
innodb_buffer_pool_size = 128M
skip-name-resolve
default_authentication_plugin = mysql_native_password
# 字符集设置
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
EOF
# 客户端配置 - 简化版本
sudo tee /etc/mysql/conf.d/mysql.cnf > /dev/null <<'EOF'
[mysql]
[client]
socket = /data/mysql/mysqld.sock
EOF
green "✓ MySQL配置文件创建完成(数据与日志均在 /data/mysql)"
}
# 修复AppArmor权限
fix_apparmor_permissions() {
local mysql_dir="/data/mysql"
if [ -f "/etc/apparmor.d/usr.sbin.mysqld" ]; then
yellow "修复AppArmor权限..."
# 备份
sudo cp /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/usr.sbin.mysqld.backup.$(date +%Y%m%d_%H%M%S)
# 确保 datadir 被放行
if ! grep -q "$mysql_dir/\*\* rwk" /etc/apparmor.d/usr.sbin.mysqld; then
sudo sed -i "/\/var\/lib\/mysql\/\*\* rwk,/a\ $mysql_dir/** rwk," /etc/apparmor.d/usr.sbin.mysqld
fi
# 重载
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld
green "✓ AppArmor权限修复完成"
else
yellow "⚠ AppArmor配置文件不存在,跳过"
fi
}
# 检查MySQL是否已安装
check_mysql_installed() {
if command -v mysql >/dev/null 2>&1; then return 0; fi
if [ -f /etc/init.d/mysql ] || { command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files | grep -q mysql; }; then return 0; fi
if pgrep mysqld >/dev/null 2>&1; then return 0; fi
return 1
}
# 显示MySQL状态
show_mysql_status() {
echo
blue "====================================="
blue " MySQL 状态检查"
blue "====================================="
if command -v mysql >/dev/null 2>&1; then
green "MySQL客户端: 已安装"
mysql --version 2>/dev/null || mysql -V 2>/dev/null
else
yellow "MySQL客户端: 未安装"
fi
local mysql_dir="/data/mysql"
if [ -d "$mysql_dir" ]; then
local db_size=$(sudo du -sh "$mysql_dir" 2>/dev/null | cut -f1)
local db_count=$(sudo find "$mysql_dir" -maxdepth 1 -type d -name '*' 2>/dev/null | wc -l)
red "⚠ 发现MySQL数据目录: $mysql_dir"
red "⚠ 数据目录大小: $db_size"
red "⚠ 数据库数量: $((db_count - 1))"
elif [ -d "/var/lib/mysql" ]; then
local db_size=$(sudo du -sh /var/lib/mysql 2>/dev/null | cut -f1)
local db_count=$(sudo find /var/lib/mysql -maxdepth 1 -type d -name '*' 2>/dev/null | wc -l)
red "⚠ 发现MySQL数据目录: /var/lib/mysql"
red "⚠ 数据目录大小: $db_size"
red "⚠ 数据库数量: $((db_count - 1))"
fi
blue "====================================="
echo
}
# 备份数据库
backup_databases() {
echo
yellow "建议在重新安装前备份数据库!"
printf "是否要备份数据库?(y/N): "
read backup_choice
if [ "$backup_choice" = "y" ] || [ "$backup_choice" = "Y" ]; then
if command -v mysqldump >/dev/null 2>&1; then
local backup_dir="/tmp/mysql_backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$backup_dir"
yellow "正在备份数据库到: $backup_dir"
if sudo mysqldump --all-databases > "$backup_dir/all_databases.sql" 2>/dev/null; then
green "✓ 数据库备份完成: $backup_dir/all_databases.sql"
else
red "✗ 数据库备份失败,可能无法连接或没有权限"
fi
else
red "✗ mysqldump 不可用,无法备份"
fi
else
yellow "跳过数据库备份"
fi
}
# 清理旧版本MySQL
clean_old_mysql() {
red "开始清理旧版本MySQL..."
red "⚠ 警告:这将删除所有MySQL数据和配置!"
echo
red "将被删除的内容:"
red " - 所有数据库数据 (/var/lib/mysql/ 和 /data/mysql/)"
red " - 配置文件 (/etc/mysql/)"
red " - 日志文件 (/var/log/mysql*, /data/mysql/error.log)"
red " - 所有用户数据和权限"
echo
printf "确定要删除所有MySQL数据并重新安装吗?(输入 'DELETE' 确认): "
read final_confirmation
if [ "$final_confirmation" != "DELETE" ]; then
green "安装已取消,数据得以保留"
exit 0
fi
yellow "开始清理..."
# 停止服务
sudo systemctl stop mysql 2>/dev/null || true
sudo systemctl disable mysql 2>/dev/null || true
sudo pkill -9 mysqld 2>/dev/null || true
sleep 2
# 卸载包
yellow "卸载MySQL软件包..."
sudo apt remove --purge mysql* mariadb* -y 2>/dev/null || true
sudo apt autoremove -y
sudo apt autoclean
# 删除文件
yellow "删除MySQL相关文件..."
sudo rm -rf /etc/mysql /var/lib/mysql /var/log/mysql* /var/run/mysqld /data/mysql
green "旧版本MySQL清理完成"
echo
}
# 初始化MySQL数据目录
initialize_mysql_data() {
local mysql_dir="/data/mysql"
yellow "准备MySQL数据目录..."
sudo systemctl stop mysql 2>/dev/null || true
sleep 3
if [ -d "$mysql_dir/mysql" ]; then
green "✓ MySQL系统数据库已存在,跳过初始化"
return 0
fi
if [ -d "$mysql_dir" ]; then
yellow "目录存在但未初始化,清理..."
sudo rm -rf "$mysql_dir"
fi
sudo mkdir -p "$mysql_dir"
sudo chown -R mysql:mysql "$mysql_dir"
sudo chmod 750 "$mysql_dir"
yellow "初始化MySQL系统表(不安全模式)..."
if sudo -u mysql mysqld --initialize-insecure --datadir="$mysql_dir" --user=mysql 2>&1 | tee /tmp/mysql_init.log; then
if [ -d "$mysql_dir/mysql" ]; then
green "✓ MySQL数据目录初始化成功"
return 0
else
red "✗ 系统表未生成"
return 1
fi
else
red "✗ MySQL初始化失败"
cat /tmp/mysql_init.log | tail -10
if [ -f "/data/mysql/error.log" ]; then
red "错误日志:"
sudo tail -10 /data/mysql/error.log
fi
return 1
fi
}
# 创建systemd服务文件
create_systemd_service() {
yellow "创建systemd服务文件..."
# 检查服务文件是否存在
if [ ! -f "/etc/systemd/system/mysql.service" ] && [ ! -f "/lib/systemd/system/mysql.service" ]; then
sudo tee /etc/systemd/system/mysql.service > /dev/null <<'EOF'
[Unit]
Description=MySQL Community Server
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
Type=forking
PIDFile=/data/mysql/mysqld.pid
ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/data/mysql/mysqld.pid
ExecStop=/bin/kill -TERM $MAINPID
LimitNOFILE=5000
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
green "✓ systemd服务文件创建完成"
else
# 如果服务文件存在,修复它
if [ -f "/lib/systemd/system/mysql.service" ]; then
sudo sed -i 's|/var/lib/mysql|/data/mysql|g' /lib/systemd/system/mysql.service
sudo sed -i 's|PIDFile=.*|PIDFile=/data/mysql/mysqld.pid|' /lib/systemd/system/mysql.service
fi
green "✓ systemd服务文件已修复"
fi
# 重新加载systemd
sudo systemctl daemon-reload
sudo systemctl enable mysql.service 2>/dev/null || sudo systemctl enable mysql 2>/dev/null || true
}
# 修复MySQL服务启动
fix_mysql_service() {
yellow "修复MySQL服务启动问题..."
sudo systemctl stop mysql 2>/dev/null || true
sudo pkill -9 mysqld 2>/dev/null || true
sleep 2
# 清理残留
sudo rm -f /var/run/mysqld/mysqld.pid /var/run/mysqld/mysqld.sock
sudo rm -f /data/mysql/mysqld.pid /data/mysql/mysqld.sock
# 创建systemd服务
create_systemd_service
# 修复 systemd 启动脚本(如果存在)
if [ -f "/usr/share/mysql/mysql-systemd-start" ]; then
if grep -q "/var/lib/mysql" /usr/share/mysql/mysql-systemd-start; then
yellow "修复systemd启动脚本..."
sudo sed -i 's|/var/lib/mysql|/data/mysql|g' /usr/share/mysql/mysql-systemd-start
fi
fi
# 启动服务
yellow "启动MySQL服务..."
if sudo systemctl start mysql; then
sleep 5
if sudo systemctl is-active mysql >/dev/null 2>&1; then
green "✓ MySQL服务启动成功"
return 0
fi
fi
# 如果systemd启动失败,尝试直接启动
yellow "systemd启动失败,尝试直接启动mysqld..."
sudo -u mysql mysqld --daemonize --datadir=/data/mysql --pid-file=/data/mysql/mysqld.pid
sleep 3
if pgrep mysqld >/dev/null 2>&1; then
green "✓ MySQL直接启动成功"
return 0
fi
red "✗ MySQL服务启动失败"
# 显示错误信息
if [ -f "/data/mysql/error.log" ]; then
red "错误日志:"
sudo tail -20 /data/mysql/error.log
fi
return 1
}
# 验证安装
verify_installation() {
echo
green "验证MySQL安装..."
if ! command -v mysql >/dev/null 2>&1; then
red "✗ MySQL客户端未安装"
return 1
fi
# 检查进程是否运行
if pgrep mysqld >/dev/null 2>&1; then
green "✓ MySQL进程正在运行"
# 等待一下让MySQL完全启动
sleep 3
# 尝试连接
if sudo mysql --socket=/data/mysql/mysqld.sock -e "SELECT @@version, @@datadir;" 2>/dev/null; then
green "✓ MySQL连接成功"
actual_datadir=$(sudo mysql --socket=/data/mysql/mysqld.sock -sN -e "SELECT @@datadir;" 2>/dev/null || echo "")
if [ "$actual_datadir" = "/data/mysql/" ]; then
green "✓ 数据目录正确: /data/mysql/"
else
yellow "⚠ 实际 datadir: $actual_datadir"
fi
return 0
else
yellow "⚠ MySQL进程在运行但无法连接,可能还在启动中"
return 1
fi
else
red "✗ MySQL进程未运行"
return 1
fi
}
# 等待用户按键
wait_for_key() {
yellow "按 Enter 键继续或 Ctrl+C 取消..."
read dummy
}
# 主流程
main() {
clear
green "====================================="
green " MySQL 安装管理脚本"
green " (数据、日志、socket 均在 /data/mysql)"
green "====================================="
echo
check_data_directory
if check_mysql_installed; then
red "⚠ 检测到系统已安装 MySQL!"
show_mysql_status
printf "是否重新安装MySQL?(y/N): "
read reinstall_choice
if [ "$reinstall_choice" = "y" ] || [ "$reinstall_choice" = "Y" ]; then
backup_databases
echo
red "=================================================="
red " ⚠ 警告 ⚠"
red "重新安装将永久删除:"
red " - 所有数据库和数据表"
red " - 所有用户账户和权限"
red " - 所有配置和日志"
red "此操作不可撤销!"
red "=================================================="
echo
printf "确定要继续重新安装吗?(输入 'CONFIRM' 继续): "
read final_confirm
if [ "$final_confirm" != "CONFIRM" ]; then
green "安装已取消"
exit 0
fi
clean_old_mysql
else
green "已退出安装"
exit 0
fi
else
green "未检测到MySQL,开始全新安装..."
fi
wait_for_key
# 安装
yellow "更新软件包列表..."
sudo apt update
yellow "安装MySQL服务器..."
if ! sudo apt install -y mysql-server; then
red "✗ MySQL安装失败"
exit 1
fi
prepare_mysql_directory
setup_mysql_permissions
create_mysql_config
fix_apparmor_permissions
initialize_mysql_data
fix_mysql_service
if verify_installation; then
green "🎉 MySQL安装成功!"
echo
yellow "现在可以运行安全配置:"
yellow "sudo mysql_secure_installation --socket=/data/mysql/mysqld.sock"
echo
yellow "或者手动设置密码:"
yellow "sudo mysql --socket=/data/mysql/mysqld.sock -e \"ALTER USER 'root'@'localhost' IDENTIFIED BY '你的密码';\""
else
red "❌ 安装失败,请检查日志"
exit 1
fi
}
# 执行
main