Kubernetes
将运维平台整套部署到被监控的 HAP/HDP Kubernetes 集群内部:Prometheus 通过 ServiceAccount 自动发现集群自身,无需 Token、无需 NodePort。
按以下步骤完成部署。各步骤已覆盖 Kubernetes 形态的完整部署流程。
若运维平台部署在集群外,则只能监控主机与中间件,无法直接采集 Kubernetes 自身的节点/Pod/Deployment 指标(1.5.3 起已移除集群外采集方式)。
开始之前
需要准备
- 一套已正常运行的 HAP/HDP 集群
- 被监控的中间件(MongoDB/MySQL/Redis/Kafka/Elasticsearch,按实际部署)可从集群内访问,账号已按 部署总览 准备好只读权限
- Flink 是可选项,未部署时留空。
kubectl可操作目标集群;如尚未准备集群,见 附录 A:搭建测试集群
⬇ 下载 k8s-cluster.tar.gz(解压得到下列文件):
00-namespace.yaml 11-configmap.yaml 30-stateful.yaml 50-daemonsets.yaml
10-secret.yaml.example 20-rbac.yaml 40-stateless.yaml
确定数据持久化方式
有状态组件(Prometheus/Grafana/ops-mongo)的数据要持久化,两种方式二选一,直接决定第 2 步怎么做:
| PVC(默认,推荐) | hostPath(备选) | |
|---|---|---|
| 数据落在 | 存储卷,节点重建不丢 | 某个节点的本地目录 |
| 用哪套清单 | k8s-cluster/ 分文件清单 | 单个 ops.yaml |
| 前提 | 集群有默认 StorageClass | 无,但要固定节点 |
| 适合 | 云托管集群(TKE/ACK/EKS)、生产环境 | 节点固定的自建集群、没有可用 StorageClass |
云厂商的节点是可替换的——故障自愈、扩缩容、版本升级都会重建节点,而 hostPath 的数据不跟着 Pod 走。
丢 Prometheus 的 TSDB 会影响指标历史查询,丢 ops-mongo 等于告警规则、通知渠道、数据源配置、慢查询历史全部丢失。
下文以 PVC 为主线,hostPath 的差异之处在各步骤里单独标出。
第 1 步:拉取镜像
crictl pull registry.cn-hangzhou.aliyuncs.com/mdpublic/ops-allinone:1.5.7
ops-nodeagent 以 DaemonSet 运行,集群每个节点都要有这个镜像。离线环境见 离线包下载。
镜像在阿里云杭州(registry.cn-hangzhou.aliyuncs.com),海外集群拉 2.16GB 可能十几分钟,且各节点耗时不一致。
某个节点卡住时,可以 kubectl cordon 该节点并删掉其上的非 DaemonSet Pod,使其重新调度到已有镜像缓存的节点
(DaemonSet 仍需等待各节点完成镜像拉取)。海外部署建议先把镜像同步到就近的镜像仓库。
第 2 步:准备持久化
PVC(推荐)
集群必须有默认 StorageClass。检查:
kubectl get sc
输出中应有一个带 (default) 标记的 StorageClass。若不存在,可按以下两种情况创建。
云托管集群(TKE/ACK/EKS)
云厂商通常已提供默认 StorageClass,但建议创建一个支持在线扩容的 StorageClass。PVC 创建后再修改 StorageClass 通常需要重建云盘。腾讯云 TKE 示例:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: cbs-expandable
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: com.tencent.cloud.csi.cbs
parameters:
diskType: CLOUD_PREMIUM # 显式声明;TKE 默认 SC 常写 `type: cbs`,那是无效参数,靠驱动默认值兜底
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true # TKE 默认 SC 通常未开启该开关;驱动支持在线扩容
创建后取消原默认 StorageClass 的默认标记,避免同时存在两个默认 StorageClass:
kubectl patch sc <原默认SC名> -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
PVC.status.capacity 只在第二阶段(节点上 resize2fs)完成后才更新,而第二阶段必须有 Pod 挂载。
没有 Pod 挂载的 PVC 会停留在旧值,condition 显示 FileSystemResizePending——这不表示扩容失败,云盘通常已经完成扩容。
自建/单节点测试集群
没有云盘时可使用 local-path-provisioner,数据落在节点本地目录:
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
kubectl patch sc local-path -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
30-stateful.yaml 默认申请 prometheus 100Gi + ops-mongo 20Gi + grafana 10Gi = 130Gi,按生产集群容量预设。
local-path-provisioner 不校验磁盘剩余空间,PVC 会正常 Bound,Prometheus 写满后才会报
no space left on device——届时容易误判为服务异常。测试机磁盘通常只有 100G 左右,apply 之前需先调整:
# 30-stateful.yaml,三处 volumeClaimTemplates
resources:
requests:
storage: 20Gi # ops-prometheus,测试环境
# storage: 5Gi # ops-mongo
# storage: 5Gi # ops-grafana
另外 local-path 不支持在线扩容,改大只能重建 PVC。生产环境请用支持 allowVolumeExpansion 的云盘 SC。
hostPath(备选)
不使用 StorageClass,改为把有状态组件固定到某个节点、数据落在该节点本地磁盘。给这个节点打标签:
kubectl label node <节点名称> hap-ops=true
kubectl get node -o wide查看节点名。数据目录统一在该节点的/data/mdis/下(prometheus/grafana/loki/tempo/mongo 各一个子目录)。
第 3 步:准备对象存储(可选)
日志(Loki)与链路(Tempo)默认写在本地卷里。要让它们长期留存、不受单节点磁盘限制,就准备对象存储——需要两个桶:
| 桶 | 用途 | 建议名 |
|---|---|---|
| 日志 | Loki 块存储 | mdis-loki |
| 链路 | Tempo 块存储 | mdis-tempo |
两处配置,配置位置需区分:
| 配的什么 | 配在哪 | 说明 |
|---|---|---|
| endpoint、AK/SK、path style | 10-secret.yaml 的 ENV_S3_* | 第 4 步填 |
| 桶名 | 30-stateful.yaml 里 ops-loki/ops-tempo 各自的 ENV_S3_BUCKET_LOKI/ENV_S3_BUCKET_TEMPO | 清单里已预置上表两个名字,按此建桶就不用改 |
⚠️ 两个组件必须用不同的桶。若只设通用的 ENV_S3_BUCKET,Loki 和 Tempo 会落进同一个桶、
目录结构互相覆盖(启动日志会打警告)。各家云的 endpoint 写法与兼容性说明见 对象存储。
如无长期留存要求,可跳过本步骤,后续按需补配。
第 4 步:填写配置
# 1. 命名空间
kubectl apply -f 00-namespace.yaml
# 2. Secret:拷贝 example 后填写
cp 10-secret.yaml.example 10-secret.yaml
10-secret.yaml 里必填这两项:
| 变量 | 说明 |
|---|---|
ENV_OPS_TOKEN | 登录令牌,自定义一个强随机串 |
ENV_ALERT_CRYPTO_KEY | 32 位十六进制字符,用 openssl rand -hex 16 生成 |
如第 3 步已准备对象存储,再补填 ENV_S3_ENDPOINT/ENV_S3_ACCESS_KEY/ENV_S3_SECRET_KEY/ENV_S3_FORCE_PATH_STYLE(桶名在上一步配置)。
kubectl apply -f 10-secret.yaml
其余可调项(数据保留时长、组件地址等)在 11-configmap.yaml,默认值可直接用,需要时查环境变量。
用 kubectl create secret 或直接写 YAML。heredoc 转义可能把引号写入变量值,导致登录鉴权失败且排查困难。
hostPath 方案:不使用上述分文件清单,改为下载单一清单后按需修改——
清单已包含全部组件(网关、Prometheus、Grafana、Loki、Tempo、Alloy、MongoDB、中间件 exporter、node-exporter)及其 Service 定义,命名空间为 hap-ops。下载后需要修改 ENV_OPS_TOKEN、ENV_ALERT_CRYPTO_KEY、镜像 tag 与节点标签。
清单已包含 Prometheus 的 ServiceAccount/ClusterRole 与 kube-state-metrics,运维平台运行在 被监控集群内,部署完成后即可采集本集群,与 PVC 方案行为一致。
不要额外部署 k8s-addons。该组件用于「运维平台在被监控集群之外」的采集场景,会另建
一个命名空间与本清单并存。仅当需要使用当前运维平台纳管其它集群时才需要它,见
Kubernetes 集群监控。
v1.5.7 之前的清单 未包含 RBAC 与 kube-state-metrics(部署后 Kubernetes 面板无数据),从旧版本升上来 重新下载并覆盖 apply 即可。
第 5 步:启动
kubectl apply -f 11-configmap.yaml -f 20-rbac.yaml \
-f 30-stateful.yaml -f 40-stateless.yaml -f 50-daemonsets.yaml
# 等待就绪(首次需拉取 2.16GB 镜像,跨境网络可能需要十几分钟)
kubectl get pods -n hap-ops -w
hostPath 方案:
kubectl apply -f ops.yaml(清单自带hap-ops命名空间),停止时执行kubectl delete -f ops.yaml。两种方案的命名空间均为hap-ops,后续验证命令通用。
全部 Running 后,确认告警子系统已挂载:
kubectl logs deploy/ops-gateway -n hap-ops | grep 告警子系统
# 期望:[alert] 告警子系统已挂载 /api/alert/
Kubernetes 没有 compose 的 depends_on,镜像拉取耗时不一致时,gateway 可能先进入 Running 状态。1.4.5 起 ops-server
连不上 ops-mongo 会在后台按 3s/6s/12s 退避重试,mongo 就绪后自动挂载告警子系统,无需手动重启。
最终出现上述日志即表示告警子系统挂载成功。
第 6 步:对外暴露并访问
ops-gateway-ui 以 NodePort 30881 暴露,集群外用 nginx 反代:
upstream hap-ops {
server <node1>:30881 max_fails=0;
server <node2>:30881 max_fails=0;
server <node3>:30881 max_fails=0;
}
location /mdis/ {
allow <运维出口IP>;
deny all;
proxy_pass http://hap-ops;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
ConfigMap 里 ENV_OPS_SUB_PATH=/mdis,所以 /mdis/ 原样透传即可,不需要 rewrite。访问 https://域名/mdis/web/,登录 Token 为 ENV_OPS_TOKEN。
安全边界 = IP 白名单 + 运维平台自身的 32 位 Token + 会话 Cookie,无需额外叠加 Basic Auth。
type: NodePort 会给该 Service 的每一个端口都分配 NodePort,把 8081(ops-server 内部 API,
仅应提供给集群内 Prometheus 做服务发现)也一起暴露出去。所以 UI 走 NodePort、内部 API 只走 ClusterIP。