139 lines
3.5 KiB
Bash
139 lines
3.5 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
用法:
|
|
./scripts/deploy/production-api-deploy.sh --source-dir build/<version> [--version <version>] [--release-root /opt/genarrative/releases] [--current-link /opt/genarrative/current] [--service genarrative-api.service] [--health-url http://127.0.0.1:8082/healthz]
|
|
|
|
说明:
|
|
进入维护模式,校验并发布 api-server 单文件,更新 current 链接,重启 systemd 服务并执行 healthz 检查。
|
|
失败时保留维护模式。
|
|
EOF
|
|
}
|
|
|
|
require_argument() {
|
|
local value="$1"
|
|
local label="$2"
|
|
|
|
if [[ -z "${value}" ]]; then
|
|
echo "[production-api-deploy] 缺少参数: ${label}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
SOURCE_DIR=""
|
|
VERSION=""
|
|
RELEASE_ROOT="/opt/genarrative/releases"
|
|
CURRENT_LINK="/opt/genarrative/current"
|
|
SERVICE_NAME="genarrative-api.service"
|
|
HEALTH_URL="http://127.0.0.1:8082/healthz"
|
|
DEPLOY_COMPLETED=0
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--source-dir)
|
|
SOURCE_DIR="${2:?缺少 --source-dir 的值}"
|
|
shift 2
|
|
;;
|
|
--version)
|
|
VERSION="${2:?缺少 --version 的值}"
|
|
shift 2
|
|
;;
|
|
--release-root)
|
|
RELEASE_ROOT="${2:?缺少 --release-root 的值}"
|
|
shift 2
|
|
;;
|
|
--current-link)
|
|
CURRENT_LINK="${2:?缺少 --current-link 的值}"
|
|
shift 2
|
|
;;
|
|
--service)
|
|
SERVICE_NAME="${2:?缺少 --service 的值}"
|
|
shift 2
|
|
;;
|
|
--health-url)
|
|
HEALTH_URL="${2:?缺少 --health-url 的值}"
|
|
shift 2
|
|
;;
|
|
*)
|
|
echo "[production-api-deploy] 未知参数: $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
require_argument "${SOURCE_DIR}" "--source-dir"
|
|
|
|
if [[ ! -d "${SOURCE_DIR}" ]]; then
|
|
echo "[production-api-deploy] 发布目录不存在: ${SOURCE_DIR}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
SOURCE_DIR="$(cd "${SOURCE_DIR}" && pwd)"
|
|
VERSION="${VERSION:-$(basename "${SOURCE_DIR}")}"
|
|
|
|
if [[ ! "${VERSION}" =~ ^[0-9A-Za-z._-]+$ ]]; then
|
|
echo "[production-api-deploy] --version 只能包含数字、字母、点、下划线和短横线: ${VERSION}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "${SOURCE_DIR}/api-server" || ! -f "${SOURCE_DIR}/api-server.sha256" ]]; then
|
|
echo "[production-api-deploy] 缺少 api-server 或 api-server.sha256: ${SOURCE_DIR}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
on_exit() {
|
|
local exit_code=$?
|
|
if [[ "${exit_code}" -ne 0 && "${DEPLOY_COMPLETED}" -ne 1 ]]; then
|
|
echo "[production-api-deploy] 部署失败,保持维护模式。" >&2
|
|
fi
|
|
exit "${exit_code}"
|
|
}
|
|
|
|
trap on_exit EXIT
|
|
|
|
"${SCRIPT_DIR}/maintenance-on.sh" "api deploy ${VERSION}"
|
|
|
|
echo "[production-api-deploy] 校验 api-server"
|
|
(
|
|
cd "${SOURCE_DIR}"
|
|
sha256sum -c api-server.sha256
|
|
)
|
|
|
|
RELEASE_DIR="${RELEASE_ROOT}/${VERSION}"
|
|
mkdir -p "${RELEASE_DIR}"
|
|
cp "${SOURCE_DIR}/api-server" "${RELEASE_DIR}/api-server"
|
|
chmod +x "${RELEASE_DIR}/api-server"
|
|
|
|
if [[ -f "${SOURCE_DIR}/release-manifest.json" ]]; then
|
|
cp "${SOURCE_DIR}/release-manifest.json" "${RELEASE_DIR}/release-manifest.api-server.json"
|
|
fi
|
|
|
|
mkdir -p "$(dirname "${CURRENT_LINK}")"
|
|
ln -sfn "${RELEASE_DIR}" "${CURRENT_LINK}"
|
|
|
|
echo "[production-api-deploy] 重启服务: ${SERVICE_NAME}"
|
|
systemctl restart "${SERVICE_NAME}"
|
|
|
|
echo "[production-api-deploy] 等待 healthz: ${HEALTH_URL}"
|
|
for _ in {1..30}; do
|
|
if curl -fsS "${HEALTH_URL}" >/dev/null; then
|
|
"${SCRIPT_DIR}/maintenance-off.sh"
|
|
DEPLOY_COMPLETED=1
|
|
echo "[production-api-deploy] 完成: ${RELEASE_DIR}/api-server"
|
|
exit 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "[production-api-deploy] healthz 检查超时: ${HEALTH_URL}" >&2
|
|
exit 1
|