使用 Helm 搭建 Prometheus + Grafana 监控平台完整笔记(k8s)

📅 2026/8/18 10:32:10
使用 Helm 搭建 Prometheus + Grafana 监控平台完整笔记(k8s)
环境以及资源环境Kubernetes 集群1 master 2 nodeChart 版本kube-prometheus-stack 88.3.0核心组件Prometheus Operator Prometheus Alertmanager Grafana node-exporter kube-state-metrics官方资源Helm Chart 仓库https://prometheus-community.github.io/helm-charts上游项目https://github.com/prometheus-community/helm-chartsChart 源码与 values.yaml 说明https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stackPrometheus Operator 项目https://github.com/prometheus-operator/kube-prometheus一、安装步骤1. 添加 kube-prometheus-stack 仓库# ❌ 官方地址国内大概率超时 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts # ✅ 国内推荐使用 itboon 镜像 helm repo add prometheus-community https://helm-charts.itboon.top/prometheus-community --force-update helm repo update # 验证 helm search repo prometheus-community | head -10遇到的问题执行官方地址直接报context deadline exceeded连接超时。原因prometheus-community.github.io托管在 GitHub Pages 上国内网络访问不稳。解决改用国内镜像源https://helm-charts.itboon.top/prometheus-community。2. 安装 Chart# ✅ 正确命令必须覆盖 admission webhook 镜像为 docker.io helm install my-kube-prometheus-stack prometheus-community/kube-prometheus-stack \ --version 88.3.0 \ -n default \ --set prometheusOperator.admissionWebhooks.patch.image.registrydocker.io \ --set prometheusOperator.admissionWebhooks.patch.image.repositoryjkroepke/kube-webhook-certgen \ --set prometheusOperator.admissionWebhooks.patch.image.taglatest \ --timeout 10m2.1 为什么要覆盖 admission webhook 镜像kube-prometheus-stack 默认启用 admission webhook用于校验 PrometheusRule 等 CRD 的语法证书由 Chart 内置的 certgen Job 自动生成 。该 Job 默认使用的镜像是ghcr.io/jkroepke/kube-webhook-certgenghcr.io 在国内几乎无法访问导致 certgen Job 卡在ContainerCreating→ Helm 等待超时 → 报context deadline exceeded。幸运的是镜像维护者 jkroepke 同时也把镜像推送到了 DockerHub所以只需要把 registry 改为docker.io即可repository 和 tag 与默认值一致无需改--set prometheusOperator.admissionWebhooks.patch.image.registrydocker.io2.2 安装过程中遇到的问题汇总问题现象根本原因解决方法admission-createPod 卡在ContainerCreatingChart 默认用ghcr.io/jkroepke/kube-webhook-certgen国内拉不到通过--set把 registry 改为docker.ioHelm 报context deadline exceeded/pending-installadmission Job 超时未完成Helm 等待超时加--timeout 10m延长超时清理残留 Job 和 Secret 后重装Helm release 状态一直pending-install上一次失败的 Job 没清干净阻塞了下次安装执行下面的清理命令安装前清理残留重要helm uninstall my-kube-prometheus-stack -n default 2/dev/null kubectl delete job -n default -l app.kubernetes.io/componentadmission-create --force --grace-period0 2/dev/null kubectl delete job -n default -l app.kubernetes.io/componentadmission-patch --force --grace-period0 2/dev/null kubectl delete secret my-kube-prometheus-stack-admission -n default 2/dev/null3. 导入镜像最关键的坑⚠️血泪教训用docker pull/load导入的镜像存在 Docker 的存储里但Kubernetes 用的是 containerd两者完全隔离必须用ctr -n k8s.io images import导入K8s 才看得到。不过像上面那样把registry改了后就不用导出了而且网络允许的话这些都不需要正常helm install 下载chart包就行3.1 镜像清单88.3.0 版本所需组件默认镜像国内拉不到国内替代源Prometheusquay.io/prometheus/prometheus:v3.13.2-distrolessquay.m.daocloud.io/prometheus/prometheus:v3.13.2-distrolessAlertmanagerquay.io/prometheus/alertmanager:v0.25.0quay.m.daocloud.io/prometheus/alertmanager:v0.25.0node-exporterquay.io/prometheus/node-exporter:v1.6.1quay.m.daocloud.io/prometheus/node-exporter:v1.6.1kube-state-metricsregistry.k8s.io/kube-state-metrics/kube-state-metrics:v2.19.1k8s.m.daocloud.io/kube-state-metrics/kube-state-metrics:v2.19.1Grafanadocker.io/grafana/grafana:10.1.0docker.m.daocloud.io/grafana/grafana:10.1.0prometheus-config-reloaderquay.io/prometheus-operator/prometheus-config-reloader:v0.93.0quay.m.daocloud.io/prometheus-operator/prometheus-config-reloader:v0.93.0参考文档https://imroc.cc/tke/en/monitoring/kube-prometheus-stack3.2 在 master01 上拉取并打标签# 通过 DaoCloud 国内镜像源拉取 docker pull quay.m.daocloud.io/prometheus/prometheus:v3.13.2-distroless docker pull quay.m.daocloud.io/prometheus/alertmanager:v0.25.0 docker pull quay.m.daocloud.io/prometheus/node-exporter:v1.6.1 docker pull k8s.m.daocloud.io/kube-state-metrics/kube-state-metrics:v2.19.1 docker pull docker.m.daocloud.io/grafana/grafana:10.1.0 # 打成 K8s 要找的名字必须完全一致 docker tag quay.m.daocloud.io/prometheus/prometheus:v3.13.2-distroless quay.io/prometheus/prometheus:v3.13.2-distroless docker tag quay.m.daocloud.io/prometheus/alertmanager:v0.25.0 quay.io/prometheus/alertmanager:v0.25.0 docker tag quay.m.daocloud.io/prometheus/node-exporter:v1.6.1 quay.io/prometheus/node-exporter:v1.6.1 docker tag k8s.m.daocloud.io/kube-state-metrics/kube-state-metrics:v2.19.1 registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.19.1 docker tag docker.m.daocloud.io/grafana/grafana:10.1.0 docker.io/grafana/grafana:10.1.03.3 导出并传到所有节点导入 containerd# 打包 docker save \ quay.io/prometheus/prometheus:v3.13.2-distroless \ quay.io/prometheus/alertmanager:v0.25.0 \ quay.io/prometheus/node-exporter:v1.6.1 \ registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.19.1 \ docker.io/grafana/grafana:10.1.0 \ -o /tmp/prometheus-all.tar # 在 master01 上导入 containerd 的 k8s.io 命名空间 ctr -n k8s.io images import /tmp/prometheus-all.tar # 传到 node01、node02 并导入关键每个节点都要有 for node in k8s-node01 k8s-node02; do scp /tmp/prometheus-all.tar root$node:/tmp/ ssh root$node ctr -n k8s.io images import /tmp/prometheus-all.tar done3.4 镜像相关问题排查问题现象原因解决方法Docker 里有了镜像但 Pod 还是ImagePullBackOffDocker 和 containerd 是两套系统K8s 看不到 Docker 的镜像用ctr -n k8s.io images import导入Pod 报CreateContainerError: content digest not found该节点上镜像元数据在但内容层缺失/损坏在该节点上ctr -n k8s.io images rm 镜像名→ctr -n k8s.io content gc→ 重新 import某个节点缺特定镜像该节点 containerd k8s.io 命名空间里没有单独在该节点上docker pullctr -n k8s.io images import验证每个节点上的镜像# 在 node02 上检查 ssh k8s-node02 ctr -n k8s.io images ls | grep -E prometheus|grafana|kube-state4. 修改 Grafana Service 类型为 NodePort# 查看当前 Service kubectl get svc # 修改 kubectl edit svc my-kube-prometheus-stack-grafana -n default # 将 spec.type 从 ClusterIP 改为 NodePort # 保存退出后自动生效修改后确认kubectl get svc my-kube-prometheus-stack-grafana # NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) # my-kube-prometheus-stack-grafana NodePort 10.1.44.199 none 80:31913/TCPNodePort 关键特性NodePort 会在集群所有节点上开放同一个端口31913。所以以下地址都能访问 Grafanahttp://192.168.10.11:31913master01http://192.168.10.12:31913node01http://192.168.10.13:31913node02这就是 NodePort 的设计——任意节点 IP 固定端口 都能到达后端服务。5. 通过浏览器访问http://192.168.10.11:319136. 获取 Grafana 登录账号和密码6.1 查看 Secretkubectl get secret my-kube-prometheus-stack-grafana -n default -o yaml6.2 解密账号echo -n YWRtaW4 | base64 -d # 输出admin6.3 解密密码echo -n SjZRcEg2cmRTN3pTdmpBVVlOVFNKQlo1Zlo3SVNDc3NEczJxejNBNg | base64 -d # 输出J6QpH6rdS7zSvjAUYNTSJBZ5fZ7ISCssDs2qz3A6如果上面的密码不对因为每次 Helm 安装会生成随机密码用下面的命令获取kubectl get secret my-kube-prometheus-stack-grafana -n default \ -o jsonpath{.data.admin-password} | base64 -d echo二、安装成功后的组件清单kubectl get pods -n default组件类型副本数说明my-kube-prometheus-stack-operatorDeployment1管理 Prometheus/Alertmanager 等 CRD 资源prometheus-my-kube-prometheus-stack-prometheus-0StatefulSet1Prometheus 主服务alertmanager-my-kube-prometheus-stack-alertmanager-0StatefulSet1告警管理my-kube-prometheus-stack-grafana-xxxDeployment1可视化面板my-kube-prometheus-stack-kube-state-metrics-xxxDeployment1K8s 资源状态指标my-kube-prometheus-stack-prometheus-node-exporter-xxxDaemonSet每节点1个节点硬件/系统指标三、知识补充1. NodePort 访问流程完整链路客户端浏览器 │ http://192.168.10.11:31913 ▼ [NodePort 31913] ← 每台节点都开同一个端口 │ ▼ [kube-proxy] ← iptables/IPVS 规则做 DNAT │ 目标地址从 NodeIP:31913 → ClusterIP:80 ▼ [Service ClusterIP:80] │ 根据 selector 轮询选 Pod ▼ [Grafana Pod] ← 返回页面2. Docker vs containerd 镜像隔离操作存到哪里K8s 能看到吗docker pull xxxDocker moby 命名空间❌ 看不到docker load -i xxx.tarDocker moby 命名空间❌ 看不到ctr -n k8s.io images import xxx.tarcontainerd k8s.io 命名空间✅ 看得到crictl pull xxxcontainerd k8s.io 命名空间✅ 看得到以后给 K8s 用的镜像一律用ctr -n k8s.io images import或crictl pull3. kube-prometheus-stack 的 Admission WebhookChart 安装时会先跑两个 Job admission-create用kube-webhook-certgen生成 TLS 证书 → 存到 Secretadmission-patch把证书配置到 API Server 的 webhook这两个 Job 需要镜像jkroepke/kube-webhook-certgen。默认从ghcr.io拉取国内必卡。解决方案✅ 安装时用--set prometheusOperator.admissionWebhooks.patch.image.registrydocker.io覆盖为 DockerHub推荐✅ 或提前在所有节点导入该镜像到 containerd⚠️ 或彻底禁用 admission webhook需同时禁用 TLS否则 operator Pod 会卡在 ContainerCreating--set prometheusOperator.admissionWebhooks.enabledfalse \ --set prometheusOperator.tls.enabledfalse四、NetworkPolicy 详解4.1 什么是 NetworkPolicyNetworkPolicy 是 Kubernetes 的四层TCP/UDP/SCTP网络访问控制机制。它定义了 Pod 之间的通信规则——谁能访问我Ingress我能访问谁Egress​ 。⚠️前提条件必须使用支持 NetworkPolicy 的 CNI 插件如 Calico、Cilium 等否则策略不生效 。4.2 默认行为情况行为命名空间没有任何 NetworkPolicy所有 Pod 之间全通默认配置了 NetworkPolicy 但只写了 IngressEgress 不受影响仍然全通配置了 NetworkPolicy 但只写了 EgressIngress 不受影响仍然全通配置了 Ingress Egress只放行规则里指定的其他全拒白名单模式4.3 核心字段详解apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: default spec: podSelector: # ① 选择该策略作用到哪些 Pod 上 matchLabels: role: db policyTypes: # ② 指定策略类型Ingress / Egress / 两者 - Ingress - Egress ingress: # ③ 入站白名单规则列表 - from: - ipBlock: # 来源 IP 段 cidr: 172.17.0.0/16 except: # 排除的 IP 段 - 172.17.1.0/24 - namespaceSelector: # 来源命名空间按标签 matchLabels: project: myproject - podSelector: # 来源 Pod同命名空间 matchLabels: role: frontend ports: # 允许的端口 - protocol: TCP port: 6379 egress: # ④ 出站白名单规则列表 - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP port: 5978字段说明字段说明podSelector选择策略作用的 Pod空 selector 表示选中命名空间下所有 Pod​policyTypes指定是 Ingress 还是 Egress如果不写默认 Ingress 始终开启Egress 仅在配置了 egress 规则时开启ingress.from入站流量的来源白名单支持 4 种选择器egress.to出站流量的目标白名单支持 4 种选择器ports允许通过的端口和协议4 种选择器from/to 均可使用选择器作用示例podSelector选择同一命名空间内的特定 PodpodSelector: {matchLabels: {role: frontend}}namespaceSelector选择特定命名空间内的所有 Pod​namespaceSelector: {matchLabels: {project: myproject}}namespaceSelectorpodSelector选择特定命名空间内的特定 Pod见下方易错点ipBlock选择特定 IP CIDR 范围ipBlock: {cidr: 10.0.0.0/24}⚠️易错点namespaceSelector和podSelector在同一个from条目里是逻辑与在不同from条目里是逻辑或# 含义允许 useralice 命名空间下 roleclient 的 Pod ingress: - from: - namespaceSelector: matchLabels: user: alice podSelector: matchLabels: role: client # 含义允许本地命名空间 roleclient 的 Pod OR 任意命名空间 useralice 的 Pod ingress: - from: - namespaceSelector: matchLabels: user: alice - podSelector: matchLabels: role: client4.4 端口范围endPortKubernetes v1.25 支持用endPort指定连续端口范围 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: multi-port-egress namespace: default spec: podSelector: matchLabels: role: db policyTypes: - Egress egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP port: 32000 # 起始端口 endPort: 32768 # 结束端口含限制endPort≥port两者都必须是数字CNI 插件必须支持endPort字段否则只生效单个port4.5 Ingress 与 Egress 简易口诀方向判断口诀Ingress​ 写到被访问的 Pod​ 上控制谁能来找我Egress​ 写到主动发起请求的 Pod​ 上控制我能去找谁4.6 实战示例示例 1只允许带accesstrue标签的 Pod 访问 nginxapiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: access-nginx spec: podSelector: matchLabels: app: nginx ingress: - from: - podSelector: matchLabels: access: true示例 2数据库 Pod 出站白名单限制能访问的目标apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: db-egress-policy namespace: default spec: podSelector: matchLabels: role: db policyTypes: - Egress egress: - to: - ipBlock: cidr: 10.244.0.0/16 # 只允许访问集群内 Pod 网段 ports: - protocol: TCP port: 70 endPort: 90 # 端口范围 70-90示例 3默认拒绝所有流量零信任基线apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny namespace: default spec: podSelector: {} # 空 selector 选择所有 Pod policyTypes: - Ingress - Egress # 不写 ingress/egress 规则 全部拒绝⚠️注意配了 Egress 限制后必须放行 DNSUDP 53否则 Pod 内域名解析会失败egress: - to: - namespaceSelector: {} podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53示例 4为 Prometheus 监控组件配置网络策略参考 kube-prometheus-stack 官方的 NetworkPolicy 模板启用 admission webhook 时需要放行 443 端口ingress: - ports: - port: 443 # admission webhook 端口 - port: 8080 # 或 operator 的 HTTP 端口TLS 未启用时五、一键排障速查表症状最可能原因快速命令Helm 安装卡住/超时admission Job 镜像拉不到ghcr.io加--set prometheusOperator.admissionWebhooks.patch.image.registrydocker.ioPodImagePullBackOff节点缺镜像ctr -n k8s.io images ls \| grep 镜像名在对应节点上查CreateContainerError镜像损坏/内容层缺失在对应节点上ctr -n k8s.io images rm 镜像名→content gc→ 重新 importGrafana 能访问但数据源报错Prometheus Pod 没起来kubectl get pods \| grep prometheus所有 Pod 都 Running 但 Grafana 显示 No DataPrometheus 还没采集到数据等 1-2 分钟或检查 Prometheus Targets 页面