rwadurian/backend/api-gateway/scripts/install-monitor.sh

381 lines
11 KiB
Bash

#!/bin/bash
# =============================================================================
# Kong 监控栈一键安装脚本
# =============================================================================
# 功能:
# - 自动配置 Nginx 反向代理
# - 自动申请 Let's Encrypt SSL 证书
# - 启动 Prometheus + Grafana 监控服务
#
# 用法:
# ./install-monitor.sh # 使用默认域名 monitor.szaiai.com
# ./install-monitor.sh mydomain.com # 使用自定义域名
# =============================================================================
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# 日志函数
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
# 默认配置
DOMAIN="${1:-monitor.szaiai.com}"
GRAFANA_PORT=3030
PROMETHEUS_PORT=9099
GRAFANA_USER="admin"
GRAFANA_PASS="admin123"
# 获取脚本目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
# 显示 Banner
show_banner() {
echo -e "${CYAN}"
echo "╔═══════════════════════════════════════════════════════════════╗"
echo "║ Kong 监控栈一键安装脚本 ║"
echo "║ Prometheus + Grafana ║"
echo "╚═══════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
echo "域名: $DOMAIN"
echo "Grafana 端口: $GRAFANA_PORT"
echo "Prometheus 端口: $PROMETHEUS_PORT"
echo ""
}
# 检查 root 权限
check_root() {
if [ "$EUID" -ne 0 ]; then
log_error "请使用 root 权限运行此脚本"
echo "用法: sudo $0 [domain]"
exit 1
fi
}
# 检查依赖
check_dependencies() {
log_step "检查依赖..."
local missing=()
if ! command -v docker &> /dev/null; then
missing+=("docker")
fi
if ! command -v nginx &> /dev/null; then
missing+=("nginx")
fi
if ! command -v certbot &> /dev/null; then
missing+=("certbot")
fi
if [ ${#missing[@]} -gt 0 ]; then
log_error "缺少依赖: ${missing[*]}"
echo ""
echo "请先安装:"
echo " apt update && apt install -y docker.io nginx certbot python3-certbot-nginx"
exit 1
fi
log_success "依赖检查通过"
}
# 检查 DNS 解析
check_dns() {
log_step "检查 DNS 解析..."
local resolved_ip=$(dig +short $DOMAIN 2>/dev/null | head -1)
local server_ip=$(curl -s ifconfig.me 2>/dev/null || curl -s icanhazip.com 2>/dev/null)
if [ -z "$resolved_ip" ]; then
log_error "无法解析域名 $DOMAIN"
echo "请先在 DNS 管理面板添加 A 记录:"
echo " $DOMAIN -> $server_ip"
exit 1
fi
if [ "$resolved_ip" != "$server_ip" ]; then
log_warn "DNS 解析的 IP ($resolved_ip) 与本机公网 IP ($server_ip) 不匹配"
read -p "是否继续? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
log_success "DNS 解析正确: $DOMAIN -> $resolved_ip"
}
# 生成 Nginx 配置
generate_nginx_config() {
log_step "生成 Nginx 配置..."
cat > /etc/nginx/sites-available/$DOMAIN.conf << EOF
# Kong 监控面板 Nginx 配置
# 自动生成于 $(date)
# HTTP -> HTTPS 重定向
server {
listen 80;
listen [::]:80;
server_name $DOMAIN;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://\$host\$request_uri;
}
}
# HTTPS 配置
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name $DOMAIN;
# SSL 证书 (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
# SSL 优化
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
# HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
# 日志
access_log /var/log/nginx/$DOMAIN.access.log;
error_log /var/log/nginx/$DOMAIN.error.log;
# Grafana
location / {
proxy_pass http://127.0.0.1:$GRAFANA_PORT;
proxy_http_version 1.1;
# WebSocket support
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
# Standard proxy headers
proxy_set_header Host \$http_host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-Host \$host;
proxy_set_header X-Forwarded-Port \$server_port;
# Grafana 10+ 反向代理支持
proxy_set_header Origin \$scheme://\$host;
# 缓存和超时
proxy_cache_bypass \$http_upgrade;
proxy_read_timeout 86400;
proxy_buffering off;
}
# Prometheus (仅内网)
location /prometheus/ {
allow 127.0.0.1;
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
proxy_pass http://127.0.0.1:$PROMETHEUS_PORT/;
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
}
# 健康检查
location = /health {
access_log off;
return 200 '{"status":"ok","service":"monitor-nginx"}';
add_header Content-Type application/json;
}
}
EOF
log_success "Nginx 配置已生成: /etc/nginx/sites-available/$DOMAIN.conf"
}
# 申请 SSL 证书
obtain_ssl_cert() {
log_step "申请 SSL 证书..."
# 检查证书是否已存在
if [ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]; then
log_success "SSL 证书已存在"
return 0
fi
# 创建 certbot webroot 目录
mkdir -p /var/www/certbot
# 临时启用 HTTP 配置用于验证
cat > /etc/nginx/sites-available/$DOMAIN-temp.conf << EOF
server {
listen 80;
server_name $DOMAIN;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 200 'Waiting for SSL...';
add_header Content-Type text/plain;
}
}
EOF
ln -sf /etc/nginx/sites-available/$DOMAIN-temp.conf /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# 申请证书
certbot certonly --webroot -w /var/www/certbot -d $DOMAIN --non-interactive --agree-tos --email admin@$DOMAIN || {
log_error "SSL 证书申请失败"
rm -f /etc/nginx/sites-enabled/$DOMAIN-temp.conf
rm -f /etc/nginx/sites-available/$DOMAIN-temp.conf
exit 1
}
# 清理临时配置
rm -f /etc/nginx/sites-enabled/$DOMAIN-temp.conf
rm -f /etc/nginx/sites-available/$DOMAIN-temp.conf
log_success "SSL 证书申请成功"
}
# 启用 Nginx 配置
enable_nginx_config() {
log_step "启用 Nginx 配置..."
ln -sf /etc/nginx/sites-available/$DOMAIN.conf /etc/nginx/sites-enabled/
nginx -t || {
log_error "Nginx 配置测试失败"
exit 1
}
systemctl reload nginx
log_success "Nginx 配置已启用"
}
# 启动监控服务
start_monitoring_services() {
log_step "启动监控服务..."
cd "$PROJECT_DIR"
# 检查 Kong 是否运行
if ! docker ps | grep -q rwa-kong; then
log_warn "Kong 未运行,先启动 Kong..."
docker compose up -d
sleep 10
fi
# 同步 Kong 配置 (启用 prometheus 插件)
log_info "同步 Kong 配置..."
docker compose run --rm kong-config || log_warn "配置同步失败,可能已是最新"
# 启动监控栈
log_info "启动 Prometheus + Grafana..."
docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d prometheus grafana
# 等待服务启动
sleep 5
# 检查服务状态
if docker ps | grep -q rwa-grafana && docker ps | grep -q rwa-prometheus; then
log_success "监控服务启动成功"
else
log_error "监控服务启动失败"
docker compose -f docker-compose.yml -f docker-compose.monitoring.yml logs --tail=50
exit 1
fi
}
# 显示安装结果
show_result() {
echo ""
echo -e "${GREEN}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ 安装完成! ║${NC}"
echo -e "${GREEN}╚═══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo "访问地址:"
echo -e " Grafana: ${CYAN}https://$DOMAIN${NC}"
echo -e " 用户名: ${YELLOW}$GRAFANA_USER${NC}"
echo -e " 密码: ${YELLOW}$GRAFANA_PASS${NC}"
echo ""
echo "Prometheus (仅内网可访问):"
echo -e " 地址: ${CYAN}https://$DOMAIN/prometheus/${NC}"
echo ""
echo "Kong 指标端点:"
echo -e " 地址: ${CYAN}http://localhost:8001/metrics${NC}"
echo ""
echo "管理命令:"
echo " ./deploy.sh monitoring up # 启动监控"
echo " ./deploy.sh monitoring down # 停止监控"
echo " ./deploy.sh metrics # 查看指标"
echo ""
}
# 卸载函数
uninstall() {
log_warn "正在卸载监控栈..."
# 停止服务
cd "$PROJECT_DIR"
docker stop rwa-prometheus rwa-grafana 2>/dev/null || true
docker rm rwa-prometheus rwa-grafana 2>/dev/null || true
# 删除 Nginx 配置
rm -f /etc/nginx/sites-enabled/$DOMAIN.conf
rm -f /etc/nginx/sites-available/$DOMAIN.conf
systemctl reload nginx 2>/dev/null || true
log_success "监控栈已卸载"
echo "注意: SSL 证书未删除,如需删除请运行: certbot delete --cert-name $DOMAIN"
}
# 主函数
main() {
show_banner
# 检查是否卸载
if [ "$1" = "uninstall" ] || [ "$1" = "--uninstall" ]; then
uninstall
exit 0
fi
check_root
check_dependencies
check_dns
generate_nginx_config
obtain_ssl_cert
enable_nginx_config
start_monitoring_services
show_result
}
main "$@"