int(1111) int(1111) 云原生监控体系构建:Prometheus+Grafana+Loki全栈监控解决方案设计与实施 | 绝缘体

云原生监控体系构建:Prometheus+Grafana+Loki全栈监控解决方案设计与实施

 
更多

云原生监控体系构建:Prometheus+Grafana+Loki全栈监控解决方案设计与实施

引言

随着云原生技术的快速发展,Kubernetes已成为容器编排的事实标准。然而,复杂的微服务架构和动态的容器环境给系统监控带来了前所未有的挑战。传统的监控方案已无法满足云原生环境下的可观测性需求。本文将详细介绍如何构建一个完整的云原生监控体系,通过Prometheus、Grafana和Loki的有机结合,实现对Kubernetes集群和应用的全方位监控。

云原生监控体系架构设计

监控体系核心组件

云原生监控体系主要包含以下核心组件:

  1. 指标监控:通过Prometheus收集和存储系统及应用指标
  2. 日志收集:使用Loki进行日志的收集、存储和查询
  3. 可视化展示:通过Grafana提供统一的监控面板
  4. 告警管理:基于Prometheus Alertmanager实现告警机制
  5. 服务发现:自动发现Kubernetes中的监控目标

架构设计原则

在设计云原生监控体系时,需要遵循以下原则:

  • 可扩展性:支持水平扩展以应对监控数据增长
  • 高可用性:确保监控系统自身的稳定运行
  • 自动化:减少人工配置,实现自动发现和部署
  • 安全性:保护监控数据的安全性和完整性
  • 成本效益:优化资源使用,降低运维成本

Prometheus指标监控配置

Prometheus架构概述

Prometheus是一个开源的系统监控和告警工具包,采用拉取模式收集指标数据。其核心组件包括:

  • Prometheus Server:负责指标收集、存储和查询
  • Client Libraries:为应用提供指标暴露接口
  • Pushgateway:处理短期作业的指标推送
  • Alertmanager:处理告警通知
  • Exporter:将第三方系统指标转换为Prometheus格式

Prometheus部署配置

Kubernetes部署方式

使用Helm部署Prometheus是最常见的做法:

# values.yaml
prometheus:
  enabled: true
  alertmanager:
    persistentVolume:
      enabled: true
      size: 2Gi
  server:
    persistentVolume:
      enabled: true
      size: 8Gi
    retention: "15d"
    resources:
      limits:
        cpu: 1000m
        memory: 2Gi
      requests:
        cpu: 500m
        memory: 1Gi
  serverFiles:
    prometheus.yml:
      rule_files:
        - /etc/config/recording_rules.yml
        - /etc/config/alerting_rules.yml

Prometheus配置文件详解

# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  scrape_timeout: 10s

rule_files:
  - "alerting_rules.yml"
  - "recording_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - alertmanager:9093

scrape_configs:
  - job_name: 'kubernetes-apiservers'
    kubernetes_sd_configs:
    - role: endpoints
    scheme: https
    tls_config:
      ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    relabel_configs:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep
      regex: default;kubernetes;https

  - job_name: 'kubernetes-nodes'
    kubernetes_sd_configs:
    - role: node
    scheme: https
    tls_config:
      ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    relabel_configs:
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)
    - target_label: __address__
      replacement: kubernetes.default.svc:443
    - source_labels: [__meta_kubernetes_node_name]
      regex: (.+)
      target_label: __metrics_path__
      replacement: /api/v1/nodes/${1}/proxy/metrics

  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
    - role: pod
    relabel_configs:
    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
      action: keep
      regex: true
    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)
    - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
      action: replace
      regex: ([^:]+)(?::\d+)?;(\d+)
      replacement: $1:$2
      target_label: __address__
    - action: labelmap
      regex: __meta_kubernetes_pod_label_(.+)
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: kubernetes_namespace
    - source_labels: [__meta_kubernetes_pod_name]
      action: replace
      target_label: kubernetes_pod_name

自定义监控指标

应用指标暴露

在应用程序中集成Prometheus客户端库:

// Go应用示例
package main

import (
    "net/http"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
    httpRequestsTotal = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total number of HTTP requests",
        },
        []string{"method", "endpoint", "status"},
    )
    
    httpRequestDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name: "http_request_duration_seconds",
            Help: "HTTP request duration in seconds",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "endpoint"},
    )
)

func init() {
    prometheus.MustRegister(httpRequestsTotal)
    prometheus.MustRegister(httpRequestDuration)
}

func main() {
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(":8080", nil)
}

常用Exporter配置

