简化生产一键部署脚本
This commit is contained in:
@@ -56,23 +56,6 @@ require_command() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
require_port_command() {
|
|
||||||
if command -v ss >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v lsof >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v netstat >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_error "缺少端口检测命令: ss、lsof 或 netstat"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
find_release_archive() {
|
find_release_archive() {
|
||||||
archives=$(find "$SCRIPT_DIR" -maxdepth 1 -type f -name '*.zip' ! -name 'dist.zip')
|
archives=$(find "$SCRIPT_DIR" -maxdepth 1 -type f -name '*.zip' ! -name 'dist.zip')
|
||||||
count=$(printf '%s\n' "$archives" | sed '/^$/d' | wc -l | tr -d ' ')
|
count=$(printf '%s\n' "$archives" | sed '/^$/d' | wc -l | tr -d ' ')
|
||||||
@@ -134,106 +117,23 @@ deploy_backend_jar() {
|
|||||||
mv "$source_jar" "$BACKEND_JAR_TARGET"
|
mv "$source_jar" "$BACKEND_JAR_TARGET"
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy_frontend_archive() {
|
deploy_frontend_dist() {
|
||||||
source_dist_zip="$1"
|
source_dist_zip="$1"
|
||||||
rm -f "$FRONTEND_DIST_ARCHIVE"
|
rm -f "$FRONTEND_DIST_ARCHIVE"
|
||||||
|
rm -rf "$FRONTEND_DIST_DIR"
|
||||||
mv "$source_dist_zip" "$FRONTEND_DIST_ARCHIVE"
|
mv "$source_dist_zip" "$FRONTEND_DIST_ARCHIVE"
|
||||||
}
|
unzip -oq "$FRONTEND_DIST_ARCHIVE" -d "$FRONTEND_DIR"
|
||||||
|
|
||||||
resolve_frontend_source_dir() {
|
if [ ! -d "$FRONTEND_DIST_DIR" ]; then
|
||||||
unzip_dir="$1"
|
log_error "dist.zip 解压后未找到 $FRONTEND_DIST_DIR"
|
||||||
|
|
||||||
if [ -f "$unzip_dir/index.html" ]; then
|
|
||||||
printf '%s\n' "$unzip_dir"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$unzip_dir/dist/index.html" ]; then
|
|
||||||
printf '%s\n' "$unzip_dir/dist"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
candidate=$(find "$unzip_dir" -type f -name 'index.html' | head -n 1)
|
|
||||||
if [ -z "${candidate:-}" ]; then
|
|
||||||
log_error "dist.zip 解压后未找到 index.html"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dirname "$candidate"
|
|
||||||
}
|
|
||||||
|
|
||||||
deploy_frontend_dist() {
|
|
||||||
dist_unpack_dir="$WORK_DIR/frontend"
|
|
||||||
|
|
||||||
mkdir -p "$dist_unpack_dir"
|
|
||||||
unzip -oq "$FRONTEND_DIST_ARCHIVE" -d "$dist_unpack_dir"
|
|
||||||
|
|
||||||
rm -rf "$FRONTEND_DIST_DIR"
|
|
||||||
mkdir -p "$FRONTEND_DIST_DIR"
|
|
||||||
cp -a "$(resolve_frontend_source_dir "$dist_unpack_dir")"/. "$FRONTEND_DIST_DIR"/
|
|
||||||
}
|
|
||||||
|
|
||||||
is_port_listening() {
|
|
||||||
port="$1"
|
|
||||||
|
|
||||||
if command -v ss >/dev/null 2>&1; then
|
|
||||||
ss -lnt 2>/dev/null | grep -q ":$port "
|
|
||||||
return $?
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v lsof >/dev/null 2>&1; then
|
|
||||||
lsof -nP -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1
|
|
||||||
return $?
|
|
||||||
fi
|
|
||||||
|
|
||||||
netstat -an 2>/dev/null | grep -E "[\\.:]$port[[:space:]].*LISTEN" >/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
is_managed_backend_pid() {
|
|
||||||
pid="$1"
|
|
||||||
|
|
||||||
if [ -z "${pid:-}" ] || ! kill -0 "$pid" 2>/dev/null; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
process_line=$(ps -ef | awk -v target_pid="$pid" '$2 == target_pid {print $0}')
|
|
||||||
if [ -z "${process_line:-}" ]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$process_line" in
|
|
||||||
*"$BACKEND_MARKER"*"$BACKEND_JAR_TARGET"*|*"$BACKEND_JAR_TARGET"*"$BACKEND_MARKER"*)
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
collect_backend_pids() {
|
collect_backend_pids() {
|
||||||
pids=""
|
ps -ef | awk -v marker="$BACKEND_MARKER" -v jar="$BACKEND_JAR_TARGET" '
|
||||||
|
index($0, marker) > 0 && index($0, jar) > 0 {print $2}
|
||||||
if [ -f "$BACKEND_PID_FILE" ]; then
|
' | xargs 2>/dev/null || true
|
||||||
file_pid=$(cat "$BACKEND_PID_FILE" 2>/dev/null || true)
|
|
||||||
if [ -n "${file_pid:-}" ] && is_managed_backend_pid "$file_pid"; then
|
|
||||||
pids="$pids $file_pid"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
marker_pids=$(
|
|
||||||
ps -ef | awk -v marker="$BACKEND_MARKER" -v jar="$BACKEND_JAR_TARGET" '
|
|
||||||
index($0, marker) > 0 && index($0, jar) > 0 {print $2}
|
|
||||||
'
|
|
||||||
)
|
|
||||||
if [ -n "${marker_pids:-}" ]; then
|
|
||||||
for pid in $marker_pids; do
|
|
||||||
if is_managed_backend_pid "$pid"; then
|
|
||||||
pids="$pids $pid"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '%s\n' "$(echo "$pids" | xargs 2>/dev/null || true)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_backend() {
|
stop_backend() {
|
||||||
@@ -310,19 +210,7 @@ start_backend() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wait_seconds=0
|
log_info "后端已启动,PID: $backend_pid"
|
||||||
while [ "$wait_seconds" -lt 30 ]; do
|
|
||||||
if is_port_listening "$BACKEND_PORT"; then
|
|
||||||
log_info "后端已监听端口: $BACKEND_PORT"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
sleep 1
|
|
||||||
wait_seconds=$((wait_seconds + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
log_error "后端未在预期时间内监听端口 $BACKEND_PORT"
|
|
||||||
exit 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
@@ -337,7 +225,6 @@ main() {
|
|||||||
require_command find
|
require_command find
|
||||||
require_command ps
|
require_command ps
|
||||||
require_command nohup
|
require_command nohup
|
||||||
require_port_command
|
|
||||||
|
|
||||||
release_archive=$(find_release_archive)
|
release_archive=$(find_release_archive)
|
||||||
WORK_DIR=$(mktemp -d "${TMPDIR:-/tmp}/deploy_from_package.XXXXXX")
|
WORK_DIR=$(mktemp -d "${TMPDIR:-/tmp}/deploy_from_package.XXXXXX")
|
||||||
@@ -352,8 +239,7 @@ main() {
|
|||||||
backup_frontend_dist
|
backup_frontend_dist
|
||||||
stop_backend
|
stop_backend
|
||||||
deploy_backend_jar "$backend_jar_source"
|
deploy_backend_jar "$backend_jar_source"
|
||||||
deploy_frontend_archive "$frontend_dist_source"
|
deploy_frontend_dist "$frontend_dist_source"
|
||||||
deploy_frontend_dist
|
|
||||||
start_backend
|
start_backend
|
||||||
|
|
||||||
log_info "部署完成"
|
log_info "部署完成"
|
||||||
|
|||||||
@@ -44,17 +44,7 @@ if [ -z "$port" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
python3 -m http.server "$port" >/dev/null 2>&1 &
|
while :; do
|
||||||
server_pid=$!
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
kill "$server_pid" 2>/dev/null || true
|
|
||||||
wait "$server_pid" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
trap cleanup EXIT INT TERM
|
|
||||||
|
|
||||||
while kill -0 "$server_pid" 2>/dev/null; do
|
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
EOF
|
EOF
|
||||||
@@ -151,10 +141,6 @@ test_deploy_success() {
|
|||||||
backend_pid=$(cat "$release_dir/backend/backend.pid")
|
backend_pid=$(cat "$release_dir/backend/backend.pid")
|
||||||
kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running"
|
kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running"
|
||||||
|
|
||||||
if ! lsof -nP -iTCP:"$backend_port" -sTCP:LISTEN >/dev/null 2>&1; then
|
|
||||||
fail "expected fake backend to listen on $backend_port"
|
|
||||||
fi
|
|
||||||
|
|
||||||
trap - EXIT INT TERM
|
trap - EXIT INT TERM
|
||||||
cleanup_release_dir "$release_dir"
|
cleanup_release_dir "$release_dir"
|
||||||
}
|
}
|
||||||
@@ -182,28 +168,6 @@ test_multiple_release_zip_should_fail() {
|
|||||||
cleanup_release_dir "$release_dir"
|
cleanup_release_dir "$release_dir"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_netstat_fallback_should_work() {
|
|
||||||
release_dir=$(mktemp -d)
|
|
||||||
backend_port=$(find_free_port)
|
|
||||||
trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM
|
|
||||||
|
|
||||||
prepare_release_dir "$release_dir" "$backend_port"
|
|
||||||
mkdir -p "$release_dir/fake-port-bin"
|
|
||||||
ln -sf /usr/sbin/netstat "$release_dir/fake-port-bin/netstat"
|
|
||||||
|
|
||||||
(
|
|
||||||
cd "$release_dir"
|
|
||||||
PATH="$release_dir/fake-port-bin:/usr/bin:/bin" ./deploy_from_package.sh
|
|
||||||
)
|
|
||||||
|
|
||||||
assert_file_exists "$release_dir/frontend/dist/index.html"
|
|
||||||
backend_pid=$(cat "$release_dir/backend/backend.pid")
|
|
||||||
kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running with netstat fallback"
|
|
||||||
|
|
||||||
trap - EXIT INT TERM
|
|
||||||
cleanup_release_dir "$release_dir"
|
|
||||||
}
|
|
||||||
|
|
||||||
test_should_use_ps_ef_for_process_detection() {
|
test_should_use_ps_ef_for_process_detection() {
|
||||||
if rg -n 'pgrep' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
if rg -n 'pgrep' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
||||||
fail "expected deploy_from_package.sh not to depend on pgrep"
|
fail "expected deploy_from_package.sh not to depend on pgrep"
|
||||||
@@ -212,6 +176,10 @@ test_should_use_ps_ef_for_process_detection() {
|
|||||||
if ! rg -n 'ps -ef' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
if ! rg -n 'ps -ef' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
||||||
fail "expected deploy_from_package.sh to use ps -ef for process detection"
|
fail "expected deploy_from_package.sh to use ps -ef for process detection"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if rg -n '\b(ss|lsof|netstat|resolve_frontend_source_dir|is_port_listening)\b' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
||||||
|
fail "expected deploy_from_package.sh to remove port detection and unzip compatibility helpers"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
@@ -219,7 +187,6 @@ main() {
|
|||||||
test_should_use_ps_ef_for_process_detection
|
test_should_use_ps_ef_for_process_detection
|
||||||
test_deploy_success
|
test_deploy_success
|
||||||
test_multiple_release_zip_should_fail
|
test_multiple_release_zip_should_fail
|
||||||
test_netstat_fallback_should_work
|
|
||||||
printf 'PASS: deploy_from_package tests\n'
|
printf 'PASS: deploy_from_package tests\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# 生产一键部署脚本简化实施记录
|
||||||
|
|
||||||
|
## 修改内容
|
||||||
|
- 简化 `bin/prod/deploy_from_package.sh`
|
||||||
|
- 删除端口检测逻辑,不再依赖 `ss`、`lsof` 或 `netstat`
|
||||||
|
- 删除前端解压兼容逻辑,不再探测多种 `dist.zip` 目录结构
|
||||||
|
- 保留并简化进程识别逻辑,直接使用 `ps -ef`
|
||||||
|
- 简化 `bin/prod/deploy_from_package_test.sh`
|
||||||
|
- 删除端口监听断言和端口检测回退场景
|
||||||
|
- 新增脚本文本断言,确认已移除端口检测和解压兼容 helper
|
||||||
|
|
||||||
|
## 当前脚本边界
|
||||||
|
- 仍然保留以下核心能力:
|
||||||
|
- 脚本同目录唯一发布 zip 校验
|
||||||
|
- 发布包内唯一 `jar` 和唯一 `dist.zip` 校验
|
||||||
|
- 旧版后端 `jar` 时间戳备份
|
||||||
|
- 旧版 `frontend/dist` 时间戳备份
|
||||||
|
- 使用 `ps -ef` 停止旧后端进程
|
||||||
|
- 替换新 `jar`
|
||||||
|
- 将 `dist.zip` 直接解压到 `frontend/`
|
||||||
|
- 启动新的 Java 进程并写入 PID 文件
|
||||||
|
|
||||||
|
## 删除的复杂逻辑
|
||||||
|
- 不再等待端口监听成功
|
||||||
|
- 不再兼容 `ss`、`lsof`、`netstat` 三种端口检测方式
|
||||||
|
- 不再兼容 `dist.zip` 根目录、`dist/index.html` 和自动 `find index.html` 多种结构
|
||||||
|
- 当前前端解压只接受一种约定:
|
||||||
|
- `dist.zip` 解压到 `frontend/` 后必须得到 `frontend/dist/`
|
||||||
|
|
||||||
|
## 验证结果
|
||||||
|
- 已执行 `sh -n bin/prod/deploy_from_package.sh`
|
||||||
|
- 已执行 `sh bin/prod/deploy_from_package_test.sh`
|
||||||
|
- 自测确认:
|
||||||
|
- 脚本使用 `ps -ef`
|
||||||
|
- 脚本中已移除端口检测 helper
|
||||||
|
- 脚本中已移除前端解压兼容 helper
|
||||||
|
- 正常部署链路仍然通过
|
||||||
|
- 多个发布 zip 失败场景仍然通过
|
||||||
Reference in New Issue
Block a user