Kubernetes 日志与监控架构

概述

在 Kubernetes 集群中,日志和监控是保障服务可用性和排查问题的重要基础设施。本文档深入剖析 Kubernetes 的日志收集机制、监控体系以及相关的最佳实践。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
┌─────────────────────────────────────────────────────────────────────────┐
│ Kubernetes 日志与监控架构图 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 应用层 │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ App A │ │ App B │ │ App C │ │ ... │ │ │
│ │ │ stdout │ │ stdout │ │ file │ │ ... │ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ │ │ │ │ │ │ │
│ └───────┼────────────┼────────────┼────────────┼────────────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 容器运行时层 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ journald │ │ json-log │ │ file │ │ │
│ │ │ (Pod) │ │ (Pod) │ │ (Pod) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 节点层 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ kubelet │ │ Fluent Bit │ │ cAdvisor │ │ │
│ │ │ (日志聚合) │ │ (日志收集) │ │ (指标采集) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 集群层 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Loki/ │ │ Prometheus │ │ Alert- │ │ │
│ │ │ Elasticsearch│ │ Stack │ │ manager │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘

1. 容器日志机制

1.1 容器日志类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
┌─────────────────────────────────────────────────────────────────────────┐
│ 容器日志类型 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ stdout/stderr (标准输出/错误) │ │
│ │ ──────────────────────────────────────────────────────────── │ │
│ │ │ │
│ │ containerd: /var/log/pods/<namespace>_<pod>_<uid>/<container>/ │ │
│ │ └── *.log │ │
│ │ │ │
│ │ json-file 驱动 (Docker): /var/lib/docker/containers/<id>/ │ │
│ │ └── <id>-json.log │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 应用程序文件日志 │ │
│ │ ──────────────────────────────────────────────────────────── │ │
│ │ │ │
│ │ 写入容器内的文件: │ │
│ │ - 挂载 Volume 保存 │ │
│ │ - HostPath 挂载到宿主机 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ journald 日志 (系统服务) │ │
│ │ ──────────────────────────────────────────────────────────── │ │
│ │ │ │
│ │ kubelet、docker、containerd 等系统服务日志 │ │
│ │ journalctl -u kubelet -f │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘

1.2 kubelet 日志管理

1
2
3
4
5
6
7
8
9
10
11
// kubelet 日志管理
// pkg/kubelet/kuberuntime/helpers.go

// 日志路径结构
// /var/log/pods/<namespace>_<podname>_<uid>/<containername>/N.log
// /var/log/pods/<namespace>_<podname>_<uid>/<containername>/0.log

// kubelet 通过 symlink 连接到实际日志位置
func getContainerLogsPath(podUID, containerName, restartCount int) string {
return filepath.Join(podLogsRootDirectory, podUID, containerName, fmt.Sprintf("%d.log", restartCount))
}

1.3 日志驱动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Docker 容器日志配置
# /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m", # 单文件最大 100MB
"max-file": "5", # 最多 5 个文件
"compress": "true" # 压缩历史日志
}
}