Node Exporter
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      hostPID: true
      hostIPC: true
      hostNetwork: true
      containers:
      - name: node-exporter
        image: prom/node-exporter:v1.3.1
        ports:
        - containerPort: 9100
          protocol: TCP
          name: http
        args:
        - --path.procfs=/host/proc
        - --path.sysfs=/host/sys
        - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+)($|/)
        - --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$
        volumeMounts:
        - name: dev
          mountPath: /host/dev
        - name: proc
          mountPath: /host/proc
        - name: sys
          mountPath: /host/sys
        - name: rootfs
          mountPath: /rootfs
          readOnly: true
        securityContext:
          privileged: true
      volumes:
      - name: proc
        hostPath:
          path: /proc
      - name: dev
        hostPath:
          path: /dev
      - name: sys
        hostPath:
          path: /sys
      - name: rootfs
        hostPath:
          path: /

Grafana可视化配置

Grafana部署

Kubernetes部署配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
      - name: grafana
        image: grafana/grafana:9.1.0
        ports:
        - containerPort: 3000
        env:
        - name: GF_SECURITY_ADMIN_PASSWORD
          value: "admin123"
        - name: GF_USERS_ALLOW_SIGN_UP
          value: "false"
        volumeMounts:
        - name: grafana-storage
          mountPath: /var/lib/grafana
      volumes:
      - name: grafana-storage
        persistentVolumeClaim:
          claimName: grafana-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: monitoring
spec:
  selector:
    app: grafana
  ports:
  - port: 3000
    targetPort: 3000
  type: LoadBalancer

数据源配置

Prometheus数据源

{
  "name": "prometheus",
  "type": "prometheus",
  "url": "http://prometheus-server:9090",
  "access": "proxy",
  "isDefault": true,
  "jsonData": {
    "timeInterval": "15s"
  }
}

Loki数据源

{
  "name": "loki",
  "type": "loki",
  "url": "http://loki:3100",
  "access": "proxy",
  "jsonData": {
    "maxLines": 1000
  }
}

核心监控面板设计

Kubernetes集群概览面板

{
  "dashboard": {
    "title": "Kubernetes Cluster Overview",
    "panels": [
      {
        "title": "Cluster CPU Usage",
        "type": "graph",
        "datasource": "prometheus",
        "targets": [
          {
            "expr": "100 - (avg(irate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
            "legendFormat": "CPU Usage %"
          }
        ]
      },
      {
        "title": "Cluster Memory Usage",
        "type": "graph",
        "datasource": "prometheus",
        "targets": [
          {
            "expr": "(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100",
            "legendFormat": "Memory Usage %"
          }
        ]
      },
      {
        "title": "Pod Status",
        "type": "stat",
        "datasource": "prometheus",
        "targets": [
          {
            "expr": "sum(kube_pod_status_ready{condition=\"true\"})",
            "legendFormat": "Ready Pods"
          }
        ]
      }
    ]
  }
}

Loki日志收集系统

Loki架构设计

Loki采用与Prometheus相似的设计理念,专门为日志设计的水平可扩展、高可用性日志聚合系统。其核心组件包括:

  • Loki Server:负责日志存储和查询
  • Promtail:日志收集代理
  • LogQL:日志查询语言

Loki部署配置

Loki Server配置

# loki-config.yaml
auth_enabled: false

server:
  http_listen_port: 3100

ingester:
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
  chunk_idle_period: 5m
  chunk_retain_period: 30s

schema_config:
  configs:
    - from: 2020-05-15
      store: boltdb
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 168h

storage_config:
  boltdb:
    directory: /tmp/loki/index
  filesystem:
    directory: /tmp/loki/chunks

limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h

chunk_store_config:
  max_look_back_period: 0s

table_manager:
  retention_deletes_enabled: false
  retention_period: 0s

Promtail配置

