如何在 kind 中部署 kube-prometheus-stack:用 Helm 搭一套可访问的 Grafana、Prometheus 和 Alertmanager 练习环境
如果你已经把 kind 装好了,接下来很适合练的一套内容,就是在本地 Kubernetes 里把完整监控栈搭起来。
这篇文章讲的不是只把 Grafana 页面打开,而是按一条更接近真实集群运维的路线,完成下面这套环境:
kind多节点集群ingress-nginxkube-prometheus-stackGrafana / Prometheus / Alertmanager的 Ingress 访问ServiceMonitor自动发现自定义应用指标
整套操作做完以后,你会同时理解两件事:
- 怎么把监控栈部署起来
- 为什么 Prometheus Operator 体系比手写
scrape_config更适合 Kubernetes
这套方案到底在做什么
先用最短的话解释一下。
kube-prometheus-stack 不是单独装一个 Prometheus。
它本质上是一个基于 Prometheus Operator 的 Kubernetes 监控方案,通常会把这些组件一起部署出来:
- Prometheus:采集和存储指标
- Grafana:看图表和 Dashboard
- Alertmanager:处理告警
- node-exporter:采集节点指标
- kube-state-metrics:采集 Kubernetes 对象状态指标
- Prometheus Operator:用 Kubernetes CRD 管理监控配置
它和“手工装一个 Prometheus + 自己写一堆抓取规则”的区别在于:
- 你不再主要依赖手写
scrape_config - 而是通过
ServiceMonitor、PodMonitor、PrometheusRule这些 Kubernetes 资源管理监控
这就是为什么它更适合拿来练 Kubernetes 监控。
你需要提前准备什么
本文默认你本机已经有这些工具:
kindkubectlhelm- 一个能正常运行的 Docker / 容器运行环境
你可以先简单确认一下:
kind versionkubectl version --clienthelm version如果这三条命令都能正常输出版本,再继续往下做。
第一步:先把实验文件按仓库结构放好
如果你准备把这套练习长期保留下来,推荐不要把 YAML 和命令散落在桌面目录里,而是单独放进一个实验仓库。
这次对应的仓库是:
这篇里用到的监控实验放在 observability/ 子目录下。
我现在这套内容对应的目录结构是:
~/Code/k8s-lab/├── README.md└── observability/ ├── README.md ├── clusters/ │ └── kind/ │ └── obs/ │ └── kind-observability.yaml ├── helm/ │ ├── ingress-nginx/ │ │ └── values.yaml │ └── kube-prometheus-stack/ │ └── values.yaml ├── manifests/ │ └── demo/ │ ├── namespace.yaml │ ├── prometheus-example-app.yaml │ └── servicemonitor.yaml └── scripts/ ├── install.sh ├── uninstall.sh └── port-forward.sh先进入实验目录:
cd ~/Code/k8s-lab/observability这一步的作用是什么
这样整理有几个实际好处:
clusters/放集群配置helm/放各个 chart 的 valuesmanifests/放业务或示例资源scripts/放安装、卸载和调试脚本- 仓库根目录的
README.md负责整个k8s-lab的总入口 observability/README.md负责这次监控实验的详细说明
也就是说,这篇文章不再只是“做完一次实验”,而是把这次实验沉淀成仓库里的一个独立实验目录,后面还可以继续往 k8s-lab 里补别的主题。
第二步:查看并使用 kind 集群配置
这份 kind 配置文件放在:
clusters/kind/obs/kind-observability.yaml内容如下:
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes: - role: control-plane extraPortMappings: - containerPort: 30080 hostPort: 8080 protocol: TCP - containerPort: 30443 hostPort: 8443 protocol: TCP - role: worker - role: worker手动创建集群时,可以这样执行:
kind create cluster --name obs --config clusters/kind/obs/kind-observability.yamlkubectl get nodes -o wide这一步的作用是什么
这里最关键的是 extraPortMappings。
它把宿主机端口映射到了 kind 控制平面节点里:
localhost:8080 -> kind control-plane:30080localhost:8443 -> kind control-plane:30443
后面我们会把 ingress-nginx 的 NodePort 固定到 30080 和 30443,这样你就能直接从浏览器访问:
- Grafana
- Prometheus
- Alertmanager
如果不提前做这个端口映射,后面的 Ingress 虽然资源能创建成功,但你从宿主机访问会不方便很多。
第三步:安装 ingress-nginx
这个 chart 的 values 文件放在:
helm/ingress-nginx/values.yaml内容如下:
controller: service: type: NodePort nodePorts: http: 30080 https: 30443先加仓库并更新索引:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginxhelm repo update再通过 values 文件安装:
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \ -n ingress-nginx \ --create-namespace \ -f helm/ingress-nginx/values.yaml \ --wait如果你宿主机的代理写的是本地回环地址,比如:
HTTP_PROXY=http://127.0.0.1:7890HTTPS_PROXY=http://127.0.0.1:7890
要注意:helm repo update 在宿主机上能走代理,不代表 kind 节点里拉镜像也能走同一个地址。
ingress-nginx 真正卡住的地方,通常不是 Helm 本身,而是集群节点里的 containerd 在拉这些镜像时仍然访问自己的 127.0.0.1:7890:
registry.k8s.io/ingress-nginx/controllerregistry.k8s.io/ingress-nginx/kube-webhook-certgen
这时常见现象是:
helm upgrade --install很慢- 最后
--wait超时或context canceled kubectl get pods -n ingress-nginx里出现ImagePullBackOff
可以直接看事件确认:
kubectl get events -n ingress-nginx --sort-by=.lastTimestamp如果输出里出现类似报错:
proxyconnect tcp: dial tcp 127.0.0.1:7890: connect: connection refused说明问题不在 values,也不在 Ingress 资源本身,而是在 kind 节点内部拿不到宿主机上的本地代理。
这种情况下,推荐直接用实验仓库里的 observability/scripts/install.sh 安装。脚本已经把这类本地代理场景处理掉了:当它检测到 HTTP_PROXY / HTTPS_PROXY 指向 127.0.0.1 或 localhost 时,会自动把 kind 节点里 containerd 的代理改写成 Docker kind 网络中的宿主机网关地址,再继续安装。
如果你想手工指定,也可以显式传:
KIND_NODE_PROXY=http://172.18.0.1:7890 ./scripts/install.sh这里的 172.18.0.1 只是当前默认 Docker bridge/kind 网络里常见的宿主机网关地址,实际环境如果不同,请改成你机器上的真实网关地址。
检查结果:
kubectl get pods -n ingress-nginxkubectl get svc -n ingress-nginx这一步的作用是什么
ingress-nginx 是这套实验里的统一入口。
它的作用可以直接理解成:
- 根据域名把请求转发到不同服务
- 让 Grafana、Prometheus、Alertmanager 都能通过浏览器访问
这里把 Service 类型设成 NodePort,并且固定端口为:
- HTTP:
30080 - HTTPS:
30443
配合上一步的 kind 端口映射,宿主机访问 8080/8443 就能进集群里的 Ingress。
第三步:给本地域名做 hosts 映射
把这几个域名加到本机 /etc/hosts:
echo "127.0.0.1 grafana.local prometheus.local alertmanager.local" | sudo tee -a /etc/hosts后面访问地址就是:
http://grafana.local:8080http://prometheus.local:8080http://alertmanager.local:8080
这一步的作用是什么
Ingress 主要是按 Host 匹配规则转发流量。
所以这里不是随便写三个名字,而是让浏览器访问时真正带上:
grafana.localprometheus.localalertmanager.local
如果你只访问 http://127.0.0.1:8080,Ingress 往往无法按你期望的规则把请求转到目标服务。
第五步:查看 kube-prometheus-stack 的 values 文件
这个 values 文件放在:
helm/kube-prometheus-stack/values.yaml内容如下:
fullnameOverride: kps
grafana: enabled: true adminPassword: admin defaultDashboardsTimezone: browser ingress: enabled: true ingressClassName: nginx hosts: - grafana.local path: /
prometheus: ingress: enabled: true ingressClassName: nginx hosts: - prometheus.local paths: - / prometheusSpec: retention: 2d scrapeInterval: 15s evaluationInterval: 15s
serviceMonitorSelectorNilUsesHelmValues: false podMonitorSelectorNilUsesHelmValues: false ruleSelectorNilUsesHelmValues: false
serviceMonitorNamespaceSelector: {} podMonitorNamespaceSelector: {} ruleNamespaceSelector: {}
resources: requests: cpu: 200m memory: 512Mi limits: memory: 2Gi
alertmanager: ingress: enabled: true ingressClassName: nginx hosts: - alertmanager.local paths: - / alertmanagerSpec: retention: 120h
kubeControllerManager: enabled: false
kubeScheduler: enabled: false
kubeEtcd: enabled: false这一步的作用是什么
这个文件是整篇里最重要的一步之一。
因为它不只是“改几个参数”,而是在明确这套监控栈的行为。
下面分几块看。
1. 打开 Grafana / Prometheus / Alertmanager 的 Ingress
这三段配置的作用是:
- 给 Grafana 配
grafana.local - 给 Prometheus 配
prometheus.local - 给 Alertmanager 配
alertmanager.local
这样安装完以后,你就能直接用浏览器访问它们。
2. 设置 Prometheus 的保留时间和采集频率
retention: 2dscrapeInterval: 15sevaluationInterval: 15s这里的含义分别是:
retention: 2d:指标保留 2 天scrapeInterval: 15s:每 15 秒抓一次指标evaluationInterval: 15s:每 15 秒执行一次规则计算
对于本地 kind 实验环境,这样的设置够用,也不会把资源拉得太高。
3. 允许跨命名空间发现监控对象
serviceMonitorSelectorNilUsesHelmValues: falsepodMonitorSelectorNilUsesHelmValues: falseruleSelectorNilUsesHelmValues: false
serviceMonitorNamespaceSelector: {}podMonitorNamespaceSelector: {}ruleNamespaceSelector: {}这一组配置很关键。
它的实际效果是让 Prometheus 不只盯着 monitoring 命名空间里的对象,而是可以发现整个集群中的:
ServiceMonitorPodMonitorPrometheusRule
这也是后面你在 demo 命名空间创建 ServiceMonitor 时,Prometheus 仍然能自动识别它的原因。
4. 限制 Prometheus 资源占用
resources: requests: cpu: 200m memory: 512Mi limits: memory: 2Gi因为 kind 是本地实验集群,不像正式生产环境那样资源充足。
这段配置的作用是:
- 给 Prometheus 一个基础资源请求值
- 避免它在本地机器上无限吃内存
5. 关闭 kind 里常见的控制平面红色 Target
kubeControllerManager: enabled: false
kubeScheduler: enabled: false
kubeEtcd: enabled: false这是很实用的一组开关。
在很多本地 kind 环境里,这些控制平面组件的指标暴露方式和真实集群不完全一样,直接打开后,Prometheus Targets 页面可能会出现一堆 Down。
先关掉它们的作用是:
- 降低初学时的噪音
- 让你先把主要监控链路跑通
- 避免一上来就被一堆红色状态误导
第六步:安装 kube-prometheus-stack
先加仓库并更新:
helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update创建命名空间并安装:
kubectl create namespace monitoring
helm upgrade --install kps prometheus-community/kube-prometheus-stack \ -n monitoring \ -f helm/kube-prometheus-stack/values.yaml \ --wait \ --timeout 10m如果你已经把脚本也放进仓库,其实这里也可以直接走:
./scripts/install.sh这个脚本会顺序完成:
- 创建
kind集群 - 安装
ingress-nginx - 安装
kube-prometheus-stack - 应用
manifests/demo/里的示例资源 - 打印 Ingress 和 ServiceMonitor 检查结果
也就是说,手工命令适合你逐步理解,脚本适合你后面重复搭环境。
安装完成后检查:
kubectl get pods -n monitoringkubectl get svc -n monitoringkubectl get ingress -n monitoringkubectl get prometheus -n monitoringkubectl get alertmanager -n monitoringkubectl get servicemonitors -A这一步的作用是什么
这一步会把整套监控栈真正装进集群。
常见会被创建出来的内容包括:
- Grafana
- Prometheus Operator
- Prometheus 实例
- Alertmanager 实例
- kube-state-metrics
- node-exporter
- 一组默认规则和 Dashboard 配置
你在这里第一次看到的重点,不应该只是 Pod Running,还应该注意:
- 有没有创建
Ingress - 有没有创建
Prometheus自定义资源 - 有没有创建一批
ServiceMonitor
这些资源恰恰体现了它是 Prometheus Operator 体系,而不是传统的“装一个 Deployment 就完了”。
第六步:访问 Grafana、Prometheus 和 Alertmanager
浏览器访问:
http://grafana.local:8080http://prometheus.local:8080http://alertmanager.local:8080
Grafana 默认登录信息:
用户名:admin密码:admin这一步你应该看到什么
如果前面的部署都正常,Grafana 里通常已经会有不少 Kubernetes 相关 Dashboard。
比如:
Kubernetes / Compute Resources / ClusterKubernetes / Compute Resources / NamespaceKubernetes / Compute Resources / PodNode Exporter / Nodes
这说明这套监控栈不只是“服务起来了”,而是:
- Prometheus 已经在采集数据
- Grafana 已经配置好了数据源
- 默认 Dashboard 已经能直接展示 Kubernetes 指标
第八步:部署一个带 metrics 的示例应用
真正能说明你已经理解这套体系的,不是把 Grafana 打开,而是把自己的应用接进来。
这套示例资源现在拆到了:
manifests/demo/├── namespace.yaml├── prometheus-example-app.yaml└── servicemonitor.yaml你可以逐个应用:
kubectl apply -f manifests/demo/namespace.yamlkubectl apply -f manifests/demo/prometheus-example-app.yamlkubectl apply -f manifests/demo/servicemonitor.yaml也可以直接交给前面的 ./scripts/install.sh 一次性处理。
检查结果:
kubectl get pods -n demokubectl get svc -n demokubectl get servicemonitor -n demo这一步的作用是什么
这份 YAML 一共做了三件事:
1. 部署应用
Deployment 会创建两个副本的示例应用 Pod。
2. 暴露应用
Service 把这些 Pod 统一暴露成一个稳定的服务入口。
3. 告诉 Prometheus 应该怎么抓它
ServiceMonitor 才是这里的重点。
它不是直接写采集规则到 Prometheus 配置文件里,而是用 Kubernetes 资源声明:
- 匹配哪些 Service
- 抓哪个端口
- 抓哪个路径
- 多久抓一次
也就是说,ServiceMonitor 是 Prometheus Operator 世界里的“监控接入声明”。
只要 Prometheus 被配置成允许发现这个命名空间里的 ServiceMonitor,它就会自动把这个应用加入抓取目标。
第九步:去 Prometheus 页面验证 Target 和指标
打开:
http://prometheus.local:8080
然后进入:
Status -> Targets
如果配置正确,你应该能看到和 demo/prometheus-example-app 相关的 Target。
再试两个简单查询:
versionhttp_requests_total这一步的作用是什么
这一步是在验证整条链路是否真的跑通:
- 应用是否正常暴露
/metrics - Service 是否正确指向 Pod
- ServiceMonitor 是否正确匹配到 Service
- Prometheus 是否真的发现并抓到了这个目标
如果这里能看到 Target Up,说明你已经完成了从“部署监控栈”到“接入自定义应用”的闭环。
第十步:这套环境起来以后,应该重点练什么
环境搭好以后,不要只停留在“我会访问 Grafana”。
更值得练的是下面这些内容:
- Grafana Dashboard 是怎么自动出现的
- Prometheus 的 Targets 为什么会
Up或Down ServiceMonitor是怎么发现Service的kube-state-metrics到底提供了哪些 Kubernetes 对象指标node-exporter到底提供了哪些节点指标PrometheusRule应该怎么写Alertmanager怎么接收和分组告警- Helm values 是怎么覆盖默认 chart 配置的
可以重点看这些命令:
kubectl get servicemonitors -Akubectl describe servicemonitor -n demo prometheus-example-app
kubectl get prometheusrules -Akubectl get pods -n monitoringkubectl logs -n monitoring deploy/kps-operator
kubectl get secret -n monitoringkubectl get cm -n monitoring | grep grafana常见问题 1:为什么我要先装 ingress-nginx
因为这篇的目标不只是把监控栈“装进去”,还包括让你能从浏览器稳定访问多个服务。
如果没有 Ingress,你当然也可以:
- 用
kubectl port-forward - 或者改成
NodePort
但那样每个服务都要单独处理,体验不统一,也不利于理解 Kubernetes 中的入口流量管理。
常见问题 2:为什么 values 里要关闭 controller-manager、scheduler、etcd
不是因为它们不重要,而是因为在本地 kind 环境里,它们经常会带来不必要的 Down Target 噪音。
先关掉的目的是:
- 让主流程先跑通
- 让你先把注意力放在应用接入和监控链路上
- 后面如果你要继续深挖控制平面监控,再单独打开排查
常见问题 3:为什么要单独写 ServiceMonitor
因为这是 Prometheus Operator 的核心使用方式。
传统 Prometheus 更偏向:
- 手工维护抓取配置
而在 Kubernetes 里,更自然的方式是:
- 让监控配置也变成 Kubernetes 资源
- 让应用通过标签和资源声明被自动发现
这就是 ServiceMonitor 的价值。
清理环境
如果你练完了,想一键清理,现在更推荐直接用仓库里的脚本:
./scripts/uninstall.sh如果你还想顺便删除 Prometheus Operator 相关 CRD:
DELETE_CRDS=true ./scripts/uninstall.sh如果你只是临时不想走 Ingress,也可以改用:
./scripts/port-forward.sh grafana./scripts/port-forward.sh prometheus./scripts/port-forward.sh alertmanager这样后面重看这套实验时,不只是命令还在,连安装、清理和调试入口都已经整理好了。
这篇流程做完以后,你真正掌握了什么
如果你把上面这一套完整跑通,收获不只是“会装一个监控组件”。
更准确地说,你已经练到了这些内容:
- 会在 kind 里搭一个可访问的监控实验环境
- 知道
ingress-nginx在这里承担什么角色 - 知道
kube-prometheus-stack为什么比单独装 Prometheus 更适合 Kubernetes - 知道
ServiceMonitor是怎么把应用接进 Prometheus 的 - 知道如何验证 Target、指标和 Dashboard 是否真的生效
如果你后面继续深入这套环境,可以把练习重点放在这些方向:
- 调整
ServiceMonitor和PodMonitor的发现范围 - 自己写一条
PrometheusRule做告警实验 - 给 Alertmanager 配一个真实的告警接收方式
- 观察某个应用从暴露指标到进入 Dashboard 的完整链路
这样再回头看这篇流程时,你就不只是“照着装完一套环境”,而是真的把 Kubernetes 监控体系从部署、发现到验证完整走了一遍。