# containerd 日志配置
# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri"]
[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "runc"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
LogDriver = "json-file"
[plugins."io.containerd.grpc.v1.cri".containerd.default_runtime_runc.options]
LogPath = "/var/log/container/"
LogSizeMax = 100000000 # 100MB

2. 日志收集方案

2.1 节点级日志收集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
┌─────────────────────────────────────────────────────────────────────────┐
│ 节点级日志收集架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Node │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ /var/log/pods/ /var/log/containers/ │ │
│ │ ┌───────────┐ ┌───────────┐ │ │
│ │ │ nginx │ │ nginx.log │ │ │
│ │ │ └── *.log │ ─────────► │ │ │ │
│ │ └───────────┘ └─────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌───────────────┐ │ │
│ │ │ Fluent Bit │ │ │
│ │ │ (DaemonSet) │ │ │
│ │ └───────┬───────┘ │ │
│ │ │ │ │
│ │ ┌──────────────────────┼──────────────────────┐ │ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐│ │
│ │ │ Loki │ │ Elasticsearch │ │ S3 ││ │
│ │ │ │ │ │ │ ││ │
│ │ └───────────────┘ └───────────────┘ └───────────────┘│ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘

2.2 Fluent Bit 部署配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# fluent-bit.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluent-bit
namespace: logging
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
spec:
selector:
matchLabels:
name: fluent-bit
template:
metadata:
labels:
name: fluent-bit
spec:
serviceAccountName: fluent-bit
containers:
- name: fluent-bit
image: fluent/fluent-bit:2.0.0
ports:
- containerPort: 2020
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlogpods
mountPath: /var/log/pods
readOnly: true
- name: config
mountPath: /fluent-bit/etc
resources:
limits:
memory: 100Mi
cpu: 100m
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlogpods
hostPath:
path: /var/log/pods
- name: config
configMap:
name: fluent-bit-config
---
# Fluent Bit 配置
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: logging
data:
fluent-bit.conf: |
[SERVICE]
Flush 5
Log_Level info
Daemon off

[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.containers.*
Refresh_Interval 5

[FILTER]
Name kubernetes
Match kube.containers.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token

[OUTPUT]
Name loki
Match *
Host loki.logging.svc.cluster.local
Port 3100
TenantID {{.TenantID}}

2.3 应用日志最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 应用日志配置示例
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: myapp:latest
# 结构化日志输出到 stdout
command: ["myapp", "--log-format=json"]
resources:
limits:
memory: "128Mi"
cpu: "100m"
# 挂载日志目录
volumeMounts:
- name: app-logs
mountPath: /var/log/myapp
volumes:
- name: app-logs
emptyDir: {}
---
# 日志格式建议(JSON)
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "INFO",
"message": "Request processed",
"request_id": "abc-123",
"user_id": "user-1",
"duration_ms": 150,
"service": "myapp",
"version": "v1.2.3"
}

3. 监控体系

3.1 Prometheus 架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌─────────────────────────────────────────────────────────────────────────┐
│ Prometheus 监控架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Prometheus Server │ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ Scrape │ │ Storage │ │ HTTP │ │ Alert │ │ │
│ │ │ Manager │ │ (TSDB) │ │ Server │ │ Manager │ │ │
│ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │ │
│ │ │ │ │ │ │ │
│ │ └──────────────┬┴──────────────┴──────────────┘ │ │
│ │ ▼ │ │
│ │ ┌───────────────┐ │ │
│ │ │ Prometheus │ │ │
│ │ │ TSDB │ │ │
│ │ │ /prometheus │ │ │
│ │ └───────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────┼─────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ kube- │ │ Node │ │ App │ │
│ │ apiserver │ │ Exporter │ │ Metrics │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ kubelet │ │ cAdvisor │ │ Sidecar │ │
│ │ + cAdvisor│ │ │ │ Exporter │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘

3.2 Prometheus Operator 部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Prometheus Operator CRD
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: k8s
namespace: monitoring
spec:
replicas: 2
retention: 15d
serviceAccountName: prometheus
serviceMonitorSelector:
matchLabels:
team: k8s
ruleSelector:
matchLabels:
role: alert-rules
resources:
requests:
memory: 400Mi
storage:
volumeClaimTemplate:
spec:
storageClassName: ssd
resources:
requests:
storage: 10Gi
---
# ServiceMonitor 示例
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: myapp
namespace: monitoring
labels:
team: k8s
spec:
selector:
matchLabels:
app: myapp
endpoints:
- port: metrics
interval: 15s
path: /metrics
namespaceSelector:
matchNames:
- production

3.3 指标类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Prometheus 指标类型

# 1. Counter - 只能递增的计数器
# 用途:请求数、错误数、完成任务数
http_requests_total{method="GET", status="200"}

# 2. Gauge - 可以任意增减的值
# 用途:CPU 使用率、内存使用量、连接数
container_cpu_usage_seconds_total{container="nginx"}

# 3. Histogram - 直方图,统计分布
# 用途:请求延迟、响应大小
http_request_duration_seconds_bucket{le="0.1"}
http_request_duration_seconds_bucket{le="0.5"}
http_request_duration_seconds_bucket{le="1.0"}

# 4. Summary - 分位数,统计延迟
# 用途:延迟的 50/90/99 分位数
http_request_duration_seconds{quantile="0.9"}

# 常用 PromQL 查询
# CPU 使用率
rate(container_cpu_usage_seconds_total{name="nginx"}[5m])
# 内存使用量
container_memory_working_set_bytes{name="nginx"}
# 请求 QPS
rate(http_requests_total{service="myapp"}[5m])
# 错误率
rate(http_requests_total{service="myapp", status=~"5.."}[5m])

4. Kubernetes 核心指标

4.1 kube-state-metrics

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# kube-state-metrics 部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-state-metrics
namespace: monitoring
spec:
selector:
matchLabels:
k8s-app: kube-state-metrics
template:
metadata:
labels:
k8s-app: kube-state-metrics
spec:
containers:
- name: kube-state-metrics
image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.9.0
ports:
- name: http
containerPort: 8080
---
# kube-state-metrics 暴露的指标

# Pod 指标
kube_pod_info{pod="nginx-7fb96c846b-abc12", namespace="default", pod_ip="10.244.1.5"}
kube_pod_status_phase{phase="Running"} # Pending/Running/Failed/Succeeded/Unknown
kube_pod_container_status_restarts_total
kube_pod_container_resource_requests{resource="cpu"}
kube_pod_container_resource_limits{resource="memory"}

# Deployment 指标
kube_deployment_spec_replicas
kube_deployment_status_replicas_available
kube_deployment_status_replicas_unavailable

# Node 指标
kube_node_info{node="node-1", zone="us-east-1a"}
kube_node_status_allocatable{resource="cpu"}
kube_node_status_capacity{resource="memory"}
kube_node_status_condition{condition="Ready"}

4.2 Node Exporter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Node Exporter DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true
containers:
- name: node-exporter
image: prom/node-exporter:v1.6.0
ports:
- containerPort: 9100
hostPort: 9100
command:
- /bin/node_exporter
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/host
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
---
# Node Exporter 指标
# CPU 指标
node_cpu_seconds_total{mode="user|idle|system|irq|softirq"}
node_load1 / node_load5 / node_load15

# 内存指标
node_memory_MemTotal_bytes
node_memory_MemAvailable_bytes
node_memory_MemCached_bytes
node_memory_MemBuffers_bytes

# 磁盘指标
node_disk_io_time_seconds_total{device="sda"}
node_disk_read_bytes_total{device="sda"}
node_disk_written_bytes_total{device="sda"}
node_filesystem_avail_bytes{mountpoint="/"}

# 网络指标
node_network_receive_bytes_total{device="eth0"}
node_network_transmit_bytes_total{device="eth0"}

4.3 cAdvisor 指标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# kubelet 内置 cAdvisor 端点
# /metrics/cadvisor

# 容器 CPU 指标
container_cpu_usage_seconds_total
container_cpu_cfs_throttled_seconds_total
container_cpu_system_seconds_total

# 容器内存指标
container_memory_working_set_bytes
container_memory_rss_bytes
container_memory_cache_bytes
container_memory_swap_bytes

# 容器网络指标
container_network_receive_bytes_total
container_network_receive_packets_dropped_total
container_network_transmit_bytes_total
container_network_transmit_packets_dropped_total

# 容器文件系统指标
container_fs_reads_bytes_total
container_fs_writes_bytes_total
container_fs_usage_bytes

5. 告警系统

5.1 Alertmanager 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Alertmanager 配置
apiVersion: monitoring.coreos.com/v1
kind: Alertmanager
metadata:
name: main
namespace: monitoring
spec:
replicas: 2
configSecret: alertmanager-config
---
apiVersion: v1
kind: Secret
metadata:
name: alertmanager-config
namespace: monitoring
type: Opaque
stringData:
alertmanager.yml: |
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'alertmanager@example.com'

route:
group_by: ['alertname', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default-receiver'
routes:
- match:
severity: critical
receiver: 'critical-receiver'
group_wait: 10s

receivers:
- name: 'default-receiver'
email_configs:
- to: 'team@example.com'

- name: 'critical-receiver'
slack_configs:
- api_url: 'https://hooks.slack.com/services/xxx'
channel: '#alerts-critical'
pagerduty_configs:
- service_key: 'xxx'

5.2 告警规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: k8s-alerts
namespace: monitoring
labels:
role: alert-rules
spec:
groups:
- name: kubernetes-apps
interval: 30s
rules:
# Pod CPU 使用率过高
- alert: PodHighCpuUsage
expr: |
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (namespace, pod)
/ sum(container_spec_cpu_quota{container!=""}/container_spec_cpu_period{container!=""}) by (namespace, pod) > 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "Pod CPU 使用率超过 80%"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} CPU 使用率超过 80%"

# Pod 内存不足
- alert: PodMemoryUsageHigh
expr: |
sum(container_memory_working_set_bytes{container!=""}) by (namespace, pod)
/ sum(container_spec_memory_limit_bytes{container!=""}) by (namespace, pod) > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "Pod 内存使用率超过 90%"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 内存使用率超过 90%"

# Pod 重启次数过多
- alert: PodContainerRestarting
expr: increase(kube_pod_container_status_restarts_total[1h]) > 5
for: 2m
labels:
severity: warning
annotations:
summary: "Pod 容器重启次数过多"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 在过去 1 小时内重启超过 5 次"

# Deployment 副本不可用
- alert: DeploymentReplicasUnavailable
expr: |
kube_deployment_status_replicas_available{deployment=~".+"}
< kube_deployment_spec_replicas{deployment=~".+"}
for: 10m
labels:
severity: warning
annotations:
summary: "Deployment 副本不可用"
description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }}{{ $value }} 个副本不可用"

