feat(api-gateway): 添加 Kong 监控栈一键安装脚本
- 添加 scripts/install-monitor.sh 一键安装脚本 - 自动检查依赖和 DNS 解析 - 自动生成 Nginx 配置 - 自动申请 Let's Encrypt SSL 证书 - 自动启动 Prometheus + Grafana - 添加 prometheus 插件到 kong.yml 配置 - 添加 docker-compose.monitoring.yml 监控服务编排 - 添加 Grafana 预配置仪表盘 - 扩展 deploy.sh 支持 monitoring install/up/down 命令 使用方式: ./deploy.sh monitoring install # 使用默认域名安装 ./deploy.sh monitoring install mydomain.com # 自定义域名 ./deploy.sh monitoring up # 仅启动服务 ./deploy.sh metrics # 查看指标 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d55a2673dc
commit
90bfa4afac
|
|
@ -12,6 +12,8 @@
|
|||
# ./deploy.sh health # 健康检查
|
||||
# ./deploy.sh reload # 重载 Kong 配置
|
||||
# ./deploy.sh routes # 查看所有路由
|
||||
# ./deploy.sh monitoring # 启动监控栈 (Prometheus + Grafana)
|
||||
# ./deploy.sh metrics # 查看 Prometheus 指标
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
|
@ -28,8 +30,11 @@ PROJECT_NAME="rwa-api-gateway"
|
|||
KONG_ADMIN_URL="http://localhost:8001"
|
||||
KONG_PROXY_URL="http://localhost:8000"
|
||||
|
||||
# 脚本目录
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# 切换到脚本所在目录
|
||||
cd "$(dirname "$0")"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# 日志函数
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
|
|
@ -187,6 +192,65 @@ cmd_clean() {
|
|||
log_success "清理完成"
|
||||
}
|
||||
|
||||
# 启动监控栈
|
||||
cmd_monitoring_up() {
|
||||
log_info "启动监控栈 (Prometheus + Grafana)..."
|
||||
$COMPOSE_CMD -f docker-compose.yml -f docker-compose.monitoring.yml up -d prometheus grafana
|
||||
|
||||
log_info "等待服务启动..."
|
||||
sleep 5
|
||||
|
||||
log_success "监控栈启动成功!"
|
||||
echo ""
|
||||
echo "监控服务地址:"
|
||||
echo " Grafana: http://localhost:3030 (admin/admin123)"
|
||||
echo " Prometheus: http://localhost:9090"
|
||||
echo " Kong 指标: http://localhost:8001/metrics"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 安装监控栈 (包括 Nginx + SSL)
|
||||
cmd_monitoring_install() {
|
||||
local domain="${1:-monitor.szaiai.com}"
|
||||
log_info "安装监控栈..."
|
||||
|
||||
if [ ! -f "$SCRIPT_DIR/scripts/install-monitor.sh" ]; then
|
||||
log_error "安装脚本不存在: scripts/install-monitor.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo bash "$SCRIPT_DIR/scripts/install-monitor.sh" "$domain"
|
||||
}
|
||||
|
||||
# 停止监控栈
|
||||
cmd_monitoring_down() {
|
||||
log_info "停止监控栈..."
|
||||
docker stop rwa-prometheus rwa-grafana 2>/dev/null || true
|
||||
docker rm rwa-prometheus rwa-grafana 2>/dev/null || true
|
||||
log_success "监控栈已停止"
|
||||
}
|
||||
|
||||
# 查看 Prometheus 指标
|
||||
cmd_metrics() {
|
||||
log_info "Kong Prometheus 指标概览:"
|
||||
echo ""
|
||||
|
||||
# 获取关键指标
|
||||
metrics=$(curl -s $KONG_ADMIN_URL/metrics 2>/dev/null)
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "=== 请求统计 ==="
|
||||
echo "$metrics" | grep -E "^kong_http_requests_total" | head -20
|
||||
echo ""
|
||||
echo "=== 延迟统计 ==="
|
||||
echo "$metrics" | grep -E "^kong_latency_" | head -10
|
||||
echo ""
|
||||
echo "完整指标: curl $KONG_ADMIN_URL/metrics"
|
||||
else
|
||||
log_error "无法获取指标,请确保 Kong 正在运行且 prometheus 插件已启用"
|
||||
fi
|
||||
}
|
||||
|
||||
# 显示帮助
|
||||
show_help() {
|
||||
echo ""
|
||||
|
|
@ -207,6 +271,13 @@ show_help() {
|
|||
echo " services 查看所有服务"
|
||||
echo " test 测试 API 路由"
|
||||
echo " clean 清理容器和数据"
|
||||
echo ""
|
||||
echo "监控命令:"
|
||||
echo " monitoring install [domain] 一键安装监控 (Nginx+SSL+服务)"
|
||||
echo " monitoring up 启动监控栈"
|
||||
echo " monitoring down 停止监控栈"
|
||||
echo " metrics 查看 Prometheus 指标"
|
||||
echo ""
|
||||
echo " help 显示帮助"
|
||||
echo ""
|
||||
echo "注意: 需要先启动 backend/services 才能启动 Kong"
|
||||
|
|
@ -255,6 +326,27 @@ main() {
|
|||
clean)
|
||||
cmd_clean
|
||||
;;
|
||||
monitoring)
|
||||
case "${2:-up}" in
|
||||
install)
|
||||
cmd_monitoring_install "$3"
|
||||
;;
|
||||
up)
|
||||
cmd_monitoring_up
|
||||
;;
|
||||
down)
|
||||
cmd_monitoring_down
|
||||
;;
|
||||
*)
|
||||
log_error "未知监控命令: $2"
|
||||
echo "用法: ./deploy.sh monitoring [install|up|down]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
metrics)
|
||||
cmd_metrics
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
# =============================================================================
|
||||
# Kong Monitoring Stack - Prometheus + Grafana
|
||||
# =============================================================================
|
||||
# Usage:
|
||||
# docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d
|
||||
# =============================================================================
|
||||
|
||||
services:
|
||||
# ===========================================================================
|
||||
# Prometheus - 指标收集
|
||||
# ===========================================================================
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: rwa-prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
|
||||
- '--web.console.templates=/usr/share/prometheus/consoles'
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- prometheus_data:/prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- rwa-network
|
||||
|
||||
# ===========================================================================
|
||||
# Grafana - 可视化仪表盘
|
||||
# ===========================================================================
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: rwa-grafana
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_USER=admin
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin123
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
# 反向代理支持
|
||||
- GF_SERVER_ROOT_URL=https://monitor.szaiai.com
|
||||
- GF_SERVER_SERVE_FROM_SUB_PATH=false
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./grafana/provisioning:/etc/grafana/provisioning:ro
|
||||
ports:
|
||||
- "3030:3000"
|
||||
depends_on:
|
||||
- prometheus
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- rwa-network
|
||||
|
||||
volumes:
|
||||
prometheus_data:
|
||||
driver: local
|
||||
grafana_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
rwa-network:
|
||||
external: true
|
||||
name: api-gateway_rwa-network
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: 'Kong API Gateway'
|
||||
orgId: 1
|
||||
folder: ''
|
||||
type: file
|
||||
disableDeletion: false
|
||||
updateIntervalSeconds: 10
|
||||
options:
|
||||
path: /etc/grafana/provisioning/dashboards
|
||||
|
|
@ -0,0 +1,612 @@
|
|||
{
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "reqps"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 1,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "sum(rate(kong_http_requests_total[5m])) by (service)",
|
||||
"legendFormat": "{{service}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "API 请求速率 (按服务)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "ms"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "histogram_quantile(0.95, sum(rate(kong_latency_bucket{type=\"request\"}[5m])) by (le, service))",
|
||||
"legendFormat": "{{service}} - P95",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "请求延迟 P95 (按服务)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 3,
|
||||
"options": {
|
||||
"displayLabels": ["name", "value"],
|
||||
"legend": {
|
||||
"displayMode": "table",
|
||||
"placement": "right",
|
||||
"showLegend": true,
|
||||
"values": ["value"]
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": ["lastNotNull"],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "sum(increase(kong_http_requests_total[1h])) by (service)",
|
||||
"legendFormat": "{{service}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "过去1小时请求分布 (按服务)",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 10,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "reqps"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "sum(rate(kong_http_requests_total{code=~\"5..\"}[5m])) by (service)",
|
||||
"legendFormat": "{{service}} - 5xx",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "sum(rate(kong_http_requests_total{code=~\"4..\"}[5m])) by (service)",
|
||||
"legendFormat": "{{service}} - 4xx",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "错误率 (4xx/5xx)",
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": ["lastNotNull"],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "sum(increase(kong_http_requests_total[24h]))",
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "24小时总请求数",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "percentunit"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 16
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": ["lastNotNull"],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "sum(rate(kong_http_requests_total{code=~\"5..\"}[5m])) / sum(rate(kong_http_requests_total[5m]))",
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "5xx 错误率",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "yellow",
|
||||
"value": 500
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 1000
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "ms"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 16
|
||||
},
|
||||
"id": 7,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": ["lastNotNull"],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "histogram_quantile(0.95, sum(rate(kong_latency_bucket{type=\"request\"}[5m])) by (le))",
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "整体 P95 延迟",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "reqps"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 4,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 16
|
||||
},
|
||||
"id": 8,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": ["lastNotNull"],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "prometheus"
|
||||
},
|
||||
"expr": "sum(rate(kong_http_requests_total[5m]))",
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "当前 QPS",
|
||||
"type": "stat"
|
||||
}
|
||||
],
|
||||
"refresh": "10s",
|
||||
"schemaVersion": 38,
|
||||
"style": "dark",
|
||||
"tags": ["kong", "api-gateway"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Kong API Gateway 监控",
|
||||
"uid": "kong-dashboard",
|
||||
"version": 1,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
access: proxy
|
||||
url: http://prometheus:9090
|
||||
isDefault: true
|
||||
editable: false
|
||||
|
|
@ -226,3 +226,12 @@ plugins:
|
|||
config:
|
||||
allowed_payload_size: 50
|
||||
size_unit: megabytes
|
||||
|
||||
# Prometheus 监控指标
|
||||
- name: prometheus
|
||||
config:
|
||||
per_consumer: true
|
||||
status_code_metrics: true
|
||||
latency_metrics: true
|
||||
bandwidth_metrics: true
|
||||
upstream_health_metrics: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# =============================================================================
|
||||
# Prometheus 配置 - Kong API Gateway 监控
|
||||
# =============================================================================
|
||||
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
# Kong Prometheus 指标端点
|
||||
- job_name: 'kong'
|
||||
static_configs:
|
||||
- targets: ['kong:8001']
|
||||
metrics_path: /metrics
|
||||
|
||||
# Prometheus 自身监控
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
#!/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=9090
|
||||
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;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host \$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_cache_bypass \$http_upgrade;
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# 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 "$@"
|
||||
Loading…
Reference in New Issue