跳到主要内容

Kubernetes

将运维平台整套部署到被监控的 HAP/HDP Kubernetes 集群内部:Prometheus 通过 ServiceAccount 自动发现集群自身,无需 Token、无需 NodePort。

按以下步骤完成部署。各步骤已覆盖 Kubernetes 形态的完整部署流程。

采集 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
云托管集群应使用 PVC

云厂商的节点是可替换的——故障自愈、扩缩容、版本升级都会重建节点,而 hostPath 的数据不跟着 Pod 走。 丢 Prometheus 的 TSDB 会影响指标历史查询,ops-mongo 等于告警规则、通知渠道、数据源配置、慢查询历史全部丢失

下文以 PVC 为主线,hostPath 的差异之处在各步骤里单独标出。


第 1 步:拉取镜像

crictl pull nocoly/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 的 capacity

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"}}}'
单节点环境务必先调整 PVC 容量

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 style10-secret.yamlENV_S3_*第 4 步填
桶名30-stateful.yamlops-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_KEY32 位十六进制字符,用 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,默认值可直接用,需要时查环境变量

不要使用 shell heredoc 生成 Secret

kubectl create secret 或直接写 YAML。heredoc 转义可能把引号写入变量值,导致登录鉴权失败且排查困难。

hostPath 方案:不使用上述分文件清单,改为下载单一清单后按需修改——

⬇ 下载 ops.yaml

清单已包含全部组件(网关、Prometheus、Grafana、Loki、Tempo、Alloy、MongoDB、中间件 exporter、node-exporter)及其 Service 定义,命名空间为 hap-ops。下载后需要修改 ENV_OPS_TOKENENV_ALERT_CRYPTO_KEY、镜像 tag 与节点标签。

Kubernetes 面板随部署自动启用

清单已包含 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/
gateway 可先于 ops-mongo 启动

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。

Service 拆分原因

type: NodePort 会给该 Service 的每一个端口都分配 NodePort,把 8081(ops-server 内部 API, 仅应提供给集群内 Prometheus 做服务发现)也一起暴露出去。所以 UI 走 NodePort、内部 API 只走 ClusterIP。


第 7 步:验证

pip install playwright && playwright install chromium
python3 mdis_regression.py --base http://<节点IP>:30881 --token <ENV_OPS_TOKEN>

退出码 0 为全部通过。若某类中间件面板没有数据,优先查看 UI「数据源」页的采集状态列——悬停红色状态即显示失败原因,多数问题可直接通过状态原因定位。其余排查见常见问题


后续接入

运维平台部署完成后,继续接入被监控对象:

  • 数据源:登记主机与中间件,采集配置仅在 UI 中配置,不在 ConfigMap 里
  • Kubernetes 集群:采集节点/容器/集群对象状态
  • Node Exporter:监控集群外部的服务器(集群内节点已由 ops-nodeagent 覆盖)
  • 服务日志:让 HAP/HDP 微服务把日志推送到运维平台
  • 链路追踪:让业务上报调用链

附录 A:搭建测试集群

已有集群可跳过本附录。以下是在 Debian 12 上使用 kubeadm 创建测试集群的最小步骤,仅适用于测试环境参考,生产请以 Kubernetes 官方文档 为准。

# 1. 关 swap(kubelet 默认要求关闭 swap)
swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab

# 2. 内核模块与网络参数
cat > /etc/modules-load.d/k8s.conf <<'EOF'
overlay
br_netfilter
EOF
modprobe overlay && modprobe br_netfilter
cat > /etc/sysctl.d/k8s.conf <<'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system

# 3. containerd(务必开启 SystemdCgroup,否则 kubelet 会反复重启)
apt-get update && apt-get install -y containerd
mkdir -p /etc/containerd && containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd && systemctl enable containerd

# 4. kubeadm / kubelet / kubectl
apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key \
| gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' \
> /etc/apt/sources.list.d/kubernetes.list
apt-get update && apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

初始化控制面:

kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--image-repository registry.aliyuncs.com/google_containers

export KUBECONFIG=/etc/kubernetes/admin.conf
echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc
中国大陆环境需配置镜像源

kubeadm init 默认从 registry.k8s.io 拉控制面镜像,中国大陆访问受限,会表现为 kubeadm init 停留在 [preflight] Pulling images 后超时。必须带 --image-repository registry.aliyuncs.com/google_containerskubeadm config images pull 也要带同样的参数,否则预拉取同样失败。

安装 CNI(未安装时节点会持续处于 NotReady):

kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

单节点集群还需移除控制面污点,否则业务 Pod 无法调度:

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

验证:

kubectl get nodes # 应为 Ready
kubectl get pods -A # 应全部 Running

附录 B:多节点与专用监控节点

精简版与标准版用同一套清单,多节点集群需关注以下事项:

  1. 专用监控节点(可选):给节点打污点,并给各工作负载加容忍:
    kubectl taint nodes <节点名称> hap-ops=true:NoSchedule
    # spec.template.spec 下添加
    tolerations:
    - { key: "hap-ops", operator: "Equal", value: "true", effect: "NoSchedule" }
  2. 多套中间件采集:标准集群常有多套 mongo/kafka/es。无需部署多个 agent——1.3.0 起一个 ops-agent 即支持多目标(端口自动分配),在「数据源」页登记多个数据源即可。
  3. 节点指标ops-nodeagent 是 DaemonSet,自动覆盖所有节点,无需逐节点配置。如需监控集群外部的服务器,在目标服务器上单独部署 Node Exporter

附录 C:与单机部署的三处结构差异

以下三处为集群模式特有配置,不应直接复用单机 Compose 配置。

1. ops-agent 的 Service 必须是 headless(clusterIP: None

ops-agent 为每个数据源实例动态启动一个 exporter,端口动态分配:

mongodb → 19400, 19401, 19402 … 每多一个 MongoDB 实例就多一个端口
kafka → 19500, 19501 …
mysql → 19100 …

普通 ClusterIP Service 只转发 ports 里列出的端口,动态端口一律 connection refused, Prometheus 会把所有中间件 target 报成 DOWN。headless Service 的 DNS 直接解析到 Pod IP, 任意端口可直连,无需枚举。

2. 容器日志要靠 alloy-logs DaemonSet

ops-alloyROLE=alloy)通过 docker.sock 采集日志,而 Kubernetes 使用 containerd——它在 Kubernetes 下无法采集容器日志 (日志里会周期性出现 docker.sock 连接报错,属于预期提示,可忽略;它在 Kubernetes 下的作用是接收 OTLP)。 50-daemonsets.yaml 中的 alloy-logs 通过 Kubernetes API 读取 Pod 日志,用于 Kubernetes 场景的容器日志采集。

3. 有状态组件用 StatefulSet 而非 Deployment

Deployment 默认滚动更新会让新旧 Pod 同时挂载同一块盘(因此 hostPath 方案需设置 strategy: Recreate); StatefulSet 单副本天然「先删后建」,可避免该问题。