- name: kubernetes-resources
interval: 30s
rules:
# 节点 NotReady
- alert: NodeNotReady
expr: kube_node_status_condition{condition="Ready",status="true"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "节点 NotReady"
description: "节点 {{ $labels.node }} 状态为 NotReady"

# 节点内存压力
- alert: NodeHighMemoryUsage
expr: |
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "节点内存压力"
description: "节点 {{ $labels.node }} 内存使用率超过 90%"

# 节点磁盘压力
- alert: NodeHighDiskUsage
expr: |
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "节点磁盘空间不足"
description: "节点 {{ $labels.node }} 根分区可用空间低于 10%"

6. 可视化与仪表板

6.1 Grafana Dashboard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# Grafana 部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana
namespace: monitoring
spec:
selector:
matchLabels:
app: grafana
template:
metadata:
labels:
app: grafana
spec:
containers:
- name: grafana
image: grafana/grafana:10.0.0
ports:
- name: http
containerPort: 3000
env:
- name: GF_SECURITY_ADMIN_USER
value: admin
- name: GF_SECURITY_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: grafana-secret
key: password
volumeMounts:
- name: grafana-storage
mountPath: /var/lib/grafana
- name: grafana-dashboards
mountPath: /etc/grafana/provisioning/dashboards
resources:
requests:
cpu: 100m
memory: 200Mi
volumes:
- name: grafana-storage
persistentVolumeClaim:
claimName: grafana-pvc
- name: grafana-dashboards
configMap:
name: grafana-dashboards
---
# 常用 Dashboard JSON
{
"dashboard": {
"title": "Kubernetes Cluster Overview",
"panels": [
{
"title": "CPU Usage",
"type": "graph",
"targets": [
{
"expr": "sum(rate(container_cpu_usage_seconds_total[5m])) by (namespace)",
"legendFormat": "{{namespace}}"
}
]
},
{
"title": "Memory Usage",
"type": "graph",
"targets": [
{
"expr": "sum(container_memory_working_set_bytes) by (namespace) / 1024 / 1024",
"legendFormat": "{{namespace}} - MB"
}
]
},
{
"title": "Pod Count",
"type": "stat",
"targets": [
{
"expr": "sum(kube_pod_info) by (namespace)",
"legendFormat": "{{namespace}}"
}
]
}
]
}
}

6.2 Kubernetes Dashboard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Kubernetes Dashboard
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-csrf
namespace: kubernetes-dashboard
type: Opaque
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
replicas: 1
selector:
matchLabels:
k8s-app: kubernetes-dashboard
template:
metadata:
labels:
k8s-app: kubernetes-dashboard
spec:
containers:
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.7.0
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
resources:
limits:
cpu: 250m
memory: 256Mi
volumes:
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs

7. 关键源码路径

组件 路径
kubelet 日志 pkg/kubelet/kuberuntime/logs/
cAdvisor pkg/kubelet/cadvisor/
kube-state-metrics staging/src/k8s.io/kube-state-metrics/
Metrics Server staging/src/k8s.io/metrics/
Prometheus github.com/prometheus/prometheus
Alertmanager github.com/prometheus/alertmanager

面试题

基础题

1. Kubernetes 有哪些日志存储方式?

  • 容器日志到 stdout/stderr:由容器运行时保存到文件
  • 应用文件日志:写入挂载的 Volume
  • journald:系统服务日志
  • Kubernetes 事件:记录到 etcd

2. 如何查看 Pod 的日志?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看日志
kubectl logs <pod-name>

# 实时跟踪
kubectl logs -f <pod-name>

# 查看指定容器
kubectl logs <pod-name> -c <container-name>

# 查看上次启动的日志
kubectl logs --previous <pod-name>

# 所有容器日志
kubectl logs <pod-name> --all-containers=true

3. Prometheus 的四种指标类型是什么?

  • Counter:只能递增的计数器
  • Gauge:可任意增减的值
  • Histogram:直方图,统计分布
  • Summary:分位数统计

4. kube-state-metrics 的作用是什么?

kube-state-metrics 暴露 Kubernetes 对象的指标:

  • Pod/Deployment/StatefulSet 状态
  • Node 资源容量和状态
  • PVC 绑定状态
  • Service 信息

5. cAdvisor 采集哪些指标?

  • 容器 CPU 使用率
  • 容器内存使用量
  • 容器网络流量
  • 容器文件系统使用
  • 容器进程数

中级题

6. 如何搭建一个完整的 Kubernetes 监控体系?

  1. 部署 Prometheus Operator:使用 CRD 管理 Prometheus
  2. 部署 node-exporter:采集节点指标
  3. 部署 kube-state-metrics:采集 Kubernetes 对象状态
  4. 配置 ServiceMonitor:自动发现监控目标
  5. 部署 Alertmanager:处理告警
  6. 部署 Grafana:可视化展示

7. 如何排查 Pod 日志收集问题?

  1. 检查 Pod 是否正常输出日志
  2. 检查日志文件是否存在
  3. 检查 Fluent Bit/Fluentd 配置
  4. 检查网络连通性
  5. 检查后端存储是否正常

8. 如何设置合理的告警规则?

  1. 基于 SLO 设置:如错误率、延迟分位数
  2. 渐进式告警:先 warning 再 critical
  3. 避免告警风暴:使用 grouping 和抑制
  4. 设置合理的 for:避免瞬时抖动
  5. 定期审查:移除无效告警

9. 如何优化日志存储成本?

  1. 日志压缩:开启 gzip 压缩
  2. 分层存储:热数据存 SSD,冷数据存对象存储
  3. 日志保留策略:设置合理的保留周期
  4. 采样:高流量应用采样存储
  5. 去重:避免重复日志

10. Prometheus 与 Kubernetes 如何集成?

  • 服务发现:通过 kube-apiserver 发现 Pod、Service、Endpoints
  • RBAC:Prometheus 需要读取 Kubernetes 资源的权限
  • 指标标签:自动添加 namespace、pod、container 等标签
  • Relabeling:重写和过滤指标标签

高级题

11. 如何实现多集群监控?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 方案一:Thanos 全局视图
# 每个集群部署 Thanos Sidecar
# 部署 Thanos Query 处理跨集群查询

# 方案二:Federation 联邦
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: federation-global
spec:
serviceMonitorSelector:
matchLabels:
team: federation
endpoints:
- tlsConfig:
caFile: /etc/prometheus/certs/ca.crt
certFile: /etc/prometheus/certs/cert.crt
keyFile: /etc/prometheus/certs/key.key
staticConfigs:
- targets:
- prometheus.cluster1:9090
- prometheus.cluster2:9090

# 方案三:Remote Write
remoteWrite:
- url: https://central-prometheus/api/v1/write
bearerTokenFile: /var/run/secrets/prometheus/token

12. 如何实现应用级别的自定义指标?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 使用 Prometheus Client 库暴露自定义指标
// github.com/prometheus/client_golang

import "github.com/prometheus/client_golang/prometheus"
import "github.com/prometheus/client_golang/prometheus/promhttp"

var (
// Counter: 请求计数
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "status", "endpoint"},
)

