Files
Cloud-Tour-to-Libo/scripts/prepare_mysql_production_storage.sh
T

110 lines
4.5 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd -P)"
STORAGE_MOUNT="${MYSQL_STORAGE_MOUNT:-}"
DATA_DIR="${MYSQL_DATA_DIR:-}"
BACKUP_ROOT="${DATA_BACKUP_ROOT:-}"
STORAGE_ID="${MYSQL_STORAGE_ID:-}"
MYSQL_UID="${MYSQL_CONTAINER_UID:-999}"
MYSQL_GID="${MYSQL_CONTAINER_GID:-999}"
ADOPT_EXISTING="${ADOPT_EXISTING_MYSQL_DATA:-false}"
fail() {
echo "错误:$*" >&2
exit 2
}
if [[ "${EUID}" -ne 0 ]]; then
fail "请使用 sudo -E 执行,以便创建并设置持久化目录权限"
fi
for command_name in find findmnt install mountpoint realpath; do
command -v "${command_name}" >/dev/null 2>&1 || fail "缺少命令:${command_name}"
done
[[ "${STORAGE_MOUNT}" == /* ]] || fail "MYSQL_STORAGE_MOUNT 必须是独立数据盘的绝对挂载点"
[[ "${DATA_DIR}" == /* ]] || fail "MYSQL_DATA_DIR 必须是项目外绝对路径"
[[ "${BACKUP_ROOT}" == /* ]] || fail "DATA_BACKUP_ROOT 必须是项目外绝对路径"
[[ "${STORAGE_ID}" =~ ^[A-Za-z0-9._-]{16,128}$ ]] || fail "MYSQL_STORAGE_ID 必须为16–128位安全标识"
[[ "${MYSQL_UID}" =~ ^[0-9]+$ && "${MYSQL_GID}" =~ ^[0-9]+$ ]] || fail "MySQL容器UID/GID必须是数字"
STORAGE_MOUNT="$(realpath -e -- "${STORAGE_MOUNT}")"
mountpoint -q -- "${STORAGE_MOUNT}" || fail "${STORAGE_MOUNT} 当前不是独立挂载点,拒绝写入系统盘"
filesystem_type="$(findmnt -n -o FSTYPE --target "${STORAGE_MOUNT}")"
mount_options="$(findmnt -n -o OPTIONS --target "${STORAGE_MOUNT}")"
case "${filesystem_type}" in
overlay|tmpfs|ramfs|nfs|nfs4|cifs|fuse.*)
fail "MySQL运行数据不能使用 ${filesystem_type} 文件系统;请使用本地持久化块存储"
;;
esac
case ",${mount_options}," in
*,rw,*) ;;
*) fail "数据盘 ${STORAGE_MOUNT} 不是可写挂载" ;;
esac
DATA_DIR="$(realpath -m -- "${DATA_DIR}")"
BACKUP_ROOT="$(realpath -m -- "${BACKUP_ROOT}")"
case "${DATA_DIR}/" in
"${STORAGE_MOUNT}/"*) ;;
*) fail "MYSQL_DATA_DIR 必须位于已确认的数据盘 ${STORAGE_MOUNT} 下" ;;
esac
[[ "${DATA_DIR}" != "${STORAGE_MOUNT}" ]] || fail "MySQL数据目录不能直接使用磁盘挂载根目录"
case "${DATA_DIR}/" in
"${PROJECT_DIR}/"*) fail "MySQL数据目录不能位于代码仓库内" ;;
esac
case "${BACKUP_ROOT}/" in
"${PROJECT_DIR}/"*) fail "备份目录不能位于代码仓库内" ;;
esac
if [[ "${DATA_DIR}" == "${BACKUP_ROOT}" || "${BACKUP_ROOT}/" == "${DATA_DIR}/"* || "${DATA_DIR}/" == "${BACKUP_ROOT}/"* ]]; then
fail "MySQL运行数据目录和备份目录不能相互包含"
fi
install -d -m 0750 -o "${MYSQL_UID}" -g "${MYSQL_GID}" -- "${DATA_DIR}"
backup_uid="${SUDO_UID:-0}"
backup_gid="${SUDO_GID:-0}"
install -d -m 0700 -o "${backup_uid}" -g "${backup_gid}" -- "${BACKUP_ROOT}"
marker="${STORAGE_MOUNT}/.nianxx-mysql-storage-id"
[[ ! -L "${marker}" ]] || fail "存储标识文件不能是符号链接"
if [[ -f "${marker}" ]]; then
actual_id="$(<"${marker}")"
[[ "${actual_id}" == "${STORAGE_ID}" ]] || fail "数据盘标识不一致,拒绝覆盖或切换数据库"
else
existing_entry="$(find "${DATA_DIR}" -mindepth 1 -maxdepth 1 -print -quit)"
if [[ -n "${existing_entry}" ]]; then
[[ "${ADOPT_EXISTING}" == "true" ]] || fail "目标目录已有数据但缺少标识;确认备份后设置 ADOPT_EXISTING_MYSQL_DATA=true 再执行"
[[ -f "${DATA_DIR}/auto.cnf" && -d "${DATA_DIR}/mysql" ]] || fail "现有目录不是完整的MySQL数据目录"
fi
temporary_marker="$(mktemp "${STORAGE_MOUNT}/.storage-id.XXXXXX")"
printf '%s\n' "${STORAGE_ID}" > "${temporary_marker}"
chown root:root "${temporary_marker}"
chmod 0444 "${temporary_marker}"
mv -n -- "${temporary_marker}" "${marker}"
fi
actual_id="$(<"${marker}")"
[[ "${actual_id}" == "${STORAGE_ID}" ]] || fail "数据盘标识写入后校验失败"
existing_entry="$(find "${DATA_DIR}" -mindepth 1 -maxdepth 1 -print -quit)"
if [[ -n "${existing_entry}" && ( ! -f "${DATA_DIR}/auto.cnf" || ! -d "${DATA_DIR}/mysql" ) ]]; then
fail "MySQL数据目录非空但结构不完整,拒绝启动"
fi
chown "${MYSQL_UID}:${MYSQL_GID}" "${DATA_DIR}"
chmod 0750 "${DATA_DIR}"
echo "MySQL生产存储已准备完成:"
echo " 数据盘挂载点:${STORAGE_MOUNT}"
echo " 文件系统:${filesystem_type} (${mount_options})"
echo " MySQL数据目录:${DATA_DIR}"
echo " 加密备份目录:${BACKUP_ROOT}"
echo " 存储标识:${STORAGE_ID}"
echo "请将以上三个路径/标识写入服务器 .env,然后再启动生产 Compose。"