243 lines
12 KiB
Bash
Executable File
243 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# status.sh — 查看所有服务运行状态
|
||
#
|
||
# 显示内容:
|
||
# - Docker 容器状态(Redis/Kafka/Etcd)
|
||
# - 远程服务配置摘要(MongoDB/S3)
|
||
# - 后端服务进程状态(PID + 监听端口)
|
||
# =============================================================================
|
||
set -euo pipefail
|
||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh"
|
||
if [[ -f "$ENV_FILE" ]]; then
|
||
set -a
|
||
# shellcheck source=/dev/null
|
||
source "$ENV_FILE"
|
||
set +a
|
||
fi
|
||
DEPLOY_TEST_IP="${DEPLOY_TEST_IP:-127.0.0.1}"
|
||
normalize_pc_proxy_env
|
||
|
||
header "服务运行状态"
|
||
|
||
# ── Docker 基础设施 ───────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ Docker 基础设施 ]${NC}"
|
||
print_container_status "Redis" "dev-redis" "${REDIS_PORT:-6379}"
|
||
print_container_status "Kafka" "dev-kafka" "${KAFKA_PORT:-9092}"
|
||
printf " ${CYAN}◉${NC} %-10s Kafka 外网 bootstrap(EXTERNAL)%s:%s TCP PLAINTEXT\n" "" "${DEPLOY_TEST_IP:-?}" "${KAFKA_EXTERNAL_PORT:-9094}"
|
||
print_container_status "Etcd" "dev-etcd" "${ETCD_PORT:-2379}"
|
||
print_container_status "MinIO" "dev-minio" "${MINIO_API_PORT:-9000}"
|
||
print_container_status "LiveKit" "dev-livekit" "7880"
|
||
printf " ${CYAN}◉${NC} %-10s 公网 %s:50000-51000/udp (WebRTC)\n" "" "${LIVEKIT_NODE_IP:-?}"
|
||
|
||
# ── Etcd RPC 注册 ─────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ Etcd RPC 注册 ]${NC}"
|
||
ETCD_ENDPOINT="127.0.0.1:${ETCD_PORT:-2379}"
|
||
if ! command -v etcdctl &>/dev/null; then
|
||
printf " ${YELLOW}○${NC} %-18s %s\n" "etcdctl" "未安装,请执行: sudo ./deploy-test/00-init-tools.sh etcdctl"
|
||
else
|
||
if ETCD_KEYS=$(ETCDCTL_API=3 etcdctl --endpoints="$ETCD_ENDPOINT" get --prefix "" --keys-only 2>&1); then
|
||
if [[ -z "$ETCD_KEYS" ]]; then
|
||
printf " ${YELLOW}○${NC} %-18s %s\n" "registry" "Etcd 可访问,但当前无注册 key"
|
||
else
|
||
OPENIM_STANDALONE_RPC_SERVICES=(
|
||
auth-rpc-service
|
||
user-rpc-service
|
||
friend-rpc-service
|
||
group-rpc-service
|
||
msg-rpc-service
|
||
conversation-rpc-service
|
||
third-rpc-service
|
||
push-rpc-service
|
||
messagegateway-rpc-service
|
||
)
|
||
INDEPENDENT_RPC_SERVICES=(
|
||
chat-rpc-service
|
||
admin-rpc-service
|
||
bot-rpc-service
|
||
)
|
||
|
||
echo -e " ${CYAN}OpenIM standalone 内部 RPC(单进程内调用,不要求 Etcd 注册):${NC}"
|
||
for svc in "${OPENIM_STANDALONE_RPC_SERVICES[@]}"; do
|
||
count=$(printf '%s\n' "$ETCD_KEYS" | grep -c "$svc" || true)
|
||
if [[ "$count" -gt 0 ]]; then
|
||
printf " ${GREEN}●${NC} %-28s %s key(s)\n" "$svc" "$count"
|
||
else
|
||
printf " ${CYAN}◉${NC} %-28s %s\n" "$svc" "standalone 进程内"
|
||
fi
|
||
done
|
||
|
||
echo -e " ${CYAN}独立进程 RPC(应注册到 Etcd):${NC}"
|
||
found_required_rpc=0
|
||
missing_required_rpc=0
|
||
for svc in "${INDEPENDENT_RPC_SERVICES[@]}"; do
|
||
count=$(printf '%s\n' "$ETCD_KEYS" | grep -c "$svc" || true)
|
||
if [[ "$count" -gt 0 ]]; then
|
||
found_required_rpc=1
|
||
printf " ${GREEN}●${NC} %-28s %s key(s)\n" "$svc" "$count"
|
||
else
|
||
missing_required_rpc=1
|
||
printf " ${YELLOW}○${NC} %-28s %s\n" "$svc" "未注册"
|
||
fi
|
||
done
|
||
|
||
echo -e " ${CYAN}原始注册 key(过滤 rpc/service/openim/chat/admin 等关键词,最多 80 行):${NC}"
|
||
filtered_keys=$(printf '%s\n' "$ETCD_KEYS" | grep -Ei 'rpc|service|openim|chat|admin|auth|user|friend|group|msg|conversation|third|push|gateway|bot' | head -80 || true)
|
||
if [[ -n "$filtered_keys" ]]; then
|
||
printf '%s\n' "$filtered_keys" | sed 's/^/ /'
|
||
else
|
||
echo " (未匹配到 RPC 相关 key)"
|
||
fi
|
||
|
||
if [[ "$found_required_rpc" -eq 0 ]]; then
|
||
warn " 未发现独立进程 RPC 注册;chat-api/admin-api 调 RPC 时可能出现 name resolver error: produced zero addresses"
|
||
elif [[ "$missing_required_rpc" -eq 1 ]]; then
|
||
warn " 存在独立进程 RPC 未注册;如果对应 API 调用失败,请优先检查该 RPC 进程日志"
|
||
fi
|
||
fi
|
||
else
|
||
printf " ${RED}○${NC} %-18s %s\n" "etcd" "不可访问: $ETCD_ENDPOINT"
|
||
printf "%s\n" "$ETCD_KEYS" | sed 's/^/ /'
|
||
fi
|
||
fi
|
||
|
||
# ── 远程服务 ─────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ 远程服务(连接配置)]${NC}"
|
||
printf " ${CYAN}◉${NC} %-10s %s\n" "MongoDB" \
|
||
"${MONGO_HOST:-?}:${MONGO_PORT:-27017}/${MONGO_DATABASE:-?} (authSource=${MONGO_AUTHSOURCE:-?})"
|
||
printf " ${CYAN}◉${NC} %-10s %s\n" "MinIO" \
|
||
"bucket=${MINIO_BUCKET:-?} external=${MINIO_EXTERNAL_ADDRESS:-?}"
|
||
|
||
# ── 后端服务 ─────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ 后端服务 ]${NC}"
|
||
print_svc_status "openim-server" ":10002 (API) :10001 (MsgGateway WS)"
|
||
print_svc_status "chat-rpc" "内部 RPC → Etcd"
|
||
print_svc_status "admin-rpc" "内部 RPC → Etcd"
|
||
print_svc_status "chat-api" ":10008"
|
||
print_svc_status "admin-api" ":10009"
|
||
print_svc_status "meetingmsg" ":8000 (WS)"
|
||
print_svc_status "livecloud" ":8080"
|
||
print_svc_status "livestream" ":8888"
|
||
print_svc_status "build-server" ":8281"
|
||
|
||
# ── Nginx API / WebSocket 网关 ─────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ Nginx 网关(PC API / WebSocket)]${NC}"
|
||
if command -v curl &>/dev/null && [[ -n "${PC_BACKEND_ORIGIN:-}" ]]; then
|
||
PC_BACKEND_ORIGIN="${PC_BACKEND_ORIGIN%/}"
|
||
curl_tls=()
|
||
[[ "$PC_BACKEND_ORIGIN" == https://* ]] && curl_tls=(-k)
|
||
if curl "${curl_tls[@]}" -fsS --max-time 3 "${PC_BACKEND_ORIGIN}/nginx-health" >/dev/null 2>&1; then
|
||
printf " ${GREEN}●${NC} %-14s %s\n" "nginx-health" "${PC_BACKEND_ORIGIN}/nginx-health"
|
||
else
|
||
printf " ${RED}○${NC} %-14s %s\n" "nginx-health" "${PC_BACKEND_ORIGIN}/nginx-health 不可达"
|
||
echo " 请执行: sudo ./deploy-test/00-init-tools.sh nginx,并确认安全组/防火墙放行 TCP 80"
|
||
fi
|
||
gateway_host=$(printf '%s' "$PC_BACKEND_ORIGIN" | sed -E 's#^https?://([^/]+).*#\1#')
|
||
if [[ "$PC_BACKEND_ORIGIN" == https://* ]]; then
|
||
default_ws_url="wss://${gateway_host}/msg_gateway"
|
||
else
|
||
default_ws_url="ws://${gateway_host}/msg_gateway"
|
||
fi
|
||
echo " PC IM API: ${PC_VITE_API_URL:-${PC_BACKEND_ORIGIN}/api/im}"
|
||
echo " PC User API: ${PC_VITE_USER_URL:-${PC_BACKEND_ORIGIN}/api/user}"
|
||
echo " PC Chat API: ${PC_VITE_CHAT_URL:-${PC_BACKEND_ORIGIN}/api/chat}"
|
||
echo " PC Admin API: ${PC_VITE_ADMIN_URL:-${PC_BACKEND_ORIGIN}/api/admin}"
|
||
echo " PC WebSocket: ${PC_VITE_WS_URL:-$default_ws_url}"
|
||
echo " PC 页面入口: ${PC_BACKEND_ORIGIN}/ (外部 HTTPS → 本机 Nginx :80 → /app/pc/dist)"
|
||
echo " Nginx 日志: /var/log/nginx/openim-pc-proxy-access.log"
|
||
pc_probe_msg_gateway "$PC_BACKEND_ORIGIN"
|
||
else
|
||
printf " ${YELLOW}○${NC} %-14s %s\n" "nginx-health" "跳过(未安装 curl 或未设置 PC_BACKEND_ORIGIN)"
|
||
fi
|
||
|
||
# ── 静态前端 ─────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ 静态前端 ]${NC}"
|
||
print_static_site_status() {
|
||
local label="$1" dist_file="$2" build_hint="$3" host_header="$4" access_url="$5"
|
||
local body title
|
||
|
||
if [[ -f "$dist_file" ]]; then
|
||
printf " ${GREEN}●${NC} %-14s %s\n" "${label}-dist" "$dist_file"
|
||
else
|
||
printf " ${YELLOW}○${NC} %-14s %s\n" "${label}-dist" "未构建(执行 ${build_hint})"
|
||
fi
|
||
|
||
if command -v curl &>/dev/null; then
|
||
if curl -fsS --max-time 3 -H "Host: ${host_header}" http://127.0.0.1/nginx-health >/dev/null 2>&1; then
|
||
printf " ${GREEN}●${NC} %-14s %s\n" "${label}-nginx" "$access_url"
|
||
body="$(curl -fsS --max-time 5 -H "Host: ${host_header}" http://127.0.0.1/ 2>/dev/null || true)"
|
||
if [[ -n "$body" ]] && printf '%s' "$body" | grep -qi "<html"; then
|
||
title="$(printf '%s' "$body" | grep -oiE '<title>[^<]*</title>' | head -1 | sed -E 's#</?title>##g' || true)"
|
||
if [[ -n "$title" ]]; then
|
||
printf " ${CYAN}◉${NC} %-14s %s\n" "${label}-title" "$title"
|
||
else
|
||
printf " ${CYAN}◉${NC} %-14s %s\n" "${label}-title" "(未解析到 <title>)"
|
||
fi
|
||
else
|
||
printf " ${YELLOW}○${NC} %-14s %s\n" "${label}-title" "首页返回异常,未识别为 HTML"
|
||
fi
|
||
else
|
||
printf " ${YELLOW}○${NC} %-14s %s\n" "${label}-nginx" "不可达(执行 sudo ./deploy-test/00-init-tools.sh nginx)"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
print_static_site_status "pc" "$ROOT_DIR/pc/dist/index.html" "./deploy-test/08-build-static-frontend.sh pc" "${PC_PROXY_DOMAIN}" "${PC_BACKEND_ORIGIN}/"
|
||
print_static_site_status "cms" "$ROOT_DIR/cms/dist/index.html" "./deploy-test/08-build-static-frontend.sh cms" "cms-jack.imharry.work" "http://cms-jack.imharry.work/"
|
||
print_static_site_status "build-cms" "$ROOT_DIR/build-cms/dist/index.html" "./deploy-test/08-build-static-frontend.sh build-cms" "build-jack.imharry.work" "http://build-jack.imharry.work/"
|
||
print_static_site_status "build-down" "$ROOT_DIR/build-down/dist/index.html" "./deploy-test/08-build-static-frontend.sh build-down" "down-jack.imharry.work" "http://down-jack.imharry.work/"
|
||
|
||
# ── 前端开发服务器 ─────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ 前端开发服务器 ]${NC}"
|
||
fe_port_desc() {
|
||
case "$1" in
|
||
meetingh5) echo "5188" ;;
|
||
h5) echo "3003" ;;
|
||
*) echo "?" ;;
|
||
esac
|
||
}
|
||
for fe in meetingh5 h5; do
|
||
pidfile="$PID_DIR/fe-${fe}.pid"
|
||
logfile="$LOG_DIR/fe-${fe}.log"
|
||
port_desc="$(fe_port_desc "$fe")"
|
||
if [[ -f "$pidfile" ]] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then
|
||
printf " ${GREEN}●${NC} %-14s PID=%-7s :%s\n" "$fe" "$(cat "$pidfile")" "$port_desc"
|
||
else
|
||
printf " ${RED}○${NC} %-14s 未运行 :%s\n" "$fe" "$port_desc"
|
||
fi
|
||
done
|
||
|
||
# ── 端口占用检查 ──────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ 端口占用 ]${NC}"
|
||
PORTS=(10002 10001 10008 10009 8000 8080 8888 8281 5188 3003)
|
||
for port in "${PORTS[@]}"; do
|
||
pid=$(lsof -ti :"$port" 2>/dev/null | head -1 || true)
|
||
if [[ -n "$pid" ]]; then
|
||
cmd=$(ps -p "$pid" -o comm= 2>/dev/null || echo "?")
|
||
printf " ${GREEN}●${NC} :%d PID=%-6s (%s)\n" "$port" "$pid" "$cmd"
|
||
else
|
||
printf " ${YELLOW}○${NC} :%d (未监听)\n" "$port"
|
||
fi
|
||
done
|
||
|
||
# ── 快速操作提示 ──────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}[ 快捷命令 ]${NC}"
|
||
echo " ./deploy-test/logs.sh <service> 查看日志(支持前端: meetingh5/h5)"
|
||
echo " ./deploy-test/restart.sh <service> 重启后端服务"
|
||
echo " ./deploy-test/restart.sh <svc> --build 重编译并重启"
|
||
echo " ./deploy-test/07-start-frontend.sh 启动开发态前端"
|
||
echo " ./deploy-test/08-build-static-frontend.sh 构建 pc/cms/build-cms/build-down 静态资源"
|
||
echo " sudo ./deploy-test/dt.sh fe-publish 构建静态前端 + 更新 Nginx + 校验"
|
||
echo " ./deploy-test/stop-frontend.sh 停止前端服务"
|
||
echo " ./deploy-test/check-conn.sh 验证 MongoDB/S3 连接"
|
||
echo ""
|