提交 0396ae7f authored 作者: PGY's avatar PGY

feat(自动化部署脚本):重构成都太行 Redis 与 Java 服务监控脚本,提升系统可靠性与可维护性

- Redis 监控脚本 (monitor_redis_service.sh):
  - 增强日志记录与错误处理机制。
  - 移除重启失败时的高风险数据清理逻辑。
  - 引入 PID 锁机制,防止脚本并发重叠执行。
  - 采用动态轮询替代固定等待,用于检测服务恢复状态。
  - 优化密码处理逻辑,避免硬编码。
  - 新增日志轮转功能,以控制日志文件大小。

- Java 服务监控脚本 (monitor_ujava_service.sh):
  - 重构服务检查逻辑,简化进程检测流程。
  - 引入动态轮询机制,用于检测服务恢复状态。
  - 使用 flock 命令实现并发控制。
  - 整合服务定义,降低后续维护难度。
  - 完善错误处理与日志记录,提升故障诊断能力。
  - 优化容器与服务的重启逻辑。
上级 f3f26dc1
......@@ -4,7 +4,7 @@
CONTAINER_NAME="umysql"
DB_USER="root"
HOST_BACKUP_DIR="/opt/mysql" # 宿主机备份目录
LOG_FILE="/var/log/backup_mysql_databases.log"
LOG_FILE="/var/log/scripts/backup_mysql_databases.log"
RETENTION_DAYS=30
TARGET_DBS=("devops" "devops_voice" "huazhao2" "nacos_mysql" "offline" "ubains" "wifi" "voice" "ubains_nacos_config" "ubains_sso")
......
#!/bin/bash
# clear_deleted_files.sh - 定时清理被进程占用的已删除文件
LOG_FILE="/var/log/cleanup_deleted_files.log"
LOG_FILE="/var/log/scripts/cleanup_deleted_files.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] 开始检查被占用的已删除文件..." >> "$LOG_FILE"
......
#!/bin/bash
# 宿主机上的脚本:检查 MySQL,如果容器未运行则重启 umysql 容器
LOG_FILE="/var/log/monitor_mysql_service.log"
#===============================================================================
# 脚本名称:monitor_mysql_service.sh
# 功能描述:监测 MySQL 容器(umysql)是否正常,不正常则自动拉起容器
# 版本:V2.0
# 修改日期:2026-08-13
# 变更历史:
# V1.0: 初始版本
# V2.0: 优化
# - 修复注释与代码不一致(原注释"等待20秒"实际sleep 60)
# - 固定等待改为动态轮询,避免启动慢时误判超时、启动快时白等
# - 增加 PID 并发锁,防止 cron 重叠执行
# - 精简冗余代码
#
# 监测逻辑:
# 1. umysql 容器是否在运行
# 2. mysqladmin ping 是否成功
# 3. 执行 SELECT 1 确认可执行 SQL
# 4. 容器异常则自动拉起,并动态轮询验证恢复
#
# 定时任务示例:
# */5 * * * * /data/services/scripts/monitor_mysql_service.sh
#===============================================================================
# ==================== 配置区(修改配置请在此处调整) ====================
CONTAINER_NAME="umysql" # MySQL 容器名称
DB_USER="root" # 数据库用户
LOG_FILE="/var/log/scripts/monitor_mysql_service.log"
PID_FILE="/var/log/scripts/.mysql_monitor.pid"
CHECK_TIMEOUT=10 # docker exec 命令超时(秒)
POLL_INTERVAL=10 # 重启后轮询检查间隔(秒)
POLL_TIMEOUT_MINUTES=5 # 重启后轮询最长等待时间(分钟)
# ========================================================================
# ==================== 日志函数 ====================
log() {
local message
message="$(date '+%Y-%m-%d %H:%M:%S') - $1"
echo "$message"
# 同时写入日志文件
echo "$message" >> "$LOG_FILE"
}
# PID 并发锁:防止 cron 周期内脚本未执行完又被触发
acquire_lock() {
if [ -f "$PID_FILE" ]; then
local old_pid
old_pid=$(cat "$PID_FILE" 2>/dev/null)
if [ -n "$old_pid" ] && kill -0 "$old_pid" 2>/dev/null; then
log "警告: 上一次脚本执行仍在运行 (PID: $old_pid),本次跳过"
exit 1
fi
rm -f "$PID_FILE"
fi
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"; exit' EXIT INT TERM HUP
}
# 获取 MySQL 密码:从容器环境变量读取(避免明文硬编码)
get_mysql_password() {
docker exec umysql printenv MYSQL_ROOT_PASSWORD 2>/dev/null
timeout "$CHECK_TIMEOUT" docker exec "$CONTAINER_NAME" printenv MYSQL_ROOT_PASSWORD 2>/dev/null
}
# 检查 MySQL 是否正常(返回 0 表示正常)
check_mysql() {
if docker ps --format '{{.Names}}' | grep -Fxq "umysql"; then
# 1. 容器是否运行
if ! docker ps --format '{{.Names}}' | grep -Fxq "$CONTAINER_NAME"; then
log "检查失败[1/3]: 容器 $CONTAINER_NAME 未运行"
return 1
fi
# 2. 获取密码
local mysql_password
mysql_password=$(get_mysql_password)
if [ -z "$mysql_password" ]; then
log "检查失败[2/3]: 无法从容器获取 MySQL 密码"
return 1
fi
# 尝试连接数据库
if docker exec umysql mysqladmin ping -h localhost -u root -p"$mysql_password" 2>/dev/null; then
# 尝试执行一个简单的SQL查询来确认数据库功能正常
if docker exec umysql mysql -u root -p"$mysql_password" -e "SELECT 1;" >/dev/null 2>&1; then
log "MySQL 服务连接正常,可以执行SQL查询"
# 3. ping 检查 + SELECT 1 验证可执行 SQL
if timeout "$CHECK_TIMEOUT" docker exec "$CONTAINER_NAME" mysqladmin ping -h localhost -u "$DB_USER" -p"$mysql_password" >/dev/null 2>&1 &&
timeout "$CHECK_TIMEOUT" docker exec "$CONTAINER_NAME" mysql -u "$DB_USER" -p"$mysql_password" -e "SELECT 1;" >/dev/null 2>&1; then
log "MySQL 服务连接正常,可以执行 SQL 查询"
return 0
else
log "警告: MySQL 服务可以ping通,但无法执行SQL查询"
return 1
fi
else
log "警告: 无法连接到 MySQL 服务"
return 1
fi
else
log "信息: umysql 容器未运行"
log "检查失败[3/3]: MySQL 连接或 SQL 执行失败"
return 1
fi
}
restart_mysql_container() {
log "MySQL 未运行。正在尝试重启容器 'umysql'..."
# 检查容器是否存在(不仅仅是运行状态)
if docker ps -a --format '{{.Names}}' | grep -Fxq "umysql"; then
# 停止可能挂起的容器
docker stop umysql >/dev/null 2>&1 || true
# 容器存在但未运行,尝试启动
if docker start umysql; then
log "成功: MySQL 容器已成功启动。"
# 等待几秒让服务启动
log "信息: 等待 60 秒让 MySQL 服务完全启动..."
for i in {1..60}; do
echo -n "." >> "$LOG_FILE"
sleep 1
done
echo "" >> "$LOG_FILE"
# 动态轮询等待 MySQL 恢复(拉起容器后调用)
wait_for_mysql() {
local timeout_minutes="${1:-$POLL_TIMEOUT_MINUTES}"
local max_attempts=$((timeout_minutes * 60 / POLL_INTERVAL))
local attempt=0
# 检查启动后容器是否仍在运行
if docker ps --format '{{.Names}}' | grep -Fxq "umysql"; then
log "信息: MySQL 容器现在正在运行。"
while [ $attempt -lt $max_attempts ]; do
attempt=$((attempt + 1))
if check_mysql >/dev/null 2>&1; then
log "MySQL 服务已恢复(耗时约 $((attempt * POLL_INTERVAL / 60))$((attempt * POLL_INTERVAL % 60)) 秒)"
return 0
fi
sleep "$POLL_INTERVAL"
done
# 等待一段时间后检查服务状态
log "信息: 等待 20 秒后检查服务状态..."
sleep 60
log "MySQL 服务在 ${timeout_minutes} 分钟内未恢复,已超时"
return 1
}
local mysql_password
mysql_password=$(get_mysql_password)
# 拉起 MySQL 容器(容器存在但未运行则启动,服务异常则重启)
restart_mysql_container() {
log "MySQL 异常,正在拉起容器 '$CONTAINER_NAME'..."
if [ -z "$mysql_password" ]; then
# 容器是否存在(含已停止的)
if ! docker ps -a --format '{{.Names}}' | grep -Fxq "$CONTAINER_NAME"; then
log "错误: 容器 '$CONTAINER_NAME' 不存在,请手动检查容器状态"
return 1
fi
if docker exec umysql mysqladmin ping -h localhost -u root -p"$mysql_password" >/dev/null 2>&1; then
if docker exec umysql mysql -u root -p"$mysql_password" -e "SELECT 1;" >/dev/null 2>&1; then
log "信息: MySQL 服务状态正常。"
return 0
else
log "错误: MySQL 服务运行中,但无法执行SQL查询。"
return 1
fi
else
log "错误: MySQL 服务状态检查失败。"
return 1
fi
else
log "错误: MySQL 容器在启动后不久就停止了。"
return 1
# 容器在运行但服务异常,先停止再启动(容器未运行则直接启动)
if docker ps --format '{{.Names}}' | grep -Fxq "$CONTAINER_NAME"; then
log "信息: 容器已在运行但服务异常,尝试重启容器..."
docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
sleep 2
fi
if docker start "$CONTAINER_NAME"; then
log "容器 '$CONTAINER_NAME' 已启动,动态轮询等待 MySQL 恢复..."
if wait_for_mysql; then
log "MySQL 容器拉起成功,服务状态正常"
return 0
else
log "错误: 无法启动 MySQL 容器。"
log "错误: 容器已启动但 MySQL 服务未恢复,请手动检查: docker logs $CONTAINER_NAME"
return 1
fi
else
log "错误: 容器 'umysql' 不存在!"
log "信息: 您可能需要手动重新创建 MySQL 容器。"
log "错误: 无法启动容器 '$CONTAINER_NAME',请手动检查: docker logs $CONTAINER_NAME"
return 1
fi
}
# 主逻辑
log "开始检查 MySQL 服务状态..."
if check_mysql; then
log "MySQL 正在运行且状态正常。"
else
log "MySQL 无响应或容器未运行。"
restart_mysql_container
# ==================== 主逻辑 ====================
main() {
# 获取锁
acquire_lock
log "==========================================="
log "MySQL 服务健康检查开始"
log "==========================================="
# 检查重启后是否正常工作
if check_mysql; then
log "MySQL 已成功重启,现在状态正常。"
log "MySQL 容器运行正常,无需处理"
else
log "错误: 重启尝试后 MySQL 仍无响应。"
log "信息: 请使用以下命令检查容器日志: docker logs umysql"
log "MySQL 异常,自动拉起容器..."
if restart_mysql_container; then
log "MySQL 已成功恢复"
else
log "错误: 自动拉起失败,请手动排查: docker ps -a && docker logs $CONTAINER_NAME"
fi
fi
fi
\ No newline at end of file
log "==========================================="
log "MySQL 服务健康检查完成"
log "==========================================="
}
# 执行主逻辑
main
\ No newline at end of file
#!/bin/bash
# 宿主机上的脚本:检查 Nacos,失败则重启 ujava2 容器中的服务
LOG_FILE="/var/log/monitor_nacos_service.log"
# ==================== 配置区(修改配置请在此处调整) ====================
CONTAINER_NAME="ujava2" # 需要监控的容器名称(Nacos 运行在此容器内)
NACOS_HEALTH_URL="http://127.0.0.1:8848/nacos/v1/console/health/readiness" # Nacos 健康检查接口
START_SCRIPT="/var/www/java/start.sh" # 容器内服务启动脚本路径
CHECK_RETRIES=3 # 服务不可用的重试次数
CHECK_RETRY_INTERVAL=5 # 每次重试间隔(秒)
CHECK_TIMEOUT=5 # curl 连接超时(秒)
POLL_INTERVAL=10 # 重启后轮询检查间隔(秒)
# 注意:start.sh 需等待 120s 才通知 Nacos 启动,Nacos 收到指令后再等 300s 才执行启动,
# 即重启后最快也要 7 分钟才开始真正启动,所以等待时限必须 >= 10 分钟,否则会误报超时。
POLL_TIMEOUT_MINUTES=12 # 重启后轮询最长等待时间(分钟)
CONTAINER_START_WAIT=30 # 容器启动后初始等待时间(秒)
LOG_FILE="/var/log/scripts/monitor_nacos_service.log"
# ========================================================================
# */15 * * * * /data/services/scripts/monitor_nacos_service.sh
# ==================== 日志函数 ====================
log() {
local message
message="$(date '+%Y-%m-%d %H:%M:%S') - $1"
......@@ -11,37 +28,89 @@ log() {
echo "$message" >> "$LOG_FILE"
}
# ==================== 健康检查 ====================
check_nacos() {
# 确保 127.0.0.1:8848 可访问(Nacos 端口已映射到宿主机)
if curl -sf http://127.0.0.1:8848/nacos/v1/console/health/readiness >/dev/null; then
local i
# 重试多次,避免网络抖动导致误判
for i in $(seq 1 $CHECK_RETRIES); do
if curl -sf --max-time "$CHECK_TIMEOUT" "$NACOS_HEALTH_URL" >/dev/null; then
return 0
else
return 1
fi
if [ $i -lt $CHECK_RETRIES ]; then
log "Nacos 检查失败(第${i}次),${CHECK_RETRY_INTERVAL} 秒后重试..."
sleep "$CHECK_RETRY_INTERVAL"
fi
done
log "Nacos 检查失败,已连续重试 ${CHECK_RETRIES} 次,确认服务不可用"
return 1
}
# ==================== 重启容器内服务 ====================
restart_in_container() {
log "Nacos NOT READY. Restarting services in container 'ujava2'..."
log "Nacos 不可用,正在重启容器 '$CONTAINER_NAME' 内的服务..."
# 检查容器是否正在运行(精确匹配名称)
if ! docker ps --format '{{.Names}}' | grep -Fxq "ujava2"; then
log "ERROR: Container 'ujava2' is not running!"
if ! docker ps --format '{{.Names}}' | grep -Fxq "$CONTAINER_NAME"; then
# 容器未运行,尝试启动容器
if docker ps -a --format '{{.Names}}' | grep -Fxq "$CONTAINER_NAME"; then
log "容器 $CONTAINER_NAME 未运行,尝试启动容器..."
if docker start "$CONTAINER_NAME"; then
log "容器 $CONTAINER_NAME 已成功启动,等待 ${CONTAINER_START_WAIT} 秒让服务初始化..."
sleep "$CONTAINER_START_WAIT"
else
log "错误: 无法启动容器 $CONTAINER_NAME,请检查容器状态"
return 1
fi
# 在容器内执行 start.sh
if docker exec ujava2 /var/www/java/start.sh; then
log "SUCCESS: Services restarted in ujava2."
else
log "ERROR: Failed to run start.sh in ujava2."
log "错误: 容器 '$CONTAINER_NAME' 不存在,请手动检查容器状态"
return 1
fi
fi
# 容器运行中,执行启动脚本重启服务
if ! docker exec "$CONTAINER_NAME" "$START_SCRIPT"; then
log "错误: 在 $CONTAINER_NAME 容器内执行 $START_SCRIPT 失败"
return 1
fi
log "$START_SCRIPT 执行成功,开始动态轮询等待 Nacos 启动..."
return 0
}
# ==================== 动态等待服务启动 ====================
wait_for_nacos() {
local timeout_minutes="${1:-$POLL_TIMEOUT_MINUTES}" # 最长等待分钟数
local max_attempts=$((timeout_minutes * 60 / POLL_INTERVAL))
local attempt=0
while [ $attempt -lt $max_attempts ]; do
attempt=$((attempt + 1))
if curl -sf --max-time "$CHECK_TIMEOUT" "$NACOS_HEALTH_URL" >/dev/null 2>&1; then
log "Nacos 服务已启动(耗时约 $((attempt * POLL_INTERVAL / 60))$((attempt * POLL_INTERVAL % 60)) 秒)"
return 0
fi
sleep "$POLL_INTERVAL"
done
log "Nacos 服务在 ${timeout_minutes} 分钟内未启动,已超时"
return 1
}
# 主逻辑
# ==================== 主逻辑 ====================
log "开始检查 Nacos 服务状态..."
if check_nacos; then
log "Nacos is healthy."
log "Nacos 服务状态正常"
else
log "Nacos is not responding."
restart_in_container
log "Nacos 服务不可用,正在尝试恢复..."
if restart_in_container; then
# 动态轮询等待 Nacos 启动
if wait_for_nacos; then
log "Nacos 服务已成功恢复,当前状态正常"
else
log "错误: 重启后 Nacos 服务在 ${POLL_TIMEOUT_MINUTES} 分钟内仍未恢复,请手动检查容器日志: docker logs $CONTAINER_NAME"
fi
else
log "错误: 服务恢复失败,请手动检查容器状态: docker ps -a"
fi
fi
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论