fix(update): recover stopped active services
这个提交包含在:
父节点
4d595edcae
当前提交
465910caa0
@ -543,9 +543,12 @@ _COMPOSE="docker compose --env-file ${ROOT_DIR}/.env \
|
||||
|
||||
# 使用 up -d 而非 restart:restart 只重启容器进程,不会切换到新拉取的镜像;
|
||||
# up -d 会检测镜像变更并重建容器,是应用新版本的正确方式。
|
||||
# 必须依据当前 profile 是否启用服务,而不能依据服务此刻是否正在运行。升级中断、
|
||||
# 宿主重启或旧容器启动失败时,后者会永久跳过本应恢复的核心服务。
|
||||
_active_services="$($_COMPOSE config --services 2>/dev/null || true)"
|
||||
for _svc in tenant-service im-service file-service update-service push-service tenant-web nginx; do
|
||||
# 仅重启已激活的服务(跳过未运行的可选服务)
|
||||
if $_COMPOSE ps --services --filter status=running 2>/dev/null | grep -q "^${_svc}$"; then
|
||||
# 仅启动当前 profile 已激活的服务;服务即使当前停止也必须被恢复。
|
||||
if printf '%s\n' "$_active_services" | grep -q "^${_svc}$"; then
|
||||
info "应用新镜像并重启 ${_svc} ..."
|
||||
$_COMPOSE up -d --no-deps --remove-orphans "$_svc"
|
||||
ok "${_svc} 已更新"
|
||||
|
||||
@ -63,6 +63,31 @@ BASE_URL="${BASE_URL%/}"
|
||||
MYSQL_PASSWORD="${MYSQL_PASSWORD:-}"
|
||||
REDIS_PASSWORD="${REDIS_PASSWORD:-}"
|
||||
|
||||
# 所有容器定位均限定在当前 Compose 项目。宿主机可能同时运行其他 MySQL、
|
||||
# Redis 或 Xuqm 环境,按名称模糊匹配会误检、误执行数据库命令。
|
||||
compose() {
|
||||
docker compose --env-file "$ROOT_DIR/.env" \
|
||||
-f "$ROOT_DIR/docker-compose.yml" \
|
||||
-f "$ROOT_DIR/docker-compose.infra.yml" "$@"
|
||||
}
|
||||
|
||||
container_id() {
|
||||
compose ps -q "$1" 2>/dev/null | head -1 || true
|
||||
}
|
||||
|
||||
container_name() {
|
||||
local id
|
||||
id="$(container_id "$1")"
|
||||
[ -n "$id" ] && docker inspect --format '{{.Name}}' "$id" 2>/dev/null | sed 's|^/||'
|
||||
}
|
||||
|
||||
profile_enabled() {
|
||||
case ",${COMPOSE_PROFILES:-base}," in
|
||||
*,"$1",*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 颜色和工具函数
|
||||
# ---------------------------------------------------------------------------
|
||||
@ -146,23 +171,27 @@ printf " 验证时间: %s\n" "$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
# ---------------------------------------------------------------------------
|
||||
section "1. 容器状态"
|
||||
|
||||
REQUIRED_CONTAINERS="tenant-service nginx tenant-web"
|
||||
REQUIRED_CONTAINERS="tenant-service file-service nginx tenant-web"
|
||||
for CTR_SUFFIX in $REQUIRED_CONTAINERS; do
|
||||
CTR_NAME=$(docker ps --filter "name=$CTR_SUFFIX" --filter "status=running" --format '{{.Names}}' 2>/dev/null | head -1)
|
||||
CTR_NAME="$(container_name "$CTR_SUFFIX")"
|
||||
if [ -n "$CTR_NAME" ]; then
|
||||
pass "容器运行中: $CTR_NAME"
|
||||
else
|
||||
fail "容器未运行: *-${CTR_SUFFIX}-*"
|
||||
fail "当前部署容器未运行: $CTR_SUFFIX"
|
||||
fi
|
||||
done
|
||||
|
||||
OPTIONAL_CONTAINERS="file-service im-service push-service update-service bugcollect-service symbolicator mysql redis"
|
||||
for CTR_SUFFIX in $OPTIONAL_CONTAINERS; do
|
||||
CTR_NAME=$(docker ps --filter "name=$CTR_SUFFIX" --filter "status=running" --format '{{.Names}}' 2>/dev/null | head -1)
|
||||
OPTIONAL_SERVICES="im:im-service push:push-service update:update-service bugcollect:bugcollect-service bugcollect:symbolicator infra-mysql:mysql infra-redis:redis"
|
||||
for PROFILE_SERVICE in $OPTIONAL_SERVICES; do
|
||||
PROFILE="${PROFILE_SERVICE%%:*}"
|
||||
CTR_SUFFIX="${PROFILE_SERVICE#*:}"
|
||||
CTR_NAME="$(container_name "$CTR_SUFFIX")"
|
||||
if [ -n "$CTR_NAME" ]; then
|
||||
pass "容器运行中: $CTR_NAME"
|
||||
elif profile_enabled "$PROFILE"; then
|
||||
fail "已启用 profile 的容器未运行: $CTR_SUFFIX"
|
||||
else
|
||||
warn "容器未运行(可选): *-${CTR_SUFFIX}-*"
|
||||
warn "容器未启用(profile: $PROFILE): $CTR_SUFFIX"
|
||||
fi
|
||||
done
|
||||
|
||||
@ -172,19 +201,20 @@ done
|
||||
section "2. 数据库和缓存"
|
||||
|
||||
# MySQL
|
||||
MYSQL_CTR=$(docker ps --filter "name=mysql" --filter "status=running" --format '{{.Names}}' 2>/dev/null | head -1)
|
||||
MYSQL_CTR="$(container_id mysql)"
|
||||
if [ -n "$MYSQL_CTR" ]; then
|
||||
if docker exec "$MYSQL_CTR" mysqladmin -u root -p"${MYSQL_ROOT_PASSWORD:-}" ping --silent 2>/dev/null; then
|
||||
pass "MySQL 响应 PONG"
|
||||
if docker exec "$MYSQL_CTR" mysql -u root -p"${MYSQL_ROOT_PASSWORD:-}" \
|
||||
--connect-timeout=5 -N -e 'SELECT 1' 2>/dev/null | grep -q '^1$'; then
|
||||
pass "MySQL 查询响应正常"
|
||||
else
|
||||
fail "MySQL ping 失败"
|
||||
fail "当前部署 MySQL 查询失败"
|
||||
fi
|
||||
else
|
||||
warn "MySQL 容器未运行(external 模式跳过此项)"
|
||||
fi
|
||||
|
||||
# Redis
|
||||
REDIS_CTR=$(docker ps --filter "name=redis" --filter "status=running" --format '{{.Names}}' 2>/dev/null | head -1)
|
||||
REDIS_CTR="$(container_id redis)"
|
||||
if [ -n "$REDIS_CTR" ]; then
|
||||
PING=$(docker exec "$REDIS_CTR" redis-cli -a "${REDIS_PASSWORD:-}" --no-auth-warning PING 2>/dev/null | tr -d '\r')
|
||||
if [ "$PING" = "PONG" ]; then
|
||||
@ -291,7 +321,7 @@ NICK=""
|
||||
|
||||
if [ -n "$CAPTCHA_KEY" ]; then
|
||||
# 从 Redis 读取验证码
|
||||
REDIS_CTR=$(docker ps --filter "name=redis" --filter "status=running" --format '{{.Names}}' 2>/dev/null | head -1)
|
||||
REDIS_CTR="$(container_id redis)"
|
||||
if [ -n "$REDIS_CTR" ]; then
|
||||
CAPTCHA_CODE=$(docker exec "$REDIS_CTR" redis-cli -a "${REDIS_PASSWORD:-}" --no-auth-warning \
|
||||
GET "captcha:${CAPTCHA_KEY}" 2>/dev/null | tr -d '\r')
|
||||
@ -365,7 +395,7 @@ except:
|
||||
fi
|
||||
|
||||
# 从数据库查询已有 App
|
||||
MYSQL_CTR=$(docker ps --filter "name=mysql" --filter "status=running" --format '{{.Names}}' 2>/dev/null | head -1)
|
||||
MYSQL_CTR="$(container_id mysql)"
|
||||
APP_KEYS=""
|
||||
if [ -n "$MYSQL_CTR" ]; then
|
||||
APP_KEYS=$(docker exec "$MYSQL_CTR" sh -c \
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户