# promtail-config.yaml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: kubernetes-pods
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels:
          - __meta_kubernetes_pod_controller_name
        regex: ([0-9a-z-.]+?)(-[0-9a-f]{8,10})?
        target_label: __tmp_controller_name
      - source_labels:
          - __meta_kubernetes_pod_label_app
        target_label: app
      - source_labels:
          - __meta_kubernetes_pod_label_component
        target_label: component
      - action: replace
        replacement: $1
        separator: "/"
        source_labels:
          - __meta_kubernetes_namespace
          - __meta_kubernetes_pod_name
        target_label: job
      - action: replace
        source_labels:
          - __meta_kubernetes_namespace
        target_label: namespace
      - action: replace
        source_labels:
          - __meta_kubernetes_pod_name
        target_label: pod
      - action: replace
        source_labels:
          - __meta_kubernetes_pod_container_name
        target_label: container
      - replacement: /var/log/pods/*$1/*.log
        separator: /
        source_labels:
          - __meta_kubernetes_pod_uid
          - __meta_kubernetes_pod_container_name
        target_label: __path__

LogQL查询语法

基础查询示例

# 查询特定应用的日志
{app="nginx"} |= "error"

# 按时间范围查询
{job="kubernetes-pods"} |~ ".*error.*" [5m]

# 聚合查询
sum(count_over_time({namespace="production"}[1h])) by (app)

# 标签过滤
{namespace="production", app=~"api|web"} | json | status >= 400

告警系统配置

Alertmanager配置

告警规则定义

# alerting_rules.yml
groups:
- name: kubernetes.rules
  rules:
  - alert: KubernetesNodeNotReady
    expr: kube_node_status_condition{condition="Ready",status="true"} == 0
    for: 10m
    labels:
      severity: critical
    annotations:
      summary: "Kubernetes node not ready (instance {{ $labels.instance }})"
      description: "Node {{ $labels.node }} has been unready for more than 10 minutes."

  - alert: KubernetesPodCrashLooping
    expr: rate(kube_pod_container_status_restarts_total[15m]) * 60 * 5 > 0
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Kubernetes pod crash looping (pod {{ $labels.pod }})"
      description: "Pod {{ $labels.pod }} is crash looping."

  - alert: HighCPUUsage
    expr: 100 - (avg(irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High CPU usage (instance {{ $labels.instance }})"
      description: "CPU usage is above 80% for more than 5 minutes."

  - alert: HighMemoryUsage
    expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 85
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High memory usage (instance {{ $labels.instance }})"
      description: "Memory usage is above 85% for more than 5 minutes."

Alertmanager配置文件

# alertmanager.yml
global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: 'alert@example.com'
  smtp_auth_username: 'alert@example.com'
  smtp_auth_password: 'password'

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'webhook'

receivers:
- name: 'webhook'
  webhook_configs:
  - url: 'http://webhook-service:8080/alert'
    send_resolved: true

- name: 'email'
  email_configs:
  - to: 'admin@example.com'
    send_resolved: true

inhibit_rules:
- source_match:
    severity: 'critical'
  target_match:
    severity: 'warning'
  equal: ['alertname', 'dev', 'instance']

告警最佳实践

告警分级策略

# 告警严重级别定义
labels:
  severity: critical  # 紧急告警,需要立即处理
  severity: warning   # 警告告警,需要关注
  severity: info      # 信息告警,用于通知

告警抑制规则

# 避免重复告警
inhibit_rules:
- source_match:
    alertname: 'KubernetesNodeDown'
  target_match:
    alertname: 'KubernetesPodNotRunning'
  equal: ['instance']

监控体系集成与优化

统一监控面板

综合监控Dashboard

{
  "dashboard": {
    "title": "Application Performance Monitoring",
    "tags": ["application", "performance", "monitoring"],
    "panels": [
      {
        "title": "Application Response Time",
        "type": "graph",
        "datasource": "prometheus",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))",
            "legendFormat": "95th percentile"
          },
          {
            "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))",
            "legendFormat": "99th percentile"
          }
        ]
      },
      {
        "title": "Error Rate",
        "type": "graph",
        "datasource": "prometheus",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m])) * 100",
            "legendFormat": "Error Rate %"
          }
        ]
      },
      {
        "title": "Application Logs",
        "type": "logs",
        "datasource": "loki",
        "targets": [
          {
            "expr": "{app=\"myapp\"} |= \"error\"",
            "refId": "A"
          }
        ]
      }
    ]
  }
}

性能优化建议

Prometheus性能优化

# prometheus优化配置
global:
  scrape_interval: 30s  # 适当增加抓取间隔
  scrape_timeout: 10s

storage:
  tsdb:
    retention.time: 15d    # 合理设置保留时间
    retention.size: 10GB   # 限制存储大小

query:
  max_concurrency: 20    # 限制并发查询数
  timeout: 2m            # 设置查询超时

Loki性能优化

# loki性能优化配置
ingester:
  chunk_idle_period: 10m     # 增加chunk空闲时间
  chunk_block_size: 262144   # 调整block大小
  chunk_encoding: snappy     # 使用压缩算法

limits_config:
  ingestion_rate_mb: 10      # 限制摄入速率
  ingestion_burst_size_mb: 20 # 限制突发摄入大小

安全性配置

访问控制配置

Prometheus安全配置

# prometheus安全配置
global:
  external_labels:
    monitor: 'production'

rule_files:
  - "alerting_rules.yml"

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
    basic_auth:
      username: 'prometheus'
      password: 'secure_password'

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']
      basic_auth:
        username: 'alertmanager'
        password: 'secure_password'

Grafana安全配置

# grafana.ini
[security]
admin_user = admin
admin_password = secure_admin_password
secret_key = very_secret_key
login_remember_days = 1
cookie_username = grafana_user
cookie_remember_name = grafana_remember

[users]
allow_sign_up = false
allow_org_create = false
auto_assign_org = true
auto_assign_org_role = Viewer

[auth.anonymous]
enabled = false

[auth.basic]
enabled = true

监控体系运维

监控系统健康检查

Prometheus健康检查

#!/bin/bash
# prometheus_health_check.sh

PROMETHEUS_URL="http://localhost:9090"

# 检查Prometheus服务状态
curl -s -o /dev/null -w "%{http_code}" $PROMETHEUS_URL/-/healthy
if [ $? -eq 200 ]; then
    echo "Prometheus is healthy"
else
    echo "Prometheus is unhealthy"
    exit 1
fi

# 检查监控目标状态
targets_status=$(curl -s $PROMETHEUS_URL/api/v1/targets | jq '.data.activeTargets[] | select(.health != "up")')
if [ -z "$targets_status" ]; then
    echo "All targets are healthy"
else
    echo "Unhealthy targets found:"
    echo "$targets_status"
fi

Loki健康检查

#!/bin/bash
# loki_health_check.sh

LOKI_URL="http://localhost:3100"

# 检查Loki服务状态
curl -s -o /dev/null -w "%{http_code}" $LOKI_URL/ready
if [ $? -eq 200 ]; then
    echo "Loki is ready"
else
    echo "Loki is not ready"
    exit 1
fi

# 检查日志摄入状态
curl -s $LOKI_URL/metrics | grep "loki_ingester_chunks_stored_total"

监控数据备份策略

Prometheus数据备份

#!/bin/bash
# prometheus_backup.sh

BACKUP_DIR="/backup/prometheus"
DATE=$(date +%Y%m%d_%H%M%S)

# 创建备份目录
mkdir -p $BACKUP_DIR/$DATE

# 备份Prometheus数据
tar -czf $BACKUP_DIR/$DATE/prometheus_data.tar.gz /prometheus/data

# 保留最近7天的备份
find $BACKUP_DIR -type d -mtime +7 -exec rm -rf {} \;

最佳实践总结

部署最佳实践

  1. 分层部署:将监控组件按功能分层部署,提高系统稳定性
  2. 资源限制:为监控组件设置合理的资源限制和请求
  3. 持久化存储:为重要监控数据配置持久化存储
  4. 版本管理:使用Helm或Kustomize管理监控组件版本

配置最佳实践

  1. 标签标准化:建立统一的标签命名规范
  2. 告警分级:实施合理的告警分级和抑制策略
  3. 保留策略:根据业务需求设置合适的数据保留时间
  4. 性能调优:定期评估和优化监控系统性能

运维最佳实践

  1. 监控自监控:建立监控系统的健康检查机制
  2. 定期备份:制定监控数据备份和恢复策略
  3. 文档完善:维护完整的监控系统文档
  4. 团队培训:定期进行监控系统使用培训

结论

通过Prometheus、Grafana和Loki的有机结合,我们可以构建一个功能完整、性能优越的云原生监控体系。这套解决方案不仅能够满足现代微服务架构的监控需求,还具备良好的可扩展性和可维护性。在实际部署过程中,需要根据具体的业务场景和资源约束进行相应的调整和优化,以确保监控系统能够稳定、高效地运行。

随着云原生技术的不断发展,监控体系也需要持续演进。建议团队保持对新技术的关注,及时引入更先进的监控工具和方法,不断提升系统的可观测性水平。

打赏

本文固定链接: https://www.cxy163.net/archives/7580 | 绝缘体

该日志由 绝缘体.. 于 2021年05月13日 发表在 未分类 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 云原生监控体系构建:Prometheus+Grafana+Loki全栈监控解决方案设计与实施 | 绝缘体
关键字: , , , ,

云原生监控体系构建:Prometheus+Grafana+Loki全栈监控解决方案设计与实施:等您坐沙发呢!

发表评论


快捷键:Ctrl+Enter