0. 简介
前面,我们已经分别可以部署了单机版和Sentinel版的Redis Operator,我们现在来完善一些监控指标。
0.1 Redis Exporter
Redis Exporter 是 Prometheus 监控生态中的关键组件,用于采集 Redis 实例的性能指标并转换为 Prometheus 格式。如下:
功能类别 | 具体指标 |
---|---|
基础运行指标 | 内存使用量、连接数、命令执行次数、键数量、网络流量等 |
持久化监控 | RDB/AOF 操作状态、持久化时间、缓冲区大小 |
复制监控 | 主从复制状态、复制延迟、同步状态 |
集群监控 | 集群节点状态、槽位分配、故障转移状态 (支持 Redis Cluster) |
特殊功能 | Lua脚本性能分析、慢查询统计、键空间分析 |
0.2 整体方案
整体方案如上所示,所以我们大致分为三步来做这个事情:
- Operator实现Redis Exporter;
- 部署Prometheus相关组件;
- 实现ServiceMnitor;
1. Operator改造
为了方便,我们以单机版的Redis Operator为例,我们在redis_types.go
中添加如下配置:
go
// RedisSpec defines the desired state of Redis
type RedisSpec struct {
// ... 已有字段
// Exporter
Exporter ExporterSpec `json:"exporter,omitempty"`
}
// ExporterSpec 定义 Redis Exporter 配置
type ExporterSpec struct {
// 是否启用监控
Enable bool `json:"enable,omitempty"`
// 镜像
// +kubebuilder:default="oliver006/redis_exporter:v1.50.0"
Image string `json:"image,omitempty"`
// 端口
// +kubebuilder:default=9121
Port int32 `json:"port,omitempty"`
// 资源限制
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
}
在redis_controller.go
中添加如下代码,即在开启了Exporter之后,使用多应用容器的方式启动Exporter(这是因为我的k8s版本是1.27,在1.29以上版本,使用边车容器的方式会更优雅)。
go
func (r *RedisReconciler) reconcileStatefulSet(ctx context.Context, redis *cachev1.Redis) error {
// ...
if redis.Spec.Exporter.Enable {
// 添加 Redis Exporter 容器
desired.Spec.Template.Spec.Containers = append(desired.Spec.Template.Spec.Containers, corev1.Container{
Name: "redis-exporter",
Image: redis.Spec.Exporter.Image,
ImagePullPolicy: corev1.PullIfNotPresent,
Ports: []corev1.ContainerPort{
{
Name: "metrics",
ContainerPort: redis.Spec.Exporter.Port,
},
},
Args: []string{
fmt.Sprintf("--redis.addr=localhost:%d", RedisPort),
fmt.Sprintf("--web.listen-address=:%d", redis.Spec.Exporter.Port),
},
Resources: redis.Spec.Exporter.Resources,
})
}
// ...
}
另外,在redis_webhook.go
中新增校验:
go
// validateRedis 执行具体验证逻辑
func (r *Redis) validateRedis(redis *Redis) error {
// ...
// 验证Redis Exporter
if redis.Spec.Exporter.Enable {
if redis.Spec.Exporter.Image == "" {
redis.Spec.Exporter.Image = "oliver006/redis_exporter:v1.50.0"
redislog.Info("Setting default exporter image", "image", redis.Spec.Exporter.Image)
}
if redis.Spec.Exporter.Port == 0 {
redis.Spec.Exporter.Port = 9121
redislog.Info("Setting default exporter port", "port", redis.Spec.Exporter.Port)
}
}
// ...
}
如上,我们基本就将Operator改造完成了。
2. 集群改造
因为本地是kind搭建的集群,所以我们对外暴露一下Prometheus和Grafana的端口:
yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 31000
hostPort: 6380
protocol: TCP
# Prometheus UI
- containerPort: 30090
hostPort: 30090
protocol: TCP
# Grafana UI
- containerPort: 30091
hostPort: 30091
protocol: TCP
# Alertmanager
- containerPort: 30093
hostPort: 9093
protocol: TCP
extraMounts:
# 主机目录映射到节点容器
- hostPath: /Users/chenyiguo/workspace/k8s/kind/single_date
containerPath: /data
- role: worker
extraMounts:
# 主机目录映射到节点容器
- hostPath: /Users/chenyiguo/workspace/k8s/kind/single_date
containerPath: /data
3. 监控组件
3.1 安装Prometheus等
bash
# 创建 prometheus 命名空间
$ k create namespace prometheus
# 添加 Helm 仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 安装 kube-prometheus-stack
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
-n prometheus \
--set prometheus.service.type=NodePort \
--set prometheus.service.nodePort=30090 \
--set grafana.service.type=NodePort \
--set grafana.service.nodePort=30091 \
--set alertmanager.service.type=NodePort \
--set alertmanager.service.nodePort=30093
我们在名为prometheus
的命名空间下安装了Prometheus以及Grafana等。这个时候我们需要注意的是,这里将Prometheus的Operator和Server都一起安装了,和所有的Operator一样,有整个Operator的管理程序,也有其CRD,以及CRD派生的Statefulset(Or Deployment)和Pod,比如:
bash
$ k -n prometheus get prometheus # CRD
NAME VERSION DESIRED READY RECONCILED AVAILABLE AGE
kube-prometheus-stack-prometheus v3.5.0 1 1 True True 4h54m
$ k -n prometheus get sts | grep kube-prometheus-stack-prometheus # Statefulset
prometheus-kube-prometheus-stack-prometheus 1/1 4h54m
$ k -n prometheus get pod | grep prometheus-kube-prometheus-stack-prometheus # Pod
prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0 5h9m
而Operator的溯源如下:
bash
$ k -n prometheus get deploy | grep operator
NAME READY UP-TO-DATE AVAILABLE AGE
kube-prometheus-stack-operator 1/1 1 1 5h10m
$ k -n prometheus get pod | grep kube-prometheus-stack-operator
kube-prometheus-stack-operator-d6f48dc88-c7c2n 1/1 Running 0 5h33m
当然,还有很多其他grafana和alertmanager组件,这里我们就不详细介绍了。
3.2 新增ServiceMonitor
可以说,ServiceMonitor
这种CRD就是连接Prometheus和Redis Exporter之间的桥梁,Prometheus的Operator通过监控这种CRD的变更,就能实现对于不同监控对象的动态加载,比如,在安装的默认Prometheus组件中,就有这对于很多集群和节点等基础组件的监控:
bash
$ k -n prometheus get smon # smon是servicemonitors的缩写
NAME AGE
kube-prometheus-stack-alertmanager 11m
kube-prometheus-stack-apiserver 11m
kube-prometheus-stack-coredns 11m
kube-prometheus-stack-grafana 11m
kube-prometheus-stack-kube-controller-manager 11m
kube-prometheus-stack-kube-etcd 11m
kube-prometheus-stack-kube-proxy 11m
kube-prometheus-stack-kube-scheduler 11m
kube-prometheus-stack-kube-state-metrics 11m
kube-prometheus-stack-kubelet 11m
kube-prometheus-stack-operator 11m
kube-prometheus-stack-prometheus 11m
kube-prometheus-stack-prometheus-node-exporter 11m
所以我们也需要定义一个监控Redis的ServiceMontor,注意需要打上release: kube-prometheus-stack
的label,因为在prometheus的CRD中,有serviceMonitorSelector
限制了labels的匹配规则,而serviceMonitorNamespaceSelector: {}
则表示不限制namespace。
yaml
$ k -n prometheus get prometheus kube-prometheus-stack-prometheus -oyaml | grep serviceMonitorSelector -C
5
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
serviceAccountName: kube-prometheus-stack-prometheus
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector:
matchLabels:
release: kube-prometheus-stack
shards: 1
tsdb:
outOfOrderTimeWindow: 0s
所以ServiceMontor定义如下:
yaml
# redis-service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: redis-monitor
namespace: default
labels:
release: kube-prometheus-stack
spec:
selector:
matchLabels:
app: redis
namespaceSelector:
matchNames:
- default
endpoints:
- port: metrics
interval: 15s
path: /metrics
relabelings:
- sourceLabels: [__meta_kubernetes_pod_name]
targetLabel: pod
- sourceLabels: [__meta_kubernetes_pod_label_name]
targetLabel: redis_instance
然后执行k apply -f config/prometheus/redis-service-monitor.yaml
,即可生成。
4. 验证
4.1 Grafana
通过一系列的命令在新的集群中启动Redis,然后我们即可在浏览器中输入http://localhost:30091/
看到grafana面板,输入账密之后登录。(账户是admin
,密码是通过kubectl --namespace prometheus get secrets kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 -d ; echo
获取)
然后再grafana的Dashboards菜单导入仪表板ID是763
的仪表板,数据源选择Prometheus,进行导入,即可得到如下图所示的监控面板: