Files
BuYuHouDuan/deploy/server/0524-replace.sh
T

134 lines
3.9 KiB
Bash
Raw Normal View History

#!/bin/bash
# ============================================================
# 0524 平台:按现有约定替换/回滚单个(或多个)服务容器
# 位置:服务器 /mnt/web/0524-replace.sh
#
# 用法:
# bash 0524-replace.sh admin # 用 0524admin:latest 重建 admin
# bash 0524-replace.sh fishgame admin # 一次替换多个
# TAG=dual-20261008 bash 0524-replace.sh admin # 回滚 admin 到旧镜像
#
# 约定(与线上既有部署保持一致):
# - 网络 webapi_backend
# - 端口只绑 127.0.0.1
# - 配置挂载 /mnt/web/config -> /app/Config(全服务共用)
# - 日志挂载 /mnt/web/logs -> /app/logs
# - ASPNETCORE_URLS 按各服务内部端口
# ============================================================
set -u
NET=webapi_backend
CFG=/mnt/web/config
LOGS=/mnt/web/logs
UPLOADS=/mnt/web/uploads
TAG="${TAG:-latest}"
ROLLBACK_TAG="${ROLLBACK_TAG:-dual-20261008}"
ALL="gateway admin user customer chess fishroom fishgame"
# 容器内部监听端口
internal_port() {
case "$1" in
gateway) echo 8001 ;;
admin) echo 5241 ;;
user) echo 5245 ;;
customer) echo 5247 ;;
chess) echo 5242 ;;
fishroom) echo 5244 ;;
fishgame) echo 8001 ;;
esac
}
# 宿主机映射端口(只绑 127.0.0.1)
host_port() {
case "$1" in
gateway) echo 8001 ;;
admin) echo 5241 ;;
user) echo 5245 ;;
customer) echo 5247 ;;
chess) echo 5242 ;;
fishroom) echo 5244 ;;
fishgame) echo 5248 ;;
esac
}
# 额外的 -v/-e 参数
extra_args() {
case "$1" in
gateway) echo "-v $CFG/ocelot.json:/app/ocelot.json -v $UPLOADS:/app/uploads" ;;
admin) echo "-v $UPLOADS:/app/wwwroot/uploads" ;;
customer) echo "-v $UPLOADS:/app/wwwroot/uploads" ;;
*) echo "" ;;
esac
}
# INSTANCE_ID(日志文件名里用于区分实例)
instance_id() {
case "$1" in
gateway) echo "" ;;
fishgame) echo "1" ;;
*) echo "Container_Port_$(host_port "$1")" ;;
esac
}
run_container() {
local svc=$1 tag=$2
local ip hp inst extra
ip=$(internal_port "$svc"); hp=$(host_port "$svc"); inst=$(instance_id "$svc"); extra=$(extra_args "$svc")
docker rm -f "0524$svc" >/dev/null 2>&1
local envar="ASPNETCORE_URLS=http://+:$ip"
[ -n "$inst" ] && envar="$envar -e INSTANCE_ID=$inst"
# shellcheck disable=SC2086
docker run -d --name "0524$svc" --restart always --network "$NET" \
-e $envar $extra \
-p "127.0.0.1:$hp:$ip" \
-v "$CFG:/app/Config" -v "$LOGS:/app/logs" -v "$CFG/nlog.config:/app/nlog.config" \
"0524$svc:$tag" >/dev/null
}
health() {
local svc=$1 hp; hp=$(host_port "$svc")
for _ in $(seq 1 15); do
local c; c=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:$hp/health")
if [ "$svc" = "gateway" ]; then
# 网关的 /health 被 Ocelot 接管,会返回 404;只要端口有 HTTP 响应即视为存活
[ "$c" != "000" ] && return 0
else
[ "$c" = "200" ] && return 0
fi
sleep 2
done
return 1
}
replace_one() {
local svc=$1
echo "=== 替换 $svc (0524$svc:$TAG)==="
run_container "$svc" "$TAG"
if health "$svc"; then
echo " ✔ $svc 健康检查通过"
else
echo " ✘ $svc 未通过,输出日志并回滚到 $ROLLBACK_TAG"
docker logs --tail 40 "0524$svc" 2>&1 | tail -20
run_container "$svc" "$ROLLBACK_TAG"
health "$svc" && echo " ↩ 已回滚,$svc 恢复正常" || echo " !! 回滚后仍不健康,请人工介入"
return 1
fi
}
if [ $# -eq 0 ]; then
echo "用法: bash 0524-replace.sh <服务...> (可选服务: $ALL)"
echo " TAG=dual-20261008 bash 0524-replace.sh <服务...> # 回滚"
exit 1
fi
for svc in "$@"; do
case " $ALL " in
*" $svc "*) replace_one "$svc" ;;
*) echo "未知服务: $svc(可选: $ALL)" ;;
esac
done
echo ""
echo "=== 当前业务容器 ==="
docker ps --format '{{.Names}} => {{.Image}} => {{.Status}}' | grep 0524