离线环境下基于 Argo CD 的 GitOps 监控栈交付方案 - 上
1.概述
1.1 目标
在 Argo CD 的 App of Apps 模式下,构建一套适用于生产环境的、可持续演进的可观测性 GitOps 交付体系。
这套体系不是简单“把监控装起来”,而是把监控栈、主动探测能力、Grafana 面板、环境配置和同步顺序统一纳入可审计、可回滚、可复用的交付流程中,并确保在离线或受限网络环境下仍然能够稳定部署。
重点解决以下问题:
用 App of Apps 统一管理整套监控栈:通过
root-app作为唯一入口,自动接管apps/目录下的各个子 Application,实现 kube-prometheus-stack、PostgreSQL Exporter、Blackbox Exporter、Grafana Dashboard、Probe 清单的统一编排。严格区分“一次性引导资源”和“持续 GitOps 接管资源”:
bootstrap/只保留root-app.yaml这一入口清单;Namespace、Secret、TLS 证书、镜像拉取凭证等敏感资源手工一次性创建,不进入 Git 仓库,不由 Argo CD 持续接管。确保生产环境可用性:镜像统一来自阿里云ACR私有仓库,CRD 依赖通过
sync-wave解决,Grafana、Prometheus、Exporter 等组件通过资源限制、Ingress、TLS、Secret、拉取凭证等配置完成生产化落地。保证离线/弱网环境可部署:Helm Chart 需要先本地化到
charts/,避免 Argo CD repo-server 依赖外部 Helm 仓库;Grafana Dashboard 采用 ConfigMap + sidecar 的离线注入方式,替代在线拉取社区仪表板。实现清晰的层次分工与可维护性:
apps/负责应用编排,charts/负责模板化打包,manifests/负责原生 Kubernetes 清单,values/负责环境差异化配置,所有层级职责清晰、边界明确。
本文的最终目标,不是把监控组件临时跑起来,而是建立一条从引导、编排、部署、验证到回滚都可追踪的 GitOps 交付链路,使整套可观测性系统具备生产化、可维护、可扩展和可审计的能力。
1.2 术语与缩写
术语 / 缩写 | 含义说明 |
GitOps | 以 Git 仓库为唯一事实来源,通过声明式配置驱动集群状态的运维方法论 |
App of Apps | Argo CD 的设计模式,父 Application 管理多个子 Application,实现分层编排 |
Sync-Wave | Argo CD 同步波次注解,数值越小越先同步,用于控制多应用的部署顺序 |
Bootstrap | 引导阶段,指一次性手工创建的集群基础资源,不由 GitOps 接管 |
CRD | 自定义资源定义(Custom Resource Definition),Prometheus Operator 安装时注册 |
ServiceMonitor | Prometheus Operator 提供的 CRD,声明式配置 Prometheus 如何抓取 Service 指标 |
Probe | Prometheus Operator 提供的 CRD,声明式配置 Blackbox Exporter 主动探测目标 |
ACR | 阿里云容器镜像服务(Alibaba Container Registry) |
SOP | 标准操作规程(Standard Operating Procedure) |
PVC | 持久卷声明(PersistentVolumeClaim),用于 Prometheus/Grafana 持久化存储 |
2. 前置条件与环境要求
2.1 基础设施要求
资源项目 | 配置 |
服务器规格 | 腾讯云 4C8G |
操作系统 | Ubuntu 24.04 LTS |
K3s 版本 | v1.35.4+ |
网络要求 | 可连通阿里云ACR仓库,如内网隔离需提前同步镜像 |
2.2 软件版本清单
软件 / 工具 | 版本要求 | 用途说明 |
kubectl | v1.35.4+ | 集群操作命令行工具 |
Helm | v4.1.4 | Chart 本地渲染与管理 |
Argo CD | v3.3.8 | GitOps 持续交付平台 |
kube-prometheus-stack | v84.5.0 | 核心监控栈 Prometheus Operator |
Grafana | v12.4.2 | 可视化仪表板 |
PostgreSQL Exporter | v0.19.1 | PostgreSQL 指标采集 |
Blackbox Exporter | v0.28.0 | HTTP/TCP 主动探测 |
2.3 账号与凭证准备
开始操作前,请确认以下凭证均已就绪:
● ACR(阿里云容器镜像仓库)的推送 / 拉取凭证(用户名和密码或 Token)
● 已注册域名(如 prometheus.example.com、grafana.example.com)及对应的 TLS 证书文件(tls.crt、tls.key)
● Grafana 管理员账号密码(自定义,用于初始化 Secret)
● PostgreSQL 数据库连接字符串: postgresql://<USER>:<PASSWORD>@<HOST>:5432/<DBNAME>?sslmode=disable
2.4 Git 仓库准备
● 在 GitHub / GitLab 或企业私有 Git 平台创建空仓库(示例仓库名:gitops-argocd)。
● 在 Argo CD 中添加仓库凭证:Settings → Repositories → Connect Repo(SSH 或 HTTPS 均可)。
● 确保 Argo CD 的 repo-server 可以访问该 Git 仓库(如内网部署,需配置 Git 代理或专线)。
3. 系统架构设计
3.1 整体架构说明
整个系统由以下6个层次组成:
层级 | 内容说明 |
bootstrap/ | 一次性引导入口 |
apps/ | Application 编排 |
charts/ | 本地化 Helm Chart |
values/ | 环境配置 |
manifests/ | 原生 Kubernetes 清单 |
argocd/ | Argo CD 自身安装与配置 |
Argo CD 管理:否,仅需手工执行一次
内容说明
这是 GitOps 的引导层,只保留一个root-app.yaml。该文件的作用是把整个apps/目录纳入 Argo CD 的管理范围,实现“用 GitOps 管理 GitOps”的闭环入口。特别说明
bootstrap 不承载 Namespace、Secret、TLS 等敏感资源,它单纯是一次性手工执行的引导器,完成之后所有后续资源交付都由 Argo CD 接管。
apps —— Application 编排层
Argo CD 管理:是(由 root-app 监听此目录)
内容说明
这里存放 Argo CD 的 Application 清单。root-app 会自动发现它们,并根据sync-wave控制同步顺序,统一编排kube-prometheus-stack、postgresql-exporter、blackbox-exporter、grafana-dashboards、blackbox-targets等子应用。特别说明
这是整套系统的应用入口,root-app 会自动纳管该目录下的所有子应用,形成统一的应用交付视图。
charts —— 本地化 Helm Chart 层
Argo CD 管理:是(子应用通过
path引用)内容说明
保存已经下载并解压到仓库中的 Helm Chart 目录。目的是让 Argo CD 在 repo-server 侧完全不依赖外部 Helm 仓库,在离线或弱网环境下依然可以正常渲染和部署。特别说明
Chart 代表应用模板本体,采用本地化管理后更稳定,适合进行版本化维护和审计。
manifests —— 原生 Kubernetes 清单层
Argo CD 管理:是(作为独立子应用管理)
内容说明
存放不需要 Helm 渲染的原生 Kubernetes 资源,例如 Grafana Dashboard 对应的 ConfigMap,以及 Blackbox Probe 对应的原生 CR。这些资源仍然受 GitOps 管理,但不走 Helm Chart 体系。特别说明
适合放置原生 CR 或无需模板化的静态清单,和 Helm 管理路径形成互补。
values —— 环境配置层
Argo CD 管理:是(随 Application 一起同步)
内容说明
存放各组件的 Helm values 覆盖文件,负责定义镜像地址、资源限制、Ingress、Secret 引用、存储规格等环境差异化配置。子应用通过引用这些 values 文件实现可重复、可审计的配置交付。特别说明
这是典型的“配置即代码”层,通常会随着环境差异和资源调优而频繁调整,但变更历史完整可追溯。
argocd —— Argo CD 自身安装与配置层
Argo CD 管理:手工管理
内容说明
主要用于 Argo CD 本体的安装参数和运行配置,不属于这套监控栈的业务工作负载层。它解决的是“Argo CD 自身怎么安装和运行”的问题。特别说明
这是平台层,不是监控栈业务层。与bootstrap/root-app.yaml角色完全不同:前者关注平台安装,后者关注 GitOps 闭环接入,两者不应混为一谈。
3.2 GitOps 仓库目录规范
标准仓库目录结构如下,每个目录的职责已明确划分:
仓库根目录
├── bootstrap/ # GitOps 引导层:只负责把 root-app 接入 Argo CD
│ └── root-app.yaml # 父应用清单;仅手工 apply 一次,后续由其接管 apps/ 目录
│
├── apps/ # Argo CD Application 编排层:所有子应用入口都放这里
│ ├── kube-prometheus-stack.yaml # 监控基础栈子应用,Wave 0;先安装 CRD 和 Prometheus/Grafana
│ ├── postgresql-exporter.yaml # PostgreSQL 指标采集子应用,Wave 1;依赖 Wave 0 的 CRD
│ ├── blackbox-exporter.yaml # Blackbox 主动探测引擎子应用,Wave 1;提供探测能力本体
│ ├── grafana-dashboards.yaml # Grafana 面板 ConfigMap 子应用,Wave 1;管理离线 Dashboard
│ └── blackbox-targets.yaml # 主动探测目标子应用,Wave 2;只管理 Probe CR,不混入 Exporter
│
├── charts/ # 本地化 Helm Chart 层:Chart 已下载并解压到仓库中
│ ├── blackbox-exporter/ # Blackbox Exporter Chart,本地渲染,不依赖外部 Helm 仓库
│ ├── kube-prometheus-stack/ # 监控主 Chart,包含 CRD/子 chart,支持离线部署
│ └── postgresql-exporter/ # PostgreSQL Exporter Chart,本地化后由 Argo CD 同步
│
├── values/ # 环境差异化配置层:镜像、资源、Ingress、Secret 引用等都在这里
│ ├── kube-prometheus-stack/ # 主监控栈 values 目录
│ │ └── values.yaml # 控制 Prometheus/Grafana/Alertmanager 等配置
│ ├── blackbox-exporter/ # Blackbox 引擎 values 目录
│ │ └── values.yaml # 只放模块配置、镜像、资源、拉取凭证
│ └── postgresql-exporter/ # PostgreSQL exporter values 目录
│ └── values.yaml # 数据源连接、SM/Rule、资源配置等
│
├── manifests/ # 原生 K8s 清单层:不经 Helm 渲染,但仍由 Argo CD 管理
│ ├── grafana-dashboards/ # Grafana Dashboard 对应的 ConfigMap 清单目录
│ │ ├── kustomization.yaml # 声明 configMapGenerator,固定名称 + 标签注解
│ │ ├── grafana-folder-config.yaml # 预创建 Folder(Databases, Networking 等)
│ │ └── dashboards/ # 清洗后的 Dashboard JSON
│ │ ├── postgresql-9628.json # PostgreSQL Dashboard JSON
│ │ └── blackbox-13659.json # Blackbox Exporter Dashboard JSON
│ └── blackbox-targets/ # Blackbox 主动探测目标的原生清单目录
│ └── probes.yaml # Probe CR:声明要监控的业务 URL,Wave 2 才下发
│
├── argocd/ # Argo CD 平台自身的安装与配置层
│ └── install/ # Argo CD 安装参数目录
│ └── values.yaml # Argo CD 自身部署配置
│
└── README.md # 仓库总说明:用于介绍结构、部署方式、使用方法3.3 App of Apps 核心原理
App of Apps 的本质,是用一个父 Application 统一生成和管理多个子 Application。
在本项目中,这个父应用就是
bootstrap/root-app.yaml它只需手工
kubectl apply一次,之后便由 Argo CD 持续接管apps/目录下的所有子应用换句话说,
root-app的职责不是直接部署 Prometheus、Grafana 或 Exporter,而是作为整套 GitOps 体系的“总入口”,负责把后续子应用纳入统一编排
这种模式的好处在于:父应用管入口,子应用管各自职责。
父应用只需要知道“有哪些 Application 需要被纳管”,而不需要知道每个应用具体怎么安装、用了什么 values、部署到哪个命名空间。真正的业务资源,例如:
kube-prometheus-stackpostgresql-exporterblackbox-exportergrafana-dashboardsblackbox-targets
分别由各自的子 Application 负责。这样设计以后,目录结构、职责边界和交付顺序都会非常清晰,后面排障、扩展或回滚也更容易。
从执行层面看,这种模式体现的是一种很实用的 GitOps 思路:
先把“声明”放进仓库,再由 Argo CD 把声明变成集群资源。
也就是说,Git 里存放的是“应该有什么”,Argo CD 负责把它变成“集群里真的有什么”。root-app 先发现 apps/ 下的子 Application,再由子 Application 去指向本地化 Chart、原生 manifests 和对应的 values 文件,从而完成具体工作负载的部署。
因此,本项目的整体链路可以概括为:
root-app 负责接入 GitOps 闭环 → apps/ 负责编排子应用 → charts/、manifests/、values/ 负责真正的资源定义。
这就是 App of Apps 的核心价值:
不是把所有 YAML 堆在一起,而是把“入口、编排、资源”分层管理,既能统一控制,又不会互相干扰。
3.4 同步顺序与 Sync-Wave 策略
在 App of Apps 模式下,同步顺序不是靠“谁先提交到 Git”决定的,而是靠 Argo CD 的 sync-wave 决定的。
sync-wave是 Argo CD 用来控制 Application 同步先后顺序的注解,数字越小,越先同步它不是 Kubernetes 原生的并行机制,而是 Argo CD 在应用层做的编排控制
对本项目来说这个机制非常关键,因为监控栈里存在明显的依赖关系:
先要有 CRD,后才能创建依赖这些 CRD 的资源;
先要有监控底座,后才能接入 exporter 和主动探测目标
本项目的同步策略划分为三层
Wave 0:kube-prometheus-stack
最先同步,因为它负责安装监控底座,尤其是 prometheus-operator 相关能力,并注册后续会用到的 CRD,例如 ServiceMonitor、PodMonitor、Probe、PrometheusRule 等。
只有这些 CRD 先存在,后面的 exporter 和 probe 清单才能被 Kubernetes 正确识别。
Wave 1:postgresql-exporter、blackbox-exporter、grafana-dashboards
在 Wave 0 已经把监控底座和 CRD 建好之后再同步。
postgresql-exporter会创建 ServiceMonitor 和 PrometheusRuleblackbox-exporter提供主动探测引擎本体grafana-dashboards则把离线 Dashboard 的 ConfigMap 注入集群,供 Grafana sidecar 发现和加载
它们都属于“底座就绪后才能顺利接入”的资源。
Wave 2:blackbox-targets
最后同步,因为它管理的是具体的主动探测目标,也就是 Probe CR。
文档里已经明确把 Probe 从 blackbox-exporter 中解耦出来,单独放到 manifests/blackbox-targets/probes.yaml,再由 apps/blackbox-targets.yaml 接管。
这样做的目的有两点:
避免资源归属冲突
确保主动探测目标在 exporter 和相关 CRD 都就绪后再下发
为什么要这么分波次
这套波次设计,其实对应的是一条非常标准的工程逻辑:
先装“底座” → 再装“采集器” → 再挂“业务目标”
如果顺序反过来,问题会很明显:
ServiceMonitor、Probe 这类资源可能会因为 CRD 未注册而创建失败
Blackbox 的目标如果提前混进 exporter 里,还会出现资源归属冲突,导致 Argo CD 长期 OutOfSync
所以,sync-wave 最简洁的理解方式是:
Wave 0 解决“能不能建监控基础”
Wave 1 解决“能不能接入指标和面板”
Wave 2 解决“能不能把业务主动探测目标安全地挂上去”
这种顺序保证了依赖先满足、资源不冲突、同步可控,最终形成一条稳定、可解释、可扩展的 GitOps 部署链路。
4. 环境引导阶段
4.1 创建命名空间
为监控组件和 Exporter 组件分别创建独立的命名空间,实现资源隔离:
# 创建监控栈命名空间(Prometheus、Grafana、Alertmanager 运行于此)
kubectl create ns monitoring
# 创建 Exporter 命名空间(PostgreSQL Exporter、Blackbox Exporter 运行于此)
kubectl create ns exporters
# 验证命名空间已创建
kubectl get ns monitoring exporters4.2 创建镜像拉取凭证(ACR Secret)
私有镜像仓库凭证需在每个会运行容器的命名空间中单独创建。从 阿里云ACR 控制台获取用户名和访问凭证(密码或 Token)后执行以下命令:
# 在 monitoring 命名空间创建镜像拉取 Secret
kubectl create secret docker-registry acr-secret \
--namespace=monitoring \
--docker-server=<ACR_REGISTRY> \
--docker-username=<ACR_USERNAME> \
--docker-password=<ACR_PASSWORD>
# 在 exporters 命名空间创建同名 Secret(名称必须与 values.yaml 中 imagePullSecrets 一致)
kubectl create secret docker-registry acr-secret \
--namespace=exporters \
--docker-server=<ACR_REGISTRY> \
--docker-username=<ACR_USERNAME> \
--docker-password=<ACR_PASSWORD>
# 验证 Secret 已创建
kubectl get secret acr-secret -n monitoring
kubectl get secret acr-secret -n exporters
注意:所有 <> 占位符必须替换为真实值。密码严禁以明文形式提交至任何 Git 仓库。
4.3 创建 Grafana 管理员密码 Secret
kubectl create secret generic grafana-admin-secret \
--namespace=monitoring \
--from-literal=admin-user=<ADMIN_USER> \
--from-literal=admin-password=<ADMIN_PASSWORD>4.4 上传 TLS 证书(Ingress HTTPS 所需)
# 为 Prometheus 创建 TLS Secret
kubectl create secret tls prometheus-tls \
--namespace=monitoring \
--cert=path/to/tls.crt \
--key=path/to/tls.key
# 为 Grafana 创建 TLS Secret
kubectl create secret tls grafana-tls \
--namespace=monitoring \
--cert=path/to/tls.crt \
--key=path/to/tls.key注意:TLS Secret 必须同时包含 tls.crt 和 tls.key,否则 Ingress TLS 规则不完整,HTTPS 访问将失败。
4.5 创建 PostgreSQL Exporter 数据源 Secret
PostgreSQL Exporter 通过该 Secret 获取数据库连接字符串,实现与目标库的连接:
kubectl create secret generic postgres-exporter-secret \
--namespace=exporters \
--from-literal=DATA_SOURCE_NAME="postgresql://<USER>:<PASSWORD>@<HOST>:5432/<DBNAME>?sslmode=disable"5. Helm Chart 本地化与离线部署
5.1 本地化策略说明
在内网隔离生产环境中,Argo CD 的 repo-server 通常无法直接访问外部 Helm 仓库。本文采用以下离线策略:
● 将所有依赖的 Helm Chart 提前下载到本地,解压后存入 Git 仓库的 charts/ 目录。
● Argo CD Application 的 source.path 直接指向 charts/ 目录,不配置任何外部 Helm 仓库地址。
● 所有镜像地址在 values.yaml 中覆盖为 ACR 私有仓库地址,部署时零外网依赖。
5.2 Chart 下载与本地化操作(以 kube-prometheus-stack 为例)
步骤 1 添加并更新 Helm 仓库
在可访问外网的机器上执行
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update步骤 2 查找目标 Chart 版本
确认 Prometheus Operator 版本与 Chart 版本的对应关系
# 查找包含 prometheusOperator 的 Chart 版本
helm search repo prometheus-community/kube-prometheus-stack --versions | head -5返回:
NAME CHART VERSION APP VERSION DESCRIPTION
prometheus-community/kube-prometheus-stack 84.5.0 v0.90.1 kube-prometheus-stack collects Kubernetes manif...
prometheus-community/kube-prometheus-stack 84.4.0 v0.90.1 kube-prometheus-stack collects Kubernetes manif...
prometheus-community/kube-prometheus-stack 84.3.0 v0.90.1 kube-prometheus-stack collects Kubernetes manif...
prometheus-community/kube-prometheus-stack 84.2.1 v0.90.1 kube-prometheus-stack collects Kubernetes manif...
prometheus-community/kube-prometheus-stack 84.2.0 v0.90.1 kube-prometheus-stack collects Kubernetes manif...步骤 3 下载并解压 Chart
将 Chart 解压到仓库的 charts/ 目录
# 下载并直接解压(--untar 参数)
helm pull prometheus-community/kube-prometheus-stack --version 84.5.0 --untar
mv kube-prometheus-stack charts/
# 验证子 chart 已完整解压(charts/ 目录不能为空)
ls -la ./charts/kube-prometheus-stack/charts/期望输出:grafana/ kube-state-metrics/ prometheus-node-exporter/
5.3 本地渲染验证
本地化完成后,必须在提交 Git 前执行一次完整的本地 Helm 渲染验证,确认 values 路径有效且无外网依赖:
# 模拟 Argo CD repo-server 的渲染过程
helm template test-release ./charts/kube-prometheus-stack \
--namespace monitoring \
--values ./values/kube-prometheus-stack/values.yaml \
--dry-run=client \
> /tmp/kps-rendered.yaml && echo "渲染成功" || echo "渲染失败,请检查 values 路径"5.4 镜像地址核查
渲染成功后,核查输出 YAML 中是否存在未重定向到 ACR 的镜像地址:
# 检查是否存在非 ACR 的镜像地址(将 ACR 域名替换为实际值)
grep -E "image:|repository:" /tmp/kps-rendered.yaml \
| grep -v "<ACR_REGISTRY_DOMAIN>" \
| grep -v "^#" \
| head -20如果上面命令有输出,说明仍有镜像未重定向,需要在 values.yaml 中补充对应的 registry/repository 配置
注意:如果核查命令有输出,说明存在未覆盖的默认镜像地址,在内网隔离环境下部署时这些镜像将拉取失败,导致 Pod 卡在 ImagePullBackOff 状态,必须逐一补充 values 覆盖配置。
6. 组件 Values 配置详解
本章给出各组件 values.yaml 的核心配置片段和关键注释说明。
6.1 kube-prometheus-stack
values/kube-prometheus-stack/values.yaml
# =============================================================================
# kube-prometheus-stack (Chart v84.5.0) 环境差异化配置
# =============================================================================
# 适用范围:腾讯云 4C8G Ubuntu 24.04,K3s v1.34+ 单节点集群
# 部署模式:Argo CD App of Apps,由 app/kube-prometheus-stack.yaml 引用
#
# 本文件的核心职责:
# 1. 将所有容器镜像重定向至阿里云 ACR 私有仓库(保证内网/离线可用)
# 2. 关闭 K3s 不暴露 Metrics 的组件,避免无效告警噪声
# 3. 配置 Prometheus 跨命名空间选择器,以便自动发现 exporters 命名空间的监控目标
# 4. 设置资源限制、持久化存储、Ingress TLS、Grafana 管理员凭证等生产化参数
# 5. 定义 Alertmanager 告警路由规则(静默低优先级告警,仅 Webhook 推送 critical 级别)
#
# ⚠️ 部署前请将 <ACR_REGISTRY>、<ACR_NAMESPACE> 替换为真实 ACR 地址与命名空间
# =============================================================================
# -----------------------------------------------------------------------------
# 全局配置
# -----------------------------------------------------------------------------
global:
# 镜像拉取凭证:所有由本 Chart 直接创建的 Pod(prometheusOperator、prometheus、
# alertmanager 等)均会自动挂载此 Secret,确保能从私有 ACR 拉取镜像。
# 注意:admissionWebhooks patch Job 不受 global 控制,须单独指定(见下文)。
imagePullSecrets:
- name: acr-secret
# -----------------------------------------------------------------------------
# 默认告警规则
# -----------------------------------------------------------------------------
defaultRules:
create: true # 启用 Prometheus Operator 内置的告警规则生成
# 针对 K3s 环境的规则裁剪:K3s 不暴露标准控制面组件的 Metrics 端点,
# 必须显式关闭对应规则,否则 Prometheus 会持续报错并产生大量无效告警。
rules:
alertmanager: true # Alertmanager 自身告警
etcd: false # K3s 使用嵌入式 etcd/SQLite,无独立端口
configReloaders: true
general: true
k8s: true
kubeApiserverAvailability: true
kubeApiserverBurnrate: true
kubeApiserverHistogram: true
kubeApiserverSlos: true
kubeControllerManager: false # K3s 不暴露 controller-manager metrics
kubelet: true
kubeProxy: false # K3s 使用 kube-router,无 kube-proxy
kubePrometheusGeneral: true
kubePrometheusNodeRecording: true
kubernetesApps: true
kubernetesResources: true
kubernetesStorage: true
kubernetesSystem: true
kubeSchedulerAlerting: false # K3s 不暴露 scheduler metrics
kubeSchedulerRecording: false
kubeStateMetrics: true
network: true
node: true
nodeExporterAlerting: true
nodeExporterRecording: true
prometheus: true
prometheusOperator: true
additionalRuleLabels: {} # 如需给所有规则附加额外标签,可在此添加
# -----------------------------------------------------------------------------
# K3s 不可用组件:完全关闭抓取端点,防止 Prometheus 无限重试
# -----------------------------------------------------------------------------
kubeEtcd:
enabled: false
kubeControllerManager:
enabled: false
kubeScheduler:
enabled: false
kubeProxy:
enabled: false
# CoreDNS:K3s 的 DNS 服务,需正确配置 service 的端口和选择器才能采集指标
coreDns:
enabled: true
service:
enabled: true
port: 9153 # CoreDNS metrics 端口
targetPort: 9153
selector:
k8s-app: kube-dns # K3s CoreDNS Pod 的标签
# kubelet 指标采集:使用 HTTPS 并跳过自签名证书验证(K3s 证书为自签)
kubelet:
enabled: true
serviceMonitor:
https: true
insecureSkipVerify: true # 唯一正确的跳过证书验证字段,勿用 tlsConfig
cAdvisor: true # 启用容器资源指标采集
proxyUrl: "" # K3s 无须代理
# =============================================================================
# Prometheus Operator 自身配置
# =============================================================================
prometheusOperator:
enabled: true
image:
registry: <ACR_REGISTRY> # 替换为 ACR 仓库地址,例如 registry.cn-hangzhou.aliyuncs.com
repository: <ACR_NAMESPACE>/prometheus-operator-prometheus-operator
tag: v0.90.1
pullPolicy: IfNotPresent
# 配置重载器:负责在 ConfigMap/Secret 变化时触发 Prometheus 重载
prometheusConfigReloader:
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/prometheus-operator-prometheus-config-reloader
tag: v0.90.1
resources:
requests:
cpu: 40m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
# Operator 自身资源限制
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1500Mi
# 准入 Webhook 配置:用于校验 PrometheusRule 等资源
admissionWebhooks:
enabled: true
patch:
enabled: true
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/jkroepke-kube-webhook-certgen
tag: "1.8.0"
pullPolicy: IfNotPresent
# 【关键】admissionWebhook patch Job 是独立的 Kubernetes Job,不受 Pod 级别
# global.imagePullSecrets 管控,因此必须在此单独声明镜像拉取凭证,
# 否则 Job 无法从私有仓库拉取镜像,会导致 Webhook 部署失败。
imagePullSecrets:
- name: acr-secret
resources:
requests:
cpu: 40m
memory: 128Mi
limits:
cpu: 300m
memory: 256Mi
ttlSecondsAfterFinished: 60 # Job 执行完毕 60 秒后自动清理
# =============================================================================
# Prometheus 实例配置
# =============================================================================
prometheus:
enabled: true
# Ingress:对外暴露 Prometheus Web UI(通过域名 + TLS)
ingress:
enabled: true
ingressClassName: traefik # K3s 内置 Traefik
annotations:
# 必须指定 entrypoints 和 TLS,否则 Traefik 无法正确路由 HTTPS 流量
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
hosts:
- prometheus.example.tech # 替换为实际域名
paths:
- /
pathType: Prefix
tls:
- secretName: prometheus-tls # 引用 bootstrap 阶段手工创建的 TLS Secret
hosts:
- prometheus.example.tech
# Prometheus 核心规格
prometheusSpec:
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/prometheus-prometheus
tag: v3.11.1
pullPolicy: IfNotPresent
replicas: 1 # 单副本,符合 K3s 单节点场景
resources:
requests:
cpu: 400m
memory: 512Mi
limits:
cpu: 1000m
memory: 1500Mi
# 数据保留策略
retention: 15d # 保留 15 天历史数据
retentionSize: "20GB" # 达到 20GB 上限后自动清理旧块,与 PVC 20Gi 对应
# 留约 2GiB 余量给 WAL (Write-Ahead-Log)
# 抓取和评估间隔
scrapeInterval: 30s
evaluationInterval: 30s
scrapeTimeout: 20s # 单次抓取超时,必须 < scrapeInterval (30s)
walCompression: true # 启用 WAL 压缩,降低磁盘 I/O,4C8G 环境推荐
# 【关键】跨命名空间选择器全开放
# 默认情况下 Prometheus 仅发现带有特定标签或同命名空间的监控资源。
# 以下配置将所有选择器置空,使 Prometheus 可以监控集群中任意命名空间的
# ServiceMonitor、PodMonitor、PrometheusRule 和 Probe 资源。
# 这是让 exporters 命名空间中的 PostgreSQL Exporter、Blackbox Exporter
# 能被采集的必要前提。
serviceMonitorSelectorNilUsesHelmValues: false
serviceMonitorSelector: {}
serviceMonitorNamespaceSelector: {}
podMonitorSelectorNilUsesHelmValues: false
podMonitorSelector: {}
podMonitorNamespaceSelector: {}
ruleSelectorNilUsesHelmValues: false
ruleSelector: {}
ruleNamespaceSelector: {}
probeSelectorNilUsesHelmValues: false
probeSelector: {}
probeNamespaceSelector: {}
# 持久化存储(PVC)
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: local-path # K3s 默认 StorageClass,无需额外安装 CSI
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
# 额外参数调优
additionalArgs:
- name: query.max-concurrency
value: "4" # 限制并发查询数,防止 OOM
- name: query.max-samples
value: "50000000" # 单次查询最大样本数,保护内存
# =============================================================================
# Alertmanager 配置
# =============================================================================
alertmanager:
enabled: true
ingress:
enabled: false # 告警管理界面不对外暴露,可通过 kubectl port-forward 访问
alertmanagerSpec:
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/prometheus-alertmanager
tag: v0.32.0
pullPolicy: IfNotPresent
replicas: 1
resources:
requests:
cpu: 80m
memory: 256Mi
limits:
cpu: 300m
memory: 600Mi
storage:
volumeClaimTemplate:
spec:
storageClassName: local-path
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
# 告警路由与接收器
config:
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'namespace', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
# 默认接收器为 null-receiver,所有非 critical 告警在此静默
receiver: 'null-receiver'
routes:
# Prometheus 自检心跳 Watchdog,始终 firing,路由到 null 避免干扰
- receiver: 'null-receiver'
matchers:
- alertname = "Watchdog"
# 高优先级告警抑制辅助信号 InfoInhibitor,同样静音
- receiver: 'null-receiver'
matchers:
- alertname = "InfoInhibitor"
# 仅 critical 级别告警通过 Webhook 发送(如钉钉机器人)
- receiver: 'critical-webhook'
matchers:
- severity = "critical"
continue: false
receivers:
- name: 'null-receiver'
# 空接收器,不发送任何通知
# 部署前必须将 url 替换为真实的 Webhook 服务地址
- name: 'critical-webhook'
webhook_configs:
- url: 'http://dingtalk-webhook.monitoring.svc.cluster.local:8060/dingtalk/robot1/send'
send_resolved: true # 告警恢复时也发送通知
# 抑制规则:当存在 critical 告警时,抑制同一 alertname + namespace 下的 warning/info
inhibit_rules:
- source_matchers:
- severity = "critical"
target_matchers:
- severity =~ "warning|info"
equal:
- alertname
- namespace
# =============================================================================
# Grafana 配置
# =============================================================================
grafana:
enabled: true
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/grafana-grafana
tag: "12.4.2"
pullPolicy: IfNotPresent
# 下载 Dashboard 时使用的 curl 镜像,替换为 ACR 私有镜像避免 GFW 拉取超时
downloadDashboardsImage:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/curlimages-curl
tag: "8.20.0"
pullPolicy: IfNotPresent
# 初始化文件权限的 busybox 镜像
initChownData:
enabled: true
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/busybox
tag: "1.37.0"
pullPolicy: IfNotPresent
# Sidecar 容器配置:负责自动发现并加载 Dashboard ConfigMap
sidecar:
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/kiwigrid-k8s-sidecar
tag: "2.6.0"
pullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 400m
memory: 400Mi
dashboards:
enabled: true
searchNamespace: ALL # 扫描所有命名空间
label: grafana_dashboard # 仅处理带此标签的 ConfigMap
labelValue: "1"
datasources:
enabled: true
searchNamespace: ALL
label: grafana_datasource
labelValue: "1"
# Dashboard 提供者:指定从本地文件路径加载 Dashboard
dashboardProviders:
dashboardproviders.yaml:
apiVersion: 1
providers:
- name: 'default'
orgId: 1
folder: ''
type: file
disableDeletion: false
editable: true
options:
path: /var/lib/grafana/dashboards/default
# Grafana 主容器资源限制
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 1500Mi
# 持久化存储
persistence:
enabled: true
storageClassName: local-path
accessModes:
- ReadWriteOnce
size: 5Gi
# 管理员凭证:引用 bootstrap 阶段手工创建的 Secret,避免明文出现在配置中
admin:
existingSecret: grafana-admin-secret
userKey: admin-user
passwordKey: admin-password
plugins: [] # 未安装额外插件
# Grafana 主配置
grafana.ini:
server:
root_url: https://grafana.example.com # 替换为实际域名
serve_from_sub_path: false
analytics:
check_for_updates: false # 内网环境禁用版本检查
reporting_enabled: false
users:
auto_assign_org_role: Viewer # 新用户默认只读
dashboards:
default_home_dashboard_path: ""
defaultDashboardsTimezone: "Asia/Shanghai"
defaultDashboardsEditable: false # 禁止在 UI 中修改 Dashboard,确保 Git 为唯一来源
# Grafana Ingress 配置
ingress:
enabled: true
ingressClassName: traefik
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
hosts:
- grafana.example.com
paths:
- /
pathType: Prefix
tls:
- secretName: grafana-tls # 引用 bootstrap 阶段创建的 TLS Secret
hosts:
- grafana.example.com
# =============================================================================
# Node Exporter 子 Chart 配置
# =============================================================================
prometheus-node-exporter:
enabled: true
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/prometheus-node-exporter
tag: v1.11.1
pullPolicy: IfNotPresent
resources:
requests:
cpu: 40m
memory: 128Mi
limits:
cpu: 400m
memory: 400Mi
hostRootFsMount:
enabled: true
mountPropagation: HostToContainer # 允许容器看到宿主机文件系统,采集节点指标必需
# =============================================================================
# Kube-State-Metrics 子 Chart 配置
# =============================================================================
kube-state-metrics:
enabled: true
image:
registry: <ACR_REGISTRY>
repository: <ACR_NAMESPACE>/kube-state-metrics-kube-state-metrics
tag: v2.18.0
pullPolicy: IfNotPresent
resources:
requests:
cpu: 40m
memory: 256Mi
limits:
cpu: 400m
memory: 800Mi
# 需要采集的资源类型(与 K3s 环境兼容)
collectors:
- certificatesigningrequests
- configmaps
- cronjobs
- daemonsets
- deployments
- endpoints
- horizontalpodautoscalers
- ingresses
- jobs
- leases
- limitranges
- namespaces
- nodes
- persistentvolumeclaims
- persistentvolumes
- pods
- replicasets
- resourcequotas
- secrets
- services
- statefulsets
- storageclasses6.1.1 全局镜像拉取凭证
作用范围:prometheusOperator、prometheus、alertmanager 等由本 Chart 直接管理的 Pod。
global:
imagePullSecrets:
- name: acr-secret6.1.2 K3s 环境不可用组件关闭
K3s 单节点架构中,以下控制面组件不暴露标准 Metrics 端口,必须关闭,否则 Prometheus 将产生大量无效告警噪声:
# K3s 使用 SQLite/etcd 内嵌,不暴露标准 etcd 端口
kubeEtcd:
enabled: false
# K3s 不暴露 controller-manager metrics
kubeControllerManager:
enabled: false
# K3s 不暴露 scheduler metrics
kubeScheduler:
enabled: false
# K3s 使用 kube-router,无标准 kube-proxy
kubeProxy:
enabled: false
6.1.3 Prometheus 选择器全开放
此配置是部署跨命名空间 ServiceMonitor(如 exporters 命名空间)的核心设置。不配置时,Prometheus 默认只发现含特定 label 的同命名空间资源:
prometheus:
prometheusSpec:
# 允许发现所有命名空间的 ServiceMonitor
serviceMonitorSelectorNilUsesHelmValues: false
serviceMonitorSelector: {}
serviceMonitorNamespaceSelector: {}
# 允许发现所有命名空间的 PodMonitor
podMonitorSelectorNilUsesHelmValues: false
podMonitorSelector: {}
podMonitorNamespaceSelector: {}
# 允许发现所有命名空间的 PrometheusRule
ruleSelectorNilUsesHelmValues: false
ruleSelector: {}
ruleNamespaceSelector: {}
# 允许发现所有命名空间的 Probe(Blackbox 主动探测)
probeSelectorNilUsesHelmValues: false
probeSelector: {}
probeNamespaceSelector: {}
6.1.4 Prometheus 资源配置与持久化存储
prometheus:
prometheusSpec:
replicas: 1
retention: 15d # 数据保留 15 天
retentionSize: "20GB" # 与 PVC 20Gi 对应,留约 2GiB 余量给 WAL
scrapeInterval: 30s
evaluationInterval: 30s
scrapeTimeout: 20s # 必须 < scrapeInterval,此处 20s < 30s ✓
walCompression: true # WAL 压缩,4C8G 环境推荐开启
resources:
requests:
cpu: 400m
memory: 512Mi
limits:
cpu: 1000m
memory: 1500Mi
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: local-path # K3s 默认 StorageClass
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 20Gi
6.1.5 admissionWebhooks 独立镜像拉取凭证
prometheusOperator:
admissionWebhooks:
patch:
imagePullSecrets:
- name: acr-secret # 必须单独声明,否则 Job 无法拉取私有镜像
6.1.6 Alertmanager 告警路由配置
alertmanager:
config:
route:
group_by: ["alertname", "namespace", "severity"]
receiver: "null-receiver" # 默认静音(非 critical 告警暂不通知)
routes:
- receiver: "null-receiver"
matchers: [alertname = "Watchdog"] # Prometheus 心跳信号,标准路由到 null
- receiver: "critical-webhook"
matchers: [severity = "critical"]
receivers:
- name: "null-receiver"
- name: "critical-webhook"
webhook_configs:
# ⚠ 部署前必须替换为真实 Webhook 地址(如钉钉机器人)
- url: 'http://dingtalk-webhook.monitoring.svc.cluster.local:8060/dingtalk/robot1/send'
send_resolved: true
6.1.7 Grafana 关键配置
grafana:
admin:
existingSecret: grafana-admin-secret # 引用 Bootstrap 阶段创建的 Secret
userKey: admin-user
passwordKey: admin-password
sidecar:
dashboards:
enabled: true
searchNamespace: ALL # 扫描所有命名空间中的 Dashboard ConfigMap
label: grafana_dashboard # 匹配此 Label 的 ConfigMap 自动注入面板
labelValue: "1"
persistence:
enabled: true
storageClassName: local-path
size: 5Gi
grafana.ini:
server:
root_url: https://grafana.example.com
analytics:
check_for_updates: false # 禁用外网版本检查,适合内网环境
reporting_enabled: false
defaultDashboardsTimezone: "Asia/Shanghai"
6.2 postgresql-exporter
values/postgresql-exporter/values.yaml
# =============================================================================
# PostgreSQL Exporter (Chart 本地化) 环境差异化配置
# =============================================================================
# 适用范围:腾讯云 4C8G Ubuntu 24.04,K3s v1.34+ 单节点集群
# 部署模式:Argo CD App of Apps,由 apps/postgresql-exporter.yaml 引用
# sync-wave:1(依赖 wave 0 的 kube-prometheus-stack 先注册 CRD)
#
# 本文件的核心职责:
# 1. 将 Prometheus PostgreSQL Exporter 的镜像重定向至阿里云 ACR(保证离线可用)
# 2. 通过 Kubernetes Secret 安全注入数据库连接字符串(避免明文写入 Git)
# 3. 创建 ServiceMonitor 以自动注册到 Prometheus 的抓取目标中
# 4. 定义数据库健康告警规则(PrometheusRule),覆盖连接状态、连接数、长事务
# 5. 设定合理的资源限制,防止 Exporter 在 4C8G 节点上 OOM 或过度占用 CPU
#
# 架构前提:
# - 本 Exporter 运行在 exporters 命名空间,监控的 Prometheus 位于 monitoring 命名空间
# - 跨命名空间采集已在 kube-prometheus-stack 的 values 中通过
# serviceMonitorNamespaceSelector: {} 等选择器全开放完成,此处无需额外配置
# - 数据库连接字符串存储在 Secret `postgres-exporter-secret` 中,
# 该 Secret 由 bootstrap 阶段手工创建,不入 Git 仓库
# =============================================================================
# -----------------------------------------------------------------------------
# 镜像配置
# -----------------------------------------------------------------------------
image:
# 镜像仓库地址:所有镜像统一从阿里云 ACR 私有仓库拉取,消除外网依赖
registry: <ACR_REGISTRY> # 替换为真实 ACR 地址,如 registry.cn-hangzhou.aliyuncs.com
repository: <ACR_NAMESPACE>/postgres-exporter
tag: v0.19.1
pullPolicy: IfNotPresent # 若本地已有镜像则不重复拉取,减少仓库压力
# 镜像拉取凭证:必须声明,否则 Kubelet 无法从私有 ACR 仓库拉取镜像,
# Pod 将卡在 ImagePullBackOff 状态。此 Secret 在 bootstrap 阶段手工创建。
imagePullSecrets:
- name: acr-secret
# 副本数:当前单节点 K3s 环境仅需 1 个实例,多副本需配合数据库连接池配置
replicaCount: 1
# -----------------------------------------------------------------------------
# Exporter 核心配置(数据源连接)
# -----------------------------------------------------------------------------
config:
# 【安全设计】数据库连接字符串不直接写在 values.yaml 中,而是通过已有 Secret 注入。
# 这样做的好处:
# 1. 密码、用户名等敏感信息不进入 Git 仓库,杜绝泄漏风险
# 2. Secret 内容可由运维人员在 bootstrap 阶段独立轮换,无需修改 GitOps 配置
# 3. Argo CD 不会接管此 Secret,避免了因 Git 变更意外覆盖凭证的问题
datasourceSecret:
name: postgres-exporter-secret # 引用 exporters 命名空间中的 Secret
key: DATA_SOURCE_NAME # Secret 中存放完整 PostgreSQL DSN 的键名
# DSN 格式示例:
# postgresql://user:password@host:5432/dbname?sslmode=disable
# -----------------------------------------------------------------------------
# 资源限制
# -----------------------------------------------------------------------------
# 基于 4C8G 单节点的保守设定,既保证 Exporter 稳定运行,又为其他组件留出资源空间。
# PostgreSQL Exporter 通常资源消耗很低,以下限制可满足上百个数据库实例的指标采集。
resources:
requests:
cpu: 20m # 最低保障,调度时确保节点至少有 0.02 核可用
memory: 64Mi # 最低保障内存
limits:
cpu: 200m # 突发上限,防止指标抓取高峰时占用过多 CPU 影响节点
memory: 256Mi # 硬限制,超过将触发 OOMKill,防止内存泄漏拖垮节点
# -----------------------------------------------------------------------------
# ServiceMonitor 配置:让 Prometheus 自动发现并抓取本 Exporter 的指标
# -----------------------------------------------------------------------------
serviceMonitor:
enabled: true
namespace: exporters # ServiceMonitor 资源本身创建在 exporters 命名空间
interval: 30s # 抓取间隔,应与 Prometheus 全局 scrapeInterval 匹配
scrapeTimeout: 20s # 单次抓取超时,必须 < interval
labels:
# 附加标签便于在 Prometheus 中筛选和分组
app.kubernetes.io/part-of: observability-stack
# 注意:此处无需配置 selector,因为 Chart 默认生成的 ServiceMonitor 会通过
# release 和 app 标签自动匹配本 Exporter 的 Service。
# -----------------------------------------------------------------------------
# PrometheusRule 配置:PostgreSQL 数据库健康告警规则
# -----------------------------------------------------------------------------
prometheusRule:
enabled: true
namespace: exporters # PrometheusRule 资源创建在 exporters 命名空间
labels:
app.kubernetes.io/part-of: observability-stack
rules:
# ── 规则 1:数据库不可达 ─────────────────────────────────────────────
- alert: PostgreSQLDown
# pg_up 是指标 prometheus.io 上 postgres_exporter 暴露的数据库存活状态,
# 0 表示不可达,1 表示正常。
expr: pg_up == 0
for: 1m # 持续 1 分钟才触发,避免网络瞬时抖动导致误报
labels:
severity: critical # 严重级别,会通过 Alertmanager 的 critical-webhook 发送通知
annotations:
summary: "PostgreSQL 不可达"
description: "postgres_exporter 无法连接 PostgreSQL"
# 补充说明:实际告警中会带有 instance 标签,指示具体哪个数据库实例。
# ── 规则 2:连接数过高 ─────────────────────────────────────────────
- alert: PostgreSQLTooManyConnections
# 计算当前活动连接数占最大连接数的比例,超过 80% 告警。
# pg_stat_activity_count 为当前连接数(按实例和数据库名分组),
# pg_settings_max_connections 为实例级别的最大连接数。
# 使用 / on(instance) group_left() 进行多对一匹配。
expr: |
sum(pg_stat_activity_count) by (instance, datname)
/ on(instance) group_left()
pg_settings_max_connections > 0.8
for: 5m # 持续 5 分钟,避免连接突增误报
labels:
severity: warning # 预警级别,默认不会推送通知(Alertmanager 仅推送 critical),
# 但会出现在 Prometheus 告警列表中供排查
annotations:
summary: "PostgreSQL 连接数过高"
description: "实例 {{ $labels.instance }} 库 {{ $labels.datname }} 连接数超过 80%"
# ── 规则 3:长事务检测 ─────────────────────────────────────────────
- alert: PostgreSQLLongRunningTransaction
# 监控最长的活跃事务持续时间(排除 template 库),超过 300 秒告警。
# pg_stat_activity_max_tx_duration 是 postgres_exporter 提供的指标,
# 表示当前数据库中运行时间最长的事务已持续的秒数。
expr: |
max(pg_stat_activity_max_tx_duration{datname!~"template.*"}) by (instance, datname) > 300
for: 5m
labels:
severity: warning
annotations:
summary: "PostgreSQL 存在长事务"
description: "数据库 {{ $labels.datname }} 存在超过 5 分钟的事务"
# 如有更多自定义规则(如复制延迟、死锁数等),可在此追加。
# 注意:PrometheusRule 中的 expr 表达式必须使用 postgres_exporter 实际暴露的指标名,
# 不同版本可能存在差异,部署后请通过 Prometheus UI 确认指标名称。
# =============================================================================
# 多数据库实例采集扩展说明
# =============================================================================
# 若需监控多个 PostgreSQL 实例,有以下推荐方式:
# 1. 在 Secret 的 DATA_SOURCE_NAME 中使用逗号分隔多个 DSN(需 Exporter 版本支持)。
# 2. 部署多个 postgresql-exporter 实例,每个实例使用独立的 Secret,并在 values 中
# 通过 releaseName 区分(需在 apps/postgresql-exporter.yaml 中定义多个 Application)。
# 3. 通过 config.datasource 块直接配置多目标(不推荐,会将连接字符串写入 Git)。
# 当前配置适用于单实例场景,扩展时请结合数据库连接池压力评估副本数。PostgreSQL Exporter 通过 Kubernetes Secret 获取数据库连接字符串,避免明文写入配置
6.3 blackbox-exporter
values/blackbox-exporter/values.yaml
# =============================================================================
# Blackbox Exporter (Chart 本地化) 环境差异化配置
# =============================================================================
# 适用范围:腾讯云 4C8G Ubuntu 24.04,K3s v1.34+ 单节点集群
# 部署模式:Argo CD App of Apps,由 apps/blackbox-exporter.yaml 引用
# sync-wave:1(依赖 wave 0 的 kube-prometheus-stack 先注册 Probe CRD)
#
# 本文件的核心职责:
# 1. 将 Blackbox Exporter 镜像重定向至阿里云 ACR(保证离线可用)
# 2. 强制固定 Service 名称为 "blackbox-exporter",使 Probe CR 中的 DNS 地址可解析
# 3. 定义探测模块(http_2xx、http_2xx_tls)作为“武器库”,供外部 Probe CR 引用
# 4. 开启自监控 ServiceMonitor,暴露 Exporter 自身运行指标
# 5. 严格禁止在此处添加探测目标——探测目标已解耦到独立的 blackbox-targets 应用
#
# ⚠️ 部署前请将 <ACR_REGISTRY>、<ACR_NAMESPACE> 替换为真实 ACR 地址与命名空间
# =============================================================================
# -----------------------------------------------------------------------------
# 【核心修复】Service 名称覆盖
# -----------------------------------------------------------------------------
# Helm 默认生成的 Service 名称是 "{releaseName}-{chartName}",形如
# "blackbox-exporter-prometheus-blackbox-exporter",这会导致 Probe CR 中
# 写死的 DNS 地址 "blackbox-exporter.exporters.svc:9115" 解析失败。
# 使用 fullnameOverride 强制覆盖为固定名称 "blackbox-exporter",确保所有
# 主动探测目标都能正确解析到 Exporter 的 Service。
fullnameOverride: "blackbox-exporter"
# -----------------------------------------------------------------------------
# 镜像配置
# -----------------------------------------------------------------------------
image:
registry: <ACR_REGISTRY> # 替换为真实 ACR 地址,如 registry.cn-hangzhou.aliyuncs.com
repository: <ACR_NAMESPACE>/prometheus-blackbox-exporter
tag: v0.28.0
pullPolicy: IfNotPresent # 如果节点上已有镜像则不重复拉取
# 镜像拉取凭证:必须声明,否则 Kubelet 无法从私有 ACR 拉取镜像。
# 此 Secret 在 bootstrap 阶段手工创建,不被 Argo CD 接管。
imagePullSecrets:
- name: acr-secret
# 副本数:单节点环境仅需 1 个实例。
# 多副本会带来多个 Exporter Pod 同时探测同一目标的问题,一般通过
# 部署多个独立的 Blackbox Exporter 实例来分散,此处保持单副本即可。
replicaCount: 1
# -----------------------------------------------------------------------------
# 资源限制
# -----------------------------------------------------------------------------
# Blackbox Exporter 本身是轻量级 HTTP/TCP 拨测工具,资源消耗极低。
# 以下限制在 4C8G 环境下留有充足余量。
resources:
requests:
cpu: 20m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
# -----------------------------------------------------------------------------
# 探测模块定义(武器库)
# -----------------------------------------------------------------------------
# 此处定义的模块是所有拨测的“能力集合”。外部 Probe CR 通过 spec.module 字段
# 引用这些模块名称(如 http_2xx 或 http_2xx_tls),从而获得特定的探测行为。
# 模块本身不指定探测目标,目标由独立的 Probe CR 提供,实现了能力与目标的解耦。
config:
modules:
# ── 模块 1:标准 HTTP 探测 ──────────────────────────────────────
http_2xx:
prober: http # 使用 HTTP 探测器
timeout: 10s # 单次探测超时,超时视为失败
http:
# 支持的 HTTP 版本,可同时接受 HTTP/1.1 和 HTTP/2.0
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
# 合法的 HTTP 状态码列表。空数组表示不进行状态码校验,任何
# 状态码(包括 4xx/5xx)都会被认为是“可达”,但是否成功由
# Prometheus 的 probe_success 指标表达(2xx 为成功)。
# 如需严格限制,可改为 [200, 301, 302] 等。
valid_status_codes: []
method: GET # 探测使用的 HTTP 方法
follow_redirects: true # 跟随重定向(最多 10 次)
# fail_if_ssl: 是否在目标没有 SSL 时失败,false 表示允许 HTTP
fail_if_ssl: false
# fail_if_not_ssl: 是否在目标没有 SSL 时失败,false 表示允许 HTTP
fail_if_not_ssl: false
# 优先使用 IPv4 地址,避免 IPv6 解析超时
preferred_ip_protocol: "ip4"
# ── 模块 2:严格 HTTPS 探测(含证书校验) ──────────────────────
http_2xx_tls:
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [] # 同样不校验状态码
method: GET
follow_redirects: true
# fail_if_ssl: false,允许目标从 HTTP 重定向到 HTTPS
fail_if_ssl: false
# fail_if_not_ssl: true,要求目标最终必须使用 HTTPS,
# 若重定向后仍是 HTTP 则探测失败
fail_if_not_ssl: true
tls_config:
# 不跳过证书校验:确保目标站点的 TLS 证书有效、未过期、
# 且与域名匹配。生产环境必须开启。
insecure_skip_verify: false
preferred_ip_protocol: "ip4"
# 如需扩展 TCP、ICMP 等探测,可在此继续添加模块,例如:
# tcp_connect:
# prober: tcp
# timeout: 5s
# tcp:
# preferred_ip_protocol: "ip4"
# -----------------------------------------------------------------------------
# ServiceMonitor:让 Prometheus 采集 Exporter 自身运行指标
# -----------------------------------------------------------------------------
# Blackbox Exporter 自身会暴露 /metrics 端点,包含如下重要指标:
# probe_success —— 探测结果(1 成功,0 失败)
# probe_duration_seconds —— 探测耗时
# probe_http_status_code —— HTTP 状态码
# 通过这些指标可以在 Prometheus 中绘制成功率、响应时间等面板。
serviceMonitor:
enabled: true
namespace: exporters # ServiceMonitor 资源创建在 exporters 命名空间
interval: 30s # 抓取间隔,与 Prometheus 全局 scrapeInterval 一致
scrapeTimeout: 20s # 必须 < interval,否则会触发 Prometheus 报错
labels:
app.kubernetes.io/part-of: observability-stack
# =============================================================================
# 【架构决策声明】探测目标(Probe CR)管理策略
# =============================================================================
#
# ⚠️ 重要:此处必须保持 probes: [] 不变,禁止在此添加探测目标条目
#
# 背景:
# 本 Chart 的 templates/probes.yaml 模板具备生成 Probe CR 的能力,
# 其渲染逻辑为 {{- range .Values.probes }},即遍历此处的列表。
# 但在本项目的 GitOps 架构中,所有 Probe CR 由独立子应用统一管理:
#
# 源文件: manifests/blackbox-targets/probes.yaml
# Argo CD App: apps/blackbox-targets.yaml(sync-wave: "2")
# Namespace: monitoring
#
# 为什么要解耦(不在这里配置探测目标)?
#
# 原因1 - 防止 Argo CD 资源归属冲突:
# 若此处定义 Probe,该 Probe 的 ownerApplication = blackbox-exporter;
# 若 manifests/ 里也有同名 Probe,ownerApplication = blackbox-targets;
# 两个 Application 会互相覆盖此资源,导致 Argo CD 永久 OutOfSync。
#
# 原因2 - 变更频率不同,职责分离:
# blackbox-exporter 是基础设施(很少变更);
# 探测目标是业务配置(随业务 URL 上线/下线频繁变更);
# 解耦后修改探测目标不会触发 blackbox-exporter Deployment 的 reconcile。
#
# 原因3 - sync-wave 顺序控制:
# blackbox-targets 在 wave 2 同步,确保 CRD 和 Exporter 都就绪后
# 再下发 Probe CR,顺序明确可控。
#
# ✅ 正确做法:如需新增/修改探测目标,编辑以下文件:
# manifests/blackbox-targets/probes.yaml
#
# ❌ 错误做法:在下方 probes: [] 处添加目标条目
# =============================================================================
probes: []配置项 | 说明 | 不配置的后果 |
fullnameOverride: "blackbox-exporter" | 强制覆盖 Helm 默认命名规则,确保 Service 名称严格为 blackbox-exporter | Probe CR 中的 URL 无法通过 DNS 解析到 Service,主动探测失败 |
imagePullSecrets | 声明私有 ACR 拉取凭证 | Pod 卡在 ImagePullBackOff,无法启动 |
probes: [] | 禁止在此处配置主动探测目标 | 与 manifests/blackbox-targets/ 中的 Probe CR 冲突,导致 Argo CD 永久 OutOfSync |
6.4 主动探测目标 Probe 配置
manifests/blackbox-targets/probes.yaml
# =============================================================================
# 主动探测目标清单(Probe CR)
# =============================================================================
# 适用范围:腾讯云 4C8G Ubuntu 24.04,K3s v1.34+ 单节点集群
# 管理方式:由 Argo CD 子应用 blackbox-targets 接管(apps/blackbox-targets.yaml)
# sync-wave:2(最后同步,确保 Blackbox Exporter 和 Probe CRD 均已就绪)
#
# 本文件的核心职责:
# 1. 声明需要对哪些外部/内部 URL 进行主动探测(HTTP/HTTPS/TCP 等)
# 2. 引用 blackbox-exporter 中定义的探测模块(如 http_2xx_tls)
# 3. 通过 namespace 和标签确保 Prometheus 能够发现并采集探测结果
# 4. 将探测目标与 Exporter 基础设施解耦,实现业务目标独立变更
#
# 架构前提:
# - Blackbox Exporter 的 Service 名称已通过 fullnameOverride 固定为
# "blackbox-exporter",因此 prober.url 使用固定的 DNS 名称
# - Prometheus 已在 kube-prometheus-stack 中配置 probeNamespaceSelector: {}
# 可发现任意命名空间的 Probe(本文件使用 monitoring 命名空间与 Prometheus 同 ns)
# - 探测模块(如 http_2xx_tls)已在 values/blackbox-exporter/values.yaml 中定义,
# 此处只负责“调用”模块,不重复定义探测逻辑
# =============================================================================
# Prometheus Operator 的 Probe CRD,表示一个主动探测任务
apiVersion: monitoring.coreos.com/v1
kind: Probe
metadata:
# Probe 的名称:建议采用 "<站点用途>-probes" 的命名规范,便于在 Prometheus
# 中通过标签筛选。此处 <YOUR-SITE-NAME> 需替换为实际业务标识,如
# "main-site-probes"、"api-gateway-probes"。
name: <YOUR-SITE-NAME>-probes
# 命名空间:与 Prometheus 实例处于同一命名空间(monitoring),
# 确保 Prometheus 在默认作用域内最优先发现,同时也避免了跨命名空间的
# RBAC 权限问题。如果部署在其他命名空间,需要确认 Prometheus 的
# probeNamespaceSelector 已配置为 {}(已在 kube-prometheus-stack 中完成)。
namespace: monitoring
labels:
# 附加此标签便于在 Prometheus 和 Grafana 中统一筛选所有观测组件
app.kubernetes.io/part-of: observability-stack
spec:
# ── 探测频率与超时 ──────────────────────────────────────────────
# interval:两次探测之间的间隔时间。60s 是生产环境常见值,既能及时发现故障,
# 又不会对被探测目标产生过大压力。
interval: 60s
# scrapeTimeout:单次探测的超时时间,必须小于 interval(30s < 60s),
# 否则 Prometheus 会报错 "scrape timeout greater than scrape interval"。
# 建议设置为比探测模块中的 timeout(http_2xx_tls 中为 10s)略大,
# 以包含网络往返和 Exporter 处理开销,但绝不能接近 interval。
scrapeTimeout: 30s
# ── 引用探测模块(武器库) ──────────────────────────────────────
# module 的值必须与 Blackbox Exporter 配置(values/blackbox-exporter/values.yaml)
# 中 config.modules 的某个键名完全一致。此处使用 http_2xx_tls,
# 该模块要求目标最终使用 HTTPS,并会验证 TLS 证书有效性(insecure_skip_verify: false)。
# 如需测试纯 HTTP 或 TCP 连接,可分别改为 http_2xx 或 tcp_connect。
module: http_2xx_tls
# ── 指定 Prober(执行探测的 Exporter 地址) ─────────────────────
prober:
# Blackbox Exporter 的 Kubernetes Service 内部 DNS 全限定名:
# <service-name>.<namespace>.svc:<port>
# 其中 "blackbox-exporter" 由 fullnameOverride 强制固定,端口 9115 是
# Blackbox Exporter 默认 metrics/探测端口。
# 如果 Service 名称或端口发生变化,此 URL 将解析失败,导致所有探测中断。
url: blackbox-exporter.exporters.svc:9115
# 探测请求的 URL 路径,Blackbox Exporter 的 HTTP 探测 API 固定为 /probe
path: /probe
# 与 Exporter 的通信协议,内部使用 HTTP 即可(不需要 TLS),
# 因为集群内 Pod 间通信受 CNI 隔离,不暴露于外部。
scheme: http
# ── 探测目标列表 ─────────────────────────────────────────────────
targets:
# 使用静态配置方式指定目标,适合固定 URL 的场景。
# 如果目标数量较多或动态变化,可考虑使用 Ingress 自动发现(staticConfig 的替代方案)。
staticConfig:
static:
# 每一行是一个完整的探测目标 URL,必须包含协议(http:// 或 https://)。
# 目标不需要是 /probe 路径,Blackbox Exporter 会通过 target 参数将 URL
# 传递给实际探测逻辑。请替换为真实业务地址。
- https://<YOUR-DOMAIN-1>
- https://<YOUR-DOMAIN-2>
# 可继续追加,例如:
# - https://api.example.com/health
# - https://www.example.com
# 若需基于 Kubernetes Ingress 自动生成目标,可使用 ingressConfig 代替 staticConfig,
# 但需要额外的 RBAC 权限,且目标 URL 会随 Ingress 变化自动更新。
# ingressConfig:
# selector:
# matchLabels:
# probe-target: "enabled"
# namespaceSelector:
# any: true主动探测目标(Probe CR)与 Exporter 基础设施解耦存放:
防止 Argo CD 资源归属冲突
探测目标变更频繁,解耦后修改不触发 Exporter Deployment 的 reconcile
sync-wave 顺序控制,确保 CRD 和 Exporter 就绪后再下发 Probe