322 lines
10 KiB
Bash
322 lines
10 KiB
Bash
#!/bin/bash
|
|
# MySQL连接诊断脚本
|
|
# 用于诊断和修复MySQL外部连接问题
|
|
|
|
set -e
|
|
|
|
# 颜色定义
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
# 检查是否在正确的目录
|
|
check_directory() {
|
|
if [[ ! -f "deploy.sh" ]]; then
|
|
log_error "请在部署目录中运行此脚本 (应包含 deploy.sh)"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# 检查环境配置
|
|
check_environment_config() {
|
|
log_info "检查环境配置..."
|
|
|
|
if [[ -f "environments/.env.production" ]]; then
|
|
source environments/.env.production
|
|
|
|
log_info "数据库配置:"
|
|
echo " DB_HOST: $DB_HOST"
|
|
echo " DB_PORT: $DB_PORT"
|
|
echo " DB_NAME: $DB_NAME"
|
|
echo " DB_USER: $DB_USER"
|
|
echo " DB_PASSWORD: [HIDDEN]"
|
|
else
|
|
log_error "未找到生产环境配置文件"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# 检查容器状态
|
|
check_container_status() {
|
|
log_info "检查MySQL容器状态..."
|
|
|
|
if docker ps --filter "name=anxin-mysql-prod" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep anxin-mysql-prod; then
|
|
log_success "✓ MySQL容器正在运行"
|
|
|
|
# 显示端口映射
|
|
local ports=$(docker port anxin-mysql-prod 2>/dev/null || echo "无端口映射")
|
|
log_info "端口映射: $ports"
|
|
else
|
|
log_error "✗ MySQL容器未运行"
|
|
|
|
# 检查是否存在但已停止
|
|
if docker ps -a --filter "name=anxin-mysql-prod" --format "{{.Names}}" | grep -q anxin-mysql-prod; then
|
|
log_warn "MySQL容器存在但已停止"
|
|
docker ps -a --filter "name=anxin-mysql-prod" --format "table {{.Names}}\t{{.Status}}"
|
|
fi
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# 检查网络连接
|
|
check_network_connectivity() {
|
|
log_info "检查网络连接..."
|
|
|
|
if [[ -f "environments/.env.production" ]]; then
|
|
source environments/.env.production
|
|
|
|
# 检查端口是否开放
|
|
log_info "检查端口 $DB_PORT 是否开放..."
|
|
if netstat -tlnp 2>/dev/null | grep ":$DB_PORT " || ss -tlnp 2>/dev/null | grep ":$DB_PORT "; then
|
|
log_success "✓ 端口 $DB_PORT 正在监听"
|
|
else
|
|
log_error "✗ 端口 $DB_PORT 未开放"
|
|
fi
|
|
|
|
# 测试本地连接
|
|
log_info "测试本地连接..."
|
|
if nc -z localhost "$DB_PORT" 2>/dev/null; then
|
|
log_success "✓ 本地连接测试成功"
|
|
else
|
|
log_error "✗ 本地连接测试失败"
|
|
fi
|
|
|
|
# 测试容器内连接
|
|
if docker ps --filter "name=anxin-mysql-prod" --format "{{.Names}}" | grep -q anxin-mysql-prod; then
|
|
log_info "测试容器内连接..."
|
|
if docker exec anxin-mysql-prod mysqladmin ping -h localhost -u root -p"$MYSQL_ROOT_PASSWORD" 2>/dev/null; then
|
|
log_success "✓ 容器内连接测试成功"
|
|
else
|
|
log_error "✗ 容器内连接测试失败"
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 检查防火墙设置
|
|
check_firewall() {
|
|
log_info "检查防火墙设置..."
|
|
|
|
if [[ -f "environments/.env.production" ]]; then
|
|
source environments/.env.production
|
|
|
|
# 检查iptables规则
|
|
if command -v iptables >/dev/null 2>&1; then
|
|
log_info "检查iptables规则..."
|
|
if iptables -L INPUT -n | grep -q "$DB_PORT"; then
|
|
log_info "找到端口 $DB_PORT 的iptables规则"
|
|
iptables -L INPUT -n | grep "$DB_PORT"
|
|
else
|
|
log_warn "未找到端口 $DB_PORT 的iptables规则"
|
|
fi
|
|
fi
|
|
|
|
# 检查firewalld
|
|
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
|
|
log_info "检查firewalld规则..."
|
|
if firewall-cmd --list-ports | grep -q "$DB_PORT"; then
|
|
log_success "✓ 端口 $DB_PORT 已在firewalld中开放"
|
|
else
|
|
log_warn "端口 $DB_PORT 未在firewalld中开放"
|
|
fi
|
|
fi
|
|
|
|
# 检查ufw
|
|
if command -v ufw >/dev/null 2>&1; then
|
|
log_info "检查ufw规则..."
|
|
if ufw status | grep -q "$DB_PORT"; then
|
|
log_success "✓ 端口 $DB_PORT 已在ufw中开放"
|
|
else
|
|
log_warn "端口 $DB_PORT 未在ufw中开放"
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 检查MySQL配置
|
|
check_mysql_config() {
|
|
log_info "检查MySQL配置..."
|
|
|
|
if docker ps --filter "name=anxin-mysql-prod" --format "{{.Names}}" | grep -q anxin-mysql-prod; then
|
|
# 检查bind-address配置
|
|
log_info "检查bind-address配置..."
|
|
if docker exec anxin-mysql-prod mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "SHOW VARIABLES LIKE 'bind_address';" 2>/dev/null; then
|
|
log_success "✓ 获取bind_address配置成功"
|
|
else
|
|
log_error "✗ 无法获取bind_address配置"
|
|
fi
|
|
|
|
# 检查用户权限
|
|
log_info "检查用户权限..."
|
|
if [[ -f "environments/.env.production" ]]; then
|
|
source environments/.env.production
|
|
|
|
if docker exec anxin-mysql-prod mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "SELECT User, Host FROM mysql.user WHERE User='$DB_USER';" 2>/dev/null; then
|
|
log_success "✓ 获取用户权限信息成功"
|
|
else
|
|
log_error "✗ 无法获取用户权限信息"
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 测试外部连接
|
|
test_external_connection() {
|
|
log_info "测试外部连接..."
|
|
|
|
if [[ -f "environments/.env.production" ]]; then
|
|
source environments/.env.production
|
|
|
|
# 获取服务器外部IP
|
|
local external_ip=$(curl -s ifconfig.me 2>/dev/null || curl -s ipinfo.io/ip 2>/dev/null || echo "unknown")
|
|
log_info "服务器外部IP: $external_ip"
|
|
|
|
# 测试从外部连接
|
|
log_info "尝试从外部连接MySQL..."
|
|
if timeout 10 mysql -h "$external_ip" -P "$DB_PORT" -u "$DB_USER" -p"$DB_PASSWORD" -e "SELECT 1;" 2>/dev/null; then
|
|
log_success "✓ 外部连接测试成功"
|
|
else
|
|
log_error "✗ 外部连接测试失败"
|
|
log_info "请检查:"
|
|
echo " 1. 防火墙是否开放端口 $DB_PORT"
|
|
echo " 2. MySQL用户是否允许远程连接"
|
|
echo " 3. 网络安全组是否允许该端口"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 修复常见问题
|
|
fix_common_issues() {
|
|
log_info "修复常见问题..."
|
|
|
|
if [[ -f "environments/.env.production" ]]; then
|
|
source environments/.env.production
|
|
|
|
# 1. 重启MySQL容器
|
|
log_info "重启MySQL容器..."
|
|
./deploy.sh restart mysql -e production
|
|
sleep 10
|
|
|
|
# 2. 检查并修复用户权限
|
|
if docker ps --filter "name=anxin-mysql-prod" --format "{{.Names}}" | grep -q anxin-mysql-prod; then
|
|
log_info "修复用户权限..."
|
|
|
|
# 创建用户并授权(如果不存在)
|
|
docker exec anxin-mysql-prod mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "
|
|
CREATE USER IF NOT EXISTS '$DB_USER'@'%' IDENTIFIED BY '$DB_PASSWORD';
|
|
GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'%';
|
|
FLUSH PRIVILEGES;
|
|
" 2>/dev/null && log_success "✓ 用户权限修复完成" || log_error "✗ 用户权限修复失败"
|
|
fi
|
|
|
|
# 3. 开放防火墙端口(如果需要)
|
|
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
|
|
log_info "开放firewalld端口..."
|
|
firewall-cmd --permanent --add-port="$DB_PORT/tcp" 2>/dev/null && \
|
|
firewall-cmd --reload 2>/dev/null && \
|
|
log_success "✓ firewalld端口开放完成" || log_warn "firewalld端口开放失败"
|
|
fi
|
|
|
|
if command -v ufw >/dev/null 2>&1; then
|
|
log_info "开放ufw端口..."
|
|
ufw allow "$DB_PORT/tcp" 2>/dev/null && \
|
|
log_success "✓ ufw端口开放完成" || log_warn "ufw端口开放失败"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 显示连接信息
|
|
show_connection_info() {
|
|
log_info "MySQL连接信息:"
|
|
echo "========================================"
|
|
|
|
if [[ -f "environments/.env.production" ]]; then
|
|
source environments/.env.production
|
|
|
|
local external_ip=$(curl -s ifconfig.me 2>/dev/null || curl -s ipinfo.io/ip 2>/dev/null || echo "your-server-ip")
|
|
|
|
echo "外部连接信息:"
|
|
echo " 主机: $external_ip"
|
|
echo " 端口: $DB_PORT"
|
|
echo " 数据库: $DB_NAME"
|
|
echo " 用户名: $DB_USER"
|
|
echo " 密码: $DB_PASSWORD"
|
|
echo ""
|
|
echo "连接命令示例:"
|
|
echo " mysql -h $external_ip -P $DB_PORT -u $DB_USER -p$DB_PASSWORD $DB_NAME"
|
|
echo ""
|
|
echo "JDBC连接字符串:"
|
|
echo " jdbc:mysql://$external_ip:$DB_PORT/$DB_NAME?useUnicode=true&characterEncoding=utf8&useSSL=false"
|
|
fi
|
|
|
|
echo "========================================"
|
|
}
|
|
|
|
# 主函数
|
|
main() {
|
|
local action=${1:-"diagnose"}
|
|
|
|
log_info "MySQL连接诊断工具"
|
|
echo "========================================"
|
|
|
|
check_directory
|
|
|
|
case $action in
|
|
"diagnose")
|
|
check_environment_config
|
|
echo ""
|
|
check_container_status
|
|
echo ""
|
|
check_network_connectivity
|
|
echo ""
|
|
check_firewall
|
|
echo ""
|
|
check_mysql_config
|
|
echo ""
|
|
test_external_connection
|
|
echo ""
|
|
show_connection_info
|
|
;;
|
|
"fix")
|
|
fix_common_issues
|
|
echo ""
|
|
main "diagnose"
|
|
;;
|
|
"info")
|
|
show_connection_info
|
|
;;
|
|
*)
|
|
echo "用法: $0 [diagnose|fix|info]"
|
|
echo " diagnose - 诊断连接问题(默认)"
|
|
echo " fix - 修复常见问题"
|
|
echo " info - 显示连接信息"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo "========================================"
|
|
log_success "操作完成!"
|
|
}
|
|
|
|
# 如果脚本被直接执行
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
main "$@"
|
|
fi |