提交 7ec3bad3 authored 作者: 陈泽健's avatar 陈泽健

refactor(auto_middleware_install): 优化MySQL安装脚本的等待和导入逻辑

- 实现主动探测MySQL服务状态替代固定延时等待
- 添加清理僵尸连接功能防止死锁问题
- 重构SQL文件拷贝逻辑支持批量处理
- 实现带死锁重试机制的SQL导入函数
- 优化Nacos配置IP更新流程

feat(auto_crontab_settings): 新增定时任务脚本配置需求文档

- 定义支持多个定时任务的配置方案
- 设计通用任务添加函数接口
- 规范健康检查脚本配置流程
- 明确脚本存在性验证和权限修复机制
上级 9cad6151
# 定时任务脚本优化需求
## 代码路径
- 需调用代码路径:[自动化部署脚本/x86架构/新统一平台/auto_crontab_settings.sh]
- 主脚本:[自动化部署脚本/x86架构/新统一平台/new_auto.sh]
## 功能需求
### 功能目标
**目标:** 定时任务脚本需要能够支持配置crontab多个定时任务。且`auto_crontab_settings.sh`只需要设置脚本定时即可。无其他复杂逻辑。
### 需求描述
#### 调用逻辑
- 当前是只配置了一个定时任务,需要修改为可配置多个定时任务。
- 不需要通过主脚本传参控制定时任务配置,主脚本只需要调用这个`auto_crontab_settings.sh`脚本,脚本内部实现多个定时任务配置。
- 新增定时任务:
- 定时周期:每天凌晨01:00执行
- 定时任务执行脚本:`/data/services/scripts/check_server_health.sh`
- 需要先判断该路径是否存在脚本,若不存在则不进行配置,打印相关日志记录。
## 疑问与解答记录
### 疑问1:现有定时任务是否保留?
- **问题:** 当前已配置 `*/3 * * * * ujava2-startup.sh` 定时任务,需求说"需要修改为可配置多个",但没有明确现有任务是否保留。
- **解答:** 现有定时任务保留,在现有基础上新增。
### 疑问2:新任务的 crontab 日志输出路径?
- **问题:** 现有任务日志输出到 `/var/log/ujava2-cron.log`,新增的 `check_server_health.sh` 日志应输出到哪里?
- **解答:** 新任务的脚本自身会管理日志,crontab 不需要做日志重定向。
### 疑问3:新任务是否需要执行权限自动修复?
- **问题:** 现有逻辑对 `ujava2-startup.sh` 做了两步检查:不存在则跳过 + 无执行权限则自动 `chmod +x`。需求只提到"判断路径是否存在",是否也需要执行权限检查和自动修复?
- **解答:** 需要补充执行权限检查和自动修复逻辑。
### 疑问4:`/data/services/scripts/check_server_health.sh` 由谁创建?
- **问题:** 需求要求判断脚本是否存在、不存在则跳过。这个脚本是由其他部署流程生成的,还是需要本脚本负责部署?
- **解答:** 脚本由用户单独提供,不需要本脚本来部署。如果不存在则跳过并打印日志。
### 疑问5:重构方式确认?
- **问题:** 计划将现有硬编码的 `add_crontab_job()` 重构为通用任务添加函数(接受脚本路径、cron 表达式、日志路径作为参数),然后在脚本内部分别调用两次来配置两个任务。
- **解答:** 改为通用函数,后期还会有其他定时任务脚本增加,需要预留扩展能力。
## 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
\ No newline at end of file
......@@ -215,194 +215,134 @@ function mysql_x86() {
return 1
fi
sleep 180
log "INFO" "✅ 容器启动成功,等待 MySQL 服务就绪..."
# ------------------- 初始化数据库:创建用户、数据库、授权、导入数据 -------------------
log "INFO" "🔧 初始化数据库:创建用户、数据库、授权..."
# 先拷贝 nacos_mysql.sql 到容器内
log "INFO" "📁 拷贝 /data/temp/nacos_mysql.sql 到容器 '$container_name' 内..."
if $SUDO docker cp "/data/temp/nacos_mysql.sql" "$container_name:/tmp/nacos_mysql.sql"; then
log "INFO" "✅ SQL 文件已成功拷贝到容器内"
else
log "ERROR" "⛔ 无法拷贝 nacos_mysql.sql 到容器,请检查文件路径或容器状态"
return 1
fi
# 先拷贝 devops_voice.sql 到容器内
log "INFO" "📁 拷贝 /data/temp/devops_voice.sql 到容器 '$container_name' 内..."
if $SUDO docker cp "/data/temp/devops_voice.sql" "$container_name:/tmp/devops_voice.sql"; then
log "INFO" "✅ SQL 文件已成功拷贝到容器内"
else
log "ERROR" "⛔ 无法拷贝 devops_voice.sql 到容器,请检查文件路径或容器状态"
return 1
fi
# 先拷贝 huazhao2.sql 到容器内
log "INFO" "📁 拷贝 /data/temp/huazhao2.sql 到容器 '$container_name' 内..."
if $SUDO docker cp "/data/temp/huazhao2.sql" "$container_name:/tmp/huazhao2.sql"; then
log "INFO" "✅ SQL 文件已成功拷贝到容器内"
else
log "ERROR" "⛔ 无法拷贝 huazhao2.sql 到容器,请检查文件路径或容器状态"
# ------------------- 2. 【核心修改】主动探测 MySQL 服务状态 -------------------
log "INFO" "⏳ 正在等待 MySQL 服务就绪 (主动探测中)..."
# 定义一个内部函数用于等待
wait_for_mysql() {
local max_retries=60 # 最大尝试次数 (60 * 2秒 = 120秒)
local count=0
# 循环检测
while [ $count -lt $max_retries ]; do
# 使用 mysqladmin ping 检测
# 注意:这里使用 127.0.0.1 而不是 localhost,避免使用 socket 文件可能带来的路径问题
if $SUDO docker exec "$container_name" mysqladmin ping -h"127.0.0.1" -u"root" -p"$mysql_root_password" --silent 2>/dev/null; then
log "INFO" "✅ MySQL 服务已就绪!"
return 0
fi
# 如果失败,等待 2 秒后重试
sleep 2
count=$((count + 1))
# 每 10 次打印一次进度,避免看起来像卡死
if [ $((count % 10)) -eq 0 ]; then
log "INFO" " 等待中... (已尝试 ${count}/${max_retries} 次)"
fi
done
log "ERROR" "⛔ 等待 MySQL 启动超时,请检查容器日志"
$SUDO docker logs "$container_name" | tail -20
return 1
fi
}
# 先拷贝 offline.sql 到容器内
log "INFO" "📁 拷贝 /data/temp/offline.sql 到容器 '$container_name' 内..."
if $SUDO docker cp "/data/temp/offline.sql" "$container_name:/tmp/offline.sql"; then
log "INFO" "✅ SQL 文件已成功拷贝到容器内"
else
log "ERROR" "⛔ 无法拷贝 offline.sql 到容器,请检查文件路径或容器状态"
return 1
fi
# 调用等待函数,如果返回失败则退出整个函数
wait_for_mysql || return 1
# 先拷贝 ubains.sql 到容器内
log "INFO" "📁 拷贝 /data/temp/ubains.sql 到容器 '$container_name' 内..."
if $SUDO docker cp "/data/temp/ubains.sql" "$container_name:/tmp/ubains.sql"; then
log "INFO" "✅ SQL 文件已成功拷贝到容器内"
else
log "ERROR" "⛔ 无法拷贝 ubains.sql 到容器,请检查文件路径或容器状态"
return 1
fi
log "INFO" "✅ 容器启动成功,等待 MySQL 服务就绪..."
# 先拷贝 devops.sql 到容器内
log "INFO" "📁 拷贝 /data/temp/devops.sql 到容器 '$container_name' 内..."
if $SUDO docker cp "/data/temp/devops.sql" "$container_name:/tmp/devops.sql"; then
log "INFO" "✅ SQL 文件已成功拷贝到容器内"
# ------------------- 3. 【关键优化】清理潜在的死锁源 -------------------
log "INFO" "🧹 正在清理潜在的僵尸连接..."
# 获取所有非系统用户的连接 ID 并杀掉,防止旧事务占用锁
# 使用 awk 过滤掉 'Id' 标题行和 'system user' 等系统进程
local kill_sql=$($SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -e "SHOW FULL PROCESSLIST;" 2>/dev/null | \
awk 'NR>1 && $4 != "system user" && $4 != "event_scheduler" && $11 !~ /NULL/ {print "KILL " $1 ";"}')
if [[ -n "$kill_sql" ]]; then
# 将所有 KILL 命令拼接执行
echo "$kill_sql" | $SUDO docker exec -i "$container_name" mysql -uroot -p"$mysql_root_password" 2>/dev/null
log "INFO" "✅ 已清理残留连接"
else
log "ERROR" "⛔ 无法拷贝 devops.sql 到容器,请检查文件路径或容器状态"
return 1
log "INFO" "✅ 无残留连接需要清理"
fi
# ------------------- 初始化数据库:创建用户、数据库、授权、导入数据 -------------------
log "INFO" "🔧 初始化数据库:创建用户、数据库、授权..."
# 定义要执行的 SQL 命令序列(注意顺序)
local init_sql=(
"CREATE USER IF NOT EXISTS 'nacos'@'%' IDENTIFIED BY 'nacos2025';"
"CREATE USER IF NOT EXISTS 'mysqluser'@'%' IDENTIFIED BY 'dNrprU&2S';"
"CREATE DATABASE IF NOT EXISTS nacos_mysql CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
"CREATE DATABASE IF NOT EXISTS devops CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
"CREATE DATABASE IF NOT EXISTS devops_voice CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
"CREATE DATABASE IF NOT EXISTS offline CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
"CREATE DATABASE IF NOT EXISTS huazhao2 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
"GRANT ALL PRIVILEGES ON nacos_mysql.* TO 'nacos'@'%';"
"GRANT ALL PRIVILEGES ON devops.* TO 'mysqluser'@'%';"
"FLUSH PRIVILEGES;"
)
# ------------------- 4. 拷贝 SQL 文件 -------------------
log "INFO" "📁 正在拷贝 SQL 文件到容器..."
local sql_files=("nacos_mysql.sql" "devops_voice.sql" "huazhao2.sql" "offline.sql" "ubains.sql" "devops.sql")
# 执行前半部分 SQL
for sql in "${init_sql[@]}"; do
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -e "$sql"
if [[ $? -ne 0 ]]; then
log "ERROR" "⛔ 执行SQL语句失败: $sql"
log "INFO" "📄 输出容器最近日志..."
$SUDO docker logs "$container_name" | tail -30
for file in "${sql_files[@]}"; do
if $SUDO docker cp "/data/temp/$file" "$container_name:/tmp/$file"; then
log "INFO" "✅ 拷贝 $file 成功"
else
log "ERROR" "⛔ 拷贝 $file 失败"
return 1
fi
done
# 执行 source 导入 nacos_mysql.sql 到 nacos_mysql 数据库
log "INFO" "📥 正在导入 nacos_mysql.sql 到数据库 nacos_mysql..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D nacos_mysql -e "source /tmp/nacos_mysql.sql"
if [[ $? -eq 0 ]]; then
log "INFO" "✅ nacos_mysql.sql 数据导入成功"
# 在导入数据后执行 IP 替换
log "INFO" "🔄 正在更新配置中的 IP 地址..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D nacos_mysql -e \
"UPDATE config_info SET content = REPLACE(content, '192.168.9.84', '"$server_ip"')
WHERE data_id IN ('auth-sso-auth-dev.yml','auth-sso-gateway-dev.yml','auth-sso-system-dev.yml');"
log "INFO" "🔄 正在保存配置..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D nacos_mysql -e \
"FLUSH PRIVILEGES;"
# ------------------- 6. 【修正版】带死锁重试的导入函数 -------------------
import_sql() {
local db=$1
local file=$2
local max_retries=3
local retry_count=0
local success=false
while [ $retry_count -lt $max_retries ]; do
log "INFO" "📥 正在导入 $file$db... (尝试 $((retry_count + 1))/$max_retries)"
# 【关键修改】使用 cat 管道符,让容器自己读取文件并传给 mysql
# 这样既避免了宿主机的路径问题,又比 source 命令更稳定
local output
output=$($SUDO docker exec "$container_name" sh -c "cat /tmp/$file | mysql -uroot -p'$mysql_root_password' $db" 2>&1)
local exit_code=$?
if [ $exit_code -eq 0 ]; then
log "INFO" "✅ $file 导入成功"
success=true
break
elif echo "$output" | grep -q "Deadlock found"; then
retry_count=$((retry_count + 1))
if [ $retry_count -lt $max_retries ]; then
log "WARN" "⚠️ 检测到死锁 (Error 1213),等待 5 秒后重试..."
sleep 5
else
log "ERROR" "⛔ $file 导入失败:重试 $max_retries 次后仍遇到死锁"
log "ERROR" "📄 错误详情: $output"
fi
else
# 非死锁错误,直接失败
log "ERROR" "⛔ $file 导入失败 (非死锁错误)"
log "ERROR" "📄 错误详情: $output"
return 1
fi
done
if [[ $? -eq 0 ]]; then
log "INFO" "✅ 配置保存成功"
else
log "ERROR" "⛔ 配置保存失败"
if [ "$success" = false ]; then
return 1
fi
else
log "ERROR" "⛔ 数据导入失败,请检查 nacos_mysql.sql 文件内容或权限"
log "INFO" "📄 输出容器日志以排查问题..."
$SUDO docker logs "$container_name" | tail -50
return 1
fi
sleep 60
# 执行 source 导入 devops_voice.sql 到 devops_voice 数据库
log "INFO" "📥 正在导入 devops_voice.sql 到数据库 devops_voice..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D devops_voice -e "source /tmp/devops_voice.sql"
if [[ $? -eq 0 ]]; then
log "INFO" "✅ devops_voice.sql 数据导入成功"
else
log "ERROR" "⛔ 数据导入失败,请检查 devops_voice.sql 文件内容或权限"
log "INFO" "📄 输出容器日志以排查问题..."
$SUDO docker logs "$container_name" | tail -50
return 1
fi
sleep 60
# 执行 source 导入 huazhao2.sql 到 huazhao2 数据库
log "INFO" "📥 正在导入 huazhao2.sql 到数据库 huazhao2..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D huazhao2 -e "source /tmp/huazhao2.sql"
if [[ $? -eq 0 ]]; then
log "INFO" "✅ huazhao2.sql 数据导入成功"
else
log "ERROR" "⛔ 数据导入失败,请检查 huazhao2.sql 文件内容或权限"
log "INFO" "📄 输出容器日志以排查问题..."
$SUDO docker logs "$container_name" | tail -50
return 1
fi
sleep 60
# 执行 source 导入 offline.sql 到 offline 数据库
log "INFO" "📥 正在导入 offline.sql 到数据库 offline..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D offline -e "source /tmp/offline.sql"
if [[ $? -eq 0 ]]; then
log "INFO" "✅ offline.sql 数据导入成功"
else
log "ERROR" "⛔ 数据导入失败,请检查 offline.sql 文件内容或权限"
log "INFO" "📄 输出容器日志以排查问题..."
$SUDO docker logs "$container_name" | tail -50
return 1
fi
sleep 60
# 执行 source 导入 ubains.sql 到 ubains 数据库
log "INFO" "📥 正在导入 ubains.sql 到数据库 ubains..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D ubains -e "source /tmp/ubains.sql"
if [[ $? -eq 0 ]]; then
log "INFO" "✅ ubains.sql 数据导入成功"
else
log "ERROR" "⛔ 数据导入失败,请检查 ubains.sql 文件内容或权限"
log "INFO" "📄 输出容器日志以排查问题..."
$SUDO docker logs "$container_name" | tail -50
return 1
fi
sleep 180
# 执行 source 导入 devops.sql 到 devops 数据库
log "INFO" "📥 正在导入 devops.sql 到数据库 devops..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D devops -e "source /tmp/devops.sql"
if [[ $? -eq 0 ]]; then
log "INFO" "✅ devops.sql 数据导入成功"
else
log "ERROR" "⛔ 数据导入失败,请检查 devops.sql 文件内容或权限"
log "INFO" "📄 输出容器日志以排查问题..."
$SUDO docker logs "$container_name" | tail -50
return 1
fi
sleep 180
return 0
}
# ------------------- 7. 执行导入 -------------------
# 导入 Nacos 并更新 IP
import_sql "nacos_mysql" "nacos_mysql.sql" || return 1
log "INFO" "🔄 正在更新 Nacos 配置 IP..."
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D nacos_mysql -e \
"UPDATE config_info SET content = REPLACE(content, '192.168.9.84', '"$server_ip"')
WHERE data_id IN ('auth-sso-auth-dev.yml','auth-sso-gateway-dev.yml','auth-sso-system-dev.yml');"
$SUDO docker exec "$container_name" mysql -uroot -p"$mysql_root_password" -D nacos_mysql -e "FLUSH PRIVILEGES;"
# 导入其他数据库
import_sql "devops_voice" "devops_voice.sql" || return 1
import_sql "huazhao2" "huazhao2.sql" || return 1
import_sql "offline" "offline.sql" || return 1
import_sql "ubains" "ubains.sql" || return 1
import_sql "devops" "devops.sql" || return 1
# ------------------- 提升用户权限 -------------------
for user in "root" "mysqluser"; do
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论