// Histogram: 请求延迟
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request latency distribution",
Buckets: []float64{0.01, 0.05, 0.1, 0.5, 1, 5},
},
[]string{"method", "endpoint"},
)

// Gauge: 当前活跃请求数
activeRequests = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "http_active_requests",
Help: "Number of active HTTP requests",
},
)
)

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

func handleRequest(w http.ResponseWriter, r *http.Request) {
timer := prometheus.NewTimer(httpRequestDuration.WithLabelValues(r.Method))
defer timer.ObserveDuration()

activeRequests.Inc()
defer activeRequests.Dec()

// 处理请求...
httpRequestsTotal.WithLabelValues(r.Method, "200").Inc()
}

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

13. 如何设计 SLO 和 SLI?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 服务 SLO 定义
# ServiceLevelObjective
apiVersion: sloth.dev/v1
kind: SLO
metadata:
name: myapp-availability
spec:
service: myapp
sli:
plugin:
id: prometheus/availability
options:
total_metric: http_requests_total
error_metric: http_requests_total{status=~"5.."}
objectives:
- ratio: 0.999
window: 30d

---
# 常用 SLI 指标
# 可用性:请求成功率
# 延迟:P50/P90/P99 延迟
# 错误:错误率
# 吞吐量:QPS/RPS
# 饱和度:CPU/内存使用率

场景题

14. 如何排查 Kubernetes 集群性能问题?

  1. 检查节点状态kubectl top nodes
  2. 检查 Pod 资源kubectl top pods
  3. 查看组件指标:Prometheus 查询 kube-apiserver、kubelet、etcd 指标
  4. 检查网络:是否有网络延迟或丢包
  5. 分析瓶颈:CPU、内存、磁盘 IO、网络
  6. 检查日志:组件日志中是否有异常

15. 如何设置合理的资源请求和限制?

  1. 参考历史数据:使用 Prometheus 观察实际使用量
  2. 设置缓冲:请求设置 P70,限制设置 P95
  3. 考虑峰值:业务高峰期可能有突发流量
  4. 监控利用率:保持 70-80% 的资源利用率
  5. 使用 VPA:Vertical Pod Autoscaler 自动调整

16. 如何实现日志的多租户隔离?

  1. 日志标签隔离:每个租户有独立的 label
  2. Loki 多租户模式:开启 authentication
  3. Grafana 多组织:隔离不同租户的 Dashboard
  4. Storage 隔离:不同租户使用不同的存储后端
  5. RBAC 控制:限制访问日志查询接口