审计发现 5 处硬伤(/metrics 空壳、零备份、prod 双副本数据分裂、零审计、资源偏紧),
本轮全部落地。
=== P0-1 真实 /metrics(原来是空壳)===
原实现只返回一行注释 `# LokiStack Metrics`,注释却写着"可被 Prometheus 抓取",
平台挂了/DB 写不进去/告警引擎卡死都只能靠用户反馈。
现接入 prometheus/client_golang,四层指标:
HTTP : lokistack_http_requests_total / _duration_seconds / _in_flight_requests
存储 : lokistack_db_size_bytes / _db_save_duration_seconds / _db_save_total / _db_records
业务 : lokistack_deployments{status,mode} / lokistack_collectors{status,type,run_mode}
后台任务: lokistack_alert_evaluations_total / _duration_seconds / lokistack_loki_queries_total
+ go_* / process_*(GoCollector、ProcessCollector)
关键点:path 标签用 c.FullPath() 路由模板,不用原始 URL —— 否则 117 个 Deployment
会把 Prometheus 基数炸掉。指标定义下沉 pkg/metrics 叶子包,避开
services ↔ repository 循环依赖。
=== P0-2 备份与恢复(原来 0 处代码)===
平台全部状态在 /app/data/opsxloki.json(51KB)+ kubeconfigs/ + known_hosts/,
DB 丢了 = 失去"这些资源是谁建的"的映射,从此无法管理/卸载/升级在跑的 Loki。
CLI : lokistack backup --output <path> / restore <pkg> / self-check / version
API : GET /system/backup(下载)/ POST /system/restore(校验暂存)/
POST /system/restore/apply(确认应用)/ GET /system/backups
K8s : kubernetes/pdb-backup.yaml —— 每日 03:30 CronJob,保留最近 7 份
安全设计:
- manifest.json 记录 ENCRYPTION_KEY 的 sha256 前 16 位**指纹**,用于恢复时
校验"这把钥匙能不能解开这份备份",不泄露密钥本身
- 恢复分两步(校验暂存 → 确认应用),应用前自动把当前 DB 备份为
opsxloki.json.before-restore.<时间戳>
- 包内不含明文密钥(kubeconfig 本就是加密态)
=== P0-3 prod compose 双副本 → 单副本 ===
lokistack-1 / lokistack-2 各挂独立数据卷 + nginx 轮询 = 数据分裂:
页面刷新两次可能看到不同结果,写操作只落一个副本。不是高可用。
已改单实例(nginx 仅做反代),文件顶部与 nginx.conf 都写明原因。
=== P0-4 操作审计日志(借鉴 /usr/local/src/aiops 的字段口径)===
aiops 是每个 controller 各写 recordXxxAudit();本平台有 60+ 写接口,
逐个埋点必然漏,漏掉的那个恰好最危险(删集群、改存储凭证)。
改为 **gin 中间件统一记录** + handler 通过 SetAudit 补充业务语义:
models/audit.go : 字段对齐 aiops,另加 Method/Path/Before/After
services/audit.go : 写入 + 90 天/2 万条自动裁剪 + 脱敏 + diff 生成
middleware/audit.go : 自动识别 module/action/resource,跳过只读接口
controllers/audit.go: 列表/详情/统计(仅 admin)
敏感字段(password/secretKey/privateKey/token)写入前统一替换为 ***。
=== P1 稳定性 ===
- 平台资源 1C/1Gi → 4C/4Gi 限(500m/512Mi 请求):JSON DB 全量读写 +
每分钟告警评估 + 批量发布并发,1Gi 会 OOM
- terminationGracePeriodSeconds: 30 —— 收到 SIGTERM 要等 DB 完整落盘,
否则 kubelet SIGKILL 会把 JSON 写一半(全库丢失)
- liveness timeoutSeconds 10s(默认 1s 写盘时会被误杀)
- PDB minAvailable: 0 —— 让 kubectl drain 正确等待重建,不卡维护
- DB schemaVersion + migrateSchema() 版本递进迁移(原先加字段全靠零值兜底)
- scripts/release.sh —— 不可变 tag <版本>-<日期>-<commit> + IfNotPresent,
根治 latest 并发构建互相覆盖导致的静默回滚(本项目已实际踩过)
- PVC 保持 30Gi(按长期增长预留,云盘单价低,不做在线扩容)
=== P2 易用性 ===
- 一键自检 GET /system/self-check + 仪表盘自检卡:真实探活 Loki /ready、
集群凭据解密、磁盘空间、主机状态、近 24h 失败操作
- 审计日志页 /audit:统计卡 + 用户名/模块/结果筛选 + 变更前后 diff 弹窗
- 菜单收敛 13 → 7(页内 tab 切换,URL 全部不变):
资源接入 = 集群 + 主机 + 存储
日志服务 = Loki 实例 + 采集器
日志 = 查询 + 分析
系统管理 = 用户 + 审计 + 设置
新增 GroupTabs 组件 + meta.group/groupKey,侧栏按分组去重并正确高亮
测试:go vet 通过、go test 全绿、tsc 通过
lokistack 部署到 Kubernetes
命名空间固定:log(日志相关资源统一放这里)
一条命令部署(推荐)
bash kubernetes/install.sh
脚本会依次完成:
- 创建
log命名空间 - 生成随机密钥
JWT_SECRET/ENCRYPTION_KEY写入 Secretlokistack-secrets(已存在则跳过,不会覆盖) - 创建 PVC
lokistack-data(30 GiB,使用集群默认 StorageClass) - 部署
lokistack(单副本 + Recreate) - 创建 Service
lokistack:8080(ClusterIP) - 等待 Pod 就绪并输出访问方式
需要 NodePort(配 ingress 时):
WITH_NODEPORT=1 bash kubernetes/install.sh
幂等性:重复执行只做增量更新,不会覆盖密钥、不会重建数据卷。
全部用法速查
| 场景 | 命令 |
|---|---|
| 标准部署(自动探测云平台 + StorageClass) | bash kubernetes/install.sh |
| 同时开 NodePort(配 ingress 用) | WITH_NODEPORT=1 bash kubernetes/install.sh |
| 指定 StorageClass | STORAGE_CLASS=cbs bash kubernetes/install.sh |
| 指定 SC(自建用 local-path) | STORAGE_CLASS=local-path bash kubernetes/install.sh |
| 自建集群强制用节点本地盘(hostPath) | LOCAL_STORAGE=force bash kubernetes/install.sh |
| 只诊断不动手(无变更) | LOCAL_STORAGE=off bash kubernetes/install.sh |
| 指定本地存储的节点/路径/容量 | NODE_NAME=node1 PV_PATH=/data/lokistack PV_SIZE=50Gi bash kubernetes/install.sh |
| 组合:自建 + 指定节点 + NodePort | LOCAL_STORAGE=force NODE_NAME=node1 WITH_NODEPORT=1 bash kubernetes/install.sh |
环境变量一览:
| 变量 | 默认值 | 说明 |
|---|---|---|
WITH_NODEPORT |
0 |
1 = 额外创建 NodePort Service(30080) |
STORAGE_CLASS |
空(自动探测) | 显式指定 StorageClass 名称 |
LOCAL_STORAGE |
auto |
auto 无 SC 时自动建本地 PV / off 只诊断 / force 强制本地盘 |
NODE_NAME |
空(第一个 Ready 节点) | hostPath PV 绑定的节点 |
PV_PATH |
/var/lib/lokistack-data |
hostPath 在宿主机上的路径 |
PV_SIZE |
30Gi |
PV 容量声明 |
环境要求
| 项 | 要求 |
|---|---|
| Kubernetes | 1.20+ |
| StorageClass | 脚本自动探测(default 注解 → 唯一 SC → 手动 STORAGE_CLASS=);自建集群无 SC 时会提前报错并给出解决方案,不会白等 |
| 镜像 | 节点可拉 lghost/lokistack:latest(或改成自己的 Harbor/ACR/TCR/SWR) |
| 权限 | 有 log 命名空间的 create/apply 权限 |
前置条件(install.sh 会自动检查,不通过直接给出具体修法)
脚本启动时做三级预检 + 一级软检查,任何一级不通过都会立即退出并打印「是哪一类问题、 下一步做什么」,不会跑到一半才报错:
| 预检项 | 不通过时的提示内容 |
|---|---|
| kubectl 是否安装 | 按 CentOS/TencentOS、Ubuntu/Debian、macOS 分别给安装命令;并给出「机器没有外网」时的替代方案(控制台下载 / 内网跳板机执行 / 只 scp 二进制) |
| kubeconfig 是否存在 | 打印实际查找路径($KUBECONFIG 或 ~/.kube/config),给出腾讯云 TKE / 阿里云 ACK / AWS EKS 各自下载 kubeconfig 的入口,以及 chmod 600 建议 |
| 能否连上 API Server | 按错误类型分类(见下表),不是笼统一句「请检查 kubeconfig」 |
| 部署权限(软检查) | kubectl auth can-i create deployments.apps -n <ns> 非 yes 时告警,提示绑定 Role 或改用管理员 kubeconfig;不阻断,避免首次部署时命名空间尚未创建导致误拦 |
连不上集群时的分类提示
| 实际错误 | 脚本的判断 | 给出的处理方向 |
|---|---|---|
current-context is not set / context does not exist |
kubeconfig 没有可用 context | kubectl config get-contexts → use-context → 重新下载 kubeconfig |
Unauthorized / Authentication required |
认证失败(云厂商 token 几小时就过期) | 回控制台重新下载 kubeconfig;自建集群查客户端证书 |
Forbidden / 403 |
已连上集群但 RBAC 拒绝 | kubectl auth whoami、auth can-i --list -n <ns>,列出部署所需的具体资源权限 |
x509 / certificate / tls: |
证书过期或域名不匹配 | 确认 API Server 证书;可信内网可临时 --insecure-skip-tls-verify 排障 |
connection refused / no such host / context deadline exceeded / i/o timeout |
网络不通 | ①curl -k <API>/version ②内网地址需 VPN/专线 ③安全组放行 6443 ④查集群状态 ⑤换成跳板机试 |
失败时的完整输出形如:
❌ 连不上集群 API Server(网络不通)
kubeconfig : /root/.kube/config
当前 context : tke-pre
API Server : https://172.19.16.13:443
当前用户 : admin
实际报错: Unable to connect to the server: context deadline exceeded (...)
── 按顺序排查 ───────────────────────────────────────────────────────
1) 地址对不对?用上面打印的 API Server 测一下: curl -k --max-time 5 <API Server>/version
2) 要不要 VPN / 专线?云上 API Server 常是内网地址(10.x / 172.16~31.x / 192.168.x)...
3) 安全组 / 防火墙:云厂商默认只放行运维网段访问 6443 端口
4) 集群本身是否正常:控制台看集群状态是否「运行中」
5) 换台机器试:在能访问集群的跳板机上执行本脚本,可排除本机网络问题
预检只读不写、耗时 < 1 秒。API Server 连接超时可用
KUBECTL_TIMEOUT=15s放宽(默认 8s)。
脚本自动处理什么
install.sh 不是无脑 apply,它会先探测环境再动手:
| 场景 | 脚本行为 |
|---|---|
| 云平台识别 | 读节点 providerID,识别出 腾讯云 TKE / AWS EKS / 阿里云 ACK / 华为云 CCE / GCP GKE / Azure AKS / K3s / 自建 |
| StorageClass | ① 显式 STORAGE_CLASS=xxx → ② is-default-class 注解 → ③ 集群唯一 SC → ④ 都没有则自动创建节点本地存储(静态 local PV,零外部依赖) |
| Secret | 不存在则用 openssl rand -hex 32 生成;已存在则跳过,绝不覆盖 |
| PVC | 把探测到的 SC 显式写进渲染后的 pvc.yaml(避免依赖隐式默认行为) |
| 就绪等待 | rollout status 最多 180s,超时后按失败原因分类诊断 |
| 镜像拉不到 | 诊断为 ImagePullBackOff 时,按云给出对应仓库格式(TCR / ACR / SWR / Harbor) |
| PVC 未绑定 | 诊断为 StorageClass 问题时,按云给出推荐 SC 名(cbs / gp3 / alicloud-disk-essd / csi-disk) |
脚本不做什么(需要人工决策的部分):
- ❌ 不自动改镜像仓库(不知道你的仓库地址,只给格式提示)
- ❌ 不覆盖已存在的 Secret / 已有数据卷
自建 K8s(kubeadm 裸装)的存储怎么办
自建集群最常见的坑就是没有 StorageClass → PVC 永久 Pending。脚本内置三种处理方式:
默认行为(LOCAL_STORAGE=auto):自动创建节点本地存储
检测到集群完全没有 SC 时,脚本自动创建一个静态 local PV:
StorageClass: lokistack-local
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer # 先定 Pod 再绑 PV
reclaimPolicy: Retain # 误删 PVC 不丢数据
PersistentVolume: lokistack-data-pv
hostPath: { path: /var/lib/lokistack-data, type: DirectoryOrCreate }
nodeAffinity: 锁定一台节点
特点:
| 优点 | 代价 |
|---|---|
| 零外部依赖(不拉任何镜像,国内网络友好) | 数据固定在单节点,Pod 不会漂移到别处 |
kubelet 自动建目录(DirectoryOrCreate) |
只能供给一个 PVC(单实例场景够用) |
Pod 一定调度到数据所在节点(nodeAffinity) |
节点损毁需从备份恢复(见「持久化」的 CSI 快照) |
实测数据:PVC 从 Pending 到 Bound 5 秒,Pod 正常读写宿主机目录。
想要动态供给(支持多 PVC / 多实例)
装 Rancher local-path-provisioner(自建集群事实标准):
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
STORAGE_CLASS=local-path bash kubernetes/install.sh
想先看着不动手(LOCAL_STORAGE=off)
LOCAL_STORAGE=off bash kubernetes/install.sh
只打印诊断和 4 种解法,不做任何变更。
自建 K8s 存储方案选型
| 方案 | 外部依赖 | 适用 | 备注 |
|---|---|---|---|
| 静态 local PV(本脚本默认) | 零 | 单副本、数据固定 | 最省事,国内网络友好 |
| local-path-provisioner | 2 个镜像 | 需要动态供给/多 PVC | 自建集群首选,社区标准 |
| OpenEBS LocalPV | Helm + 较多镜像 | 要 LVM/ZFS 精细控制 | 较重 |
| Longhorn | Helm,每节点装 | 需要副本/高可用 | 每节点约 1C2G 开销 |
| NFS + nfs-subdir-provisioner | 需现成 NFS 服务器 | 多节点共享 | 依赖外部 NFS |
对 lokistack 这类单副本 + JSON DB 单写者的应用,local PV 完全够用, 不需要为了"高可用"上 Longhorn —— 副本存储反而会和"单写者"约束冲突。
hostPath 数据的运维(自建集群必读)
自建集群用 hostPath 时,数据在宿主机目录里,不在云盘上。下面这些操作要会。
数据在哪
# 1) 找到 PV 绑定的节点和路径
kubectl get pv lokistack-data-pv -o custom-columns=\
'NAME:.metadata.name,PATH:.spec.hostPath.path,NODE:.spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].values[0]'
# 2) 去那台节点上看
NODE=<上面的 NODE 值>
ssh root@${NODE} 'ls -la /var/lib/lokistack-data/'
# 应看到:lokistack.json kubeconfigs/ known_hosts
备份(不用停机)
NODE=<节点>
TS=$(date +%Y%m%d-%H%M%S)
ssh root@${NODE} "tar czf /tmp/lokistack-backup-${TS}.tar.gz -C /var/lib lokistack-data"
scp root@${NODE}:/tmp/lokistack-backup-${TS}.tar.gz ./
lokistack.json写入是原子的(临时文件 + fsync + rename),热备份安全,不用停 Pod。
迁移到另一台节点
OLD=<旧节点> NEW=<新节点>
# 1) 停止写入
kubectl -n log scale deploy lokistack --replicas=0
# 2) 从旧节点拉取数据
ssh root@${OLD} 'tar czf - -C /var/lib lokistack-data' > /tmp/lokistack-data.tar.gz
# 3) 推到新节点并解包
scp /tmp/lokistack-data.tar.gz root@${NEW}:/tmp/
ssh root@${NEW} 'mkdir -p /var/lib && tar xzf /tmp/lokistack-data.tar.gz -C /var/lib && ls -la /var/lib/lokistack-data'
# 4) 改 PV 的 nodeAffinity 指向新节点
kubectl patch pv lokistack-data-pv --type=json -p \
"[{\"op\":\"replace\",\"path\":\"/spec/nodeAffinity/required/nodeSelectorTerms/0/matchExpressions/0/values\",\"value\":[\"${NEW}\"]}]"
# 5) 恢复
kubectl -n log scale deploy lokistack --replicas=1
kubectl -n log rollout status deploy/lokistack
卸载但保留数据
# 删工作负载和服务(数据卷保留)
kubectl -n log delete deploy lokistack svc lokistack
# PVC 保留(Retain 策略,删了也不会丢 PV 里的数据)
# 想彻底清掉的话:
# kubectl delete pvc lokistack-data
# kubectl delete pv lokistack-data-pv
# 然后去节点上 rm -rf /var/lib/lokistack-data
# 如果要连脏数据一起重置重装:
kubectl -n log delete pvc lokistack-data
kubectl delete pv lokistack-data-pv
kubectl delete sc lokistack-local
ssh root@${NODE} 'rm -rf /var/lib/lokistack-data'
# 然后重新 bash install.sh
常见坑
| 现象 | 原因 | 处理 |
|---|---|---|
| Pod 一直 Pending | PV 的 nodeAffinity 指向的节点不可用 | kubectl get nodes 确认该节点 Ready,或按上面「迁移」流程改节点 |
Pod Pending 且报 node(s) didn't match node affinity |
Pod 被调度到其他节点 | 正常,scheduler 会重试;若持续,检查 PV 的 nodeAffinity 是否写错节点名 |
| 换节点后数据"消失" | 数据在新节点上不存在 | 走「迁移到另一台节点」流程,别只改 nodeAffinity |
| 磁盘写满 | hostPath 用节点本地盘 | df -h /var/lib,迁移到大盘或改 PV_PATH |
目录结构
kubernetes/
├── install.sh # 一键部署脚本(推荐入口)
├── namespace.yaml # log 命名空间
├── pvc.yaml # 数据卷 30Gi(storageClassName 留空 → 用默认 SC)
├── deployment.yaml # 平台本体(单副本 + Recreate,必须)
├── service.yaml # ClusterIP lokistack:8080
├── service-nodeport.yaml # NodePort 30080(配 ingress 时用)
└── examples/ # 云相关配置,不参与默认部署
├── ingress.yaml # 阿里云 ACK(alb class)
├── ingress-tke.yaml # 腾讯云 TKE(qcloud class)
└── secret.example.yaml # Secret 模板(仅供手工创建参考)
⚠️
examples/里的文件故意不放在kubernetes/根目录: 它们是云厂商相关的(ingress class 各云不同),混在默认目录里会让kubectl apply -f kubernetes/在不同云上互相覆盖或报错。
手动部署(等价于 install.sh,供需要精细控制时用)
# 1) 命名空间
kubectl apply -f kubernetes/namespace.yaml
# 2) 密钥(⚠️ 必须先做,否则 Pod 起不来)
# 密钥只生成一次,丢失会导致已保存的凭证无法解密
kubectl -n log create secret generic lokistack-secrets \
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
--from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
# 3) 数据卷 + 平台 + 服务
kubectl apply -f kubernetes/pvc.yaml
kubectl apply -f kubernetes/deployment.yaml
kubectl apply -f kubernetes/service.yaml
# 4) 等待就绪
kubectl -n log rollout status deployment/lokistack --timeout=180s
❗不要直接
kubectl apply -f kubernetes/:Secret 不在目录里(密钥不能进 Git), 缺 Secret 时 Pod 会一直CreateContainerConfigError。
访问
临时(本地端口转发):
kubectl -n log port-forward svc/lokistack 8080:8080
# 浏览器打开 http://localhost:8080
初始账号:admin / admin123 ← 首次登录请立即改密
配 Ingress(可选)
以腾讯云 TKE 为例(其他云见 examples/):
# 1) 先开 NodePort(TKE 的 qcloud ingress 后端要求 NodePort 类型 Service)
WITH_NODEPORT=1 bash kubernetes/install.sh
# 2) 改域名后应用
vi kubernetes/examples/ingress-tke.yaml # 改 host
kubectl apply -f kubernetes/examples/ingress-tke.yaml
# 3) 查 CLB 分配的公网 IP,把域名解析过去
kubectl -n log get ingress lokistack
| 云 | ingressClassName | 备注 |
|---|---|---|
| 腾讯云 TKE | qcloud |
后端 Service 必须 NodePort |
| 阿里云 ACK | alb |
用 alb.ingress.kubernetes.io/* 注解 |
| AWS EKS | alb 或 nginx |
需装 AWS Load Balancer Controller |
| 华为云 CCE | nginx 或 cce |
— |
| 自建 | nginx |
需装 ingress-nginx |
持久化(重要)
/app/data挂 PVC,保存lokistack.json、kubeconfigs/、known_hosts。- 必须
replicas: 1+strategy: Recreate:JSON DB 是单写者;滚动更新时两个 Pod 同时挂同一个 RWO PVC 会互相覆盖。 - DB 写入本身是原子的(临时文件 + fsync + rename),容器被杀不会写坏文件。
备份:CSI VolumeSnapshot
各云都支持同一套 snapshot.storage.k8s.io API(AWS EBS / 腾讯 CBS / 华为 EVS / 阿里云 ESSD):
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: lokistack-data-20261025
namespace: log
spec:
volumeSnapshotClassName: <集群的 snapshotClass>
source:
persistentVolumeClaimName: lokistack-data
多云兼容
| 项 | 做法 |
|---|---|
| 存储类 | pvc.yaml 不写 storageClassName,用集群默认 SC;没有默认 SC 时填对应云的名字(AWS gp3 / 腾讯 cbs / 华为 csi-disk / 阿里云 alicloud-disk-essd) |
| 镜像仓库 | deployment.yaml 的 image 填目标云可拉的仓库(Harbor / ACR / TCR / SWR) |
| Loki 存储 | 平台已支持 S3 / OSS / COS / OBS,均 S3 兼容,无需云厂商 SDK |
| 查询链路 | 平台与 Loki 同集群时,数据源选「集群服务」(namespace log、service loki、port 3100),无需 Ingress/WAF |
| Namespace | 固定 log,跨云一致 |
与外部实例的关系
平台的 JSON DB 单写者,不要两个实例共用同一份数据卷。要么:
- 集群内新实例 + 迁移旧数据文件(停旧实例后拷贝);或
- 保留外部实例做带外管理,集群内实例使用独立数据卷(两套数据)。
日志
-
平台只写 stdout(Go/GIN 默认),不写日志文件;
kubectl logs可直接看。 -
Kubernetes 由 kubelet 统一轮转,节点级配置建议:
# /var/lib/kubelet/config.yaml containerLogMaxSize: 50Mi containerLogMaxFiles: 5 -
Loki / Promtail 同样输出到 stdout,由容器运行时轮转;不要在容器内写业务日志文件。
-
应用自身的部署日志写在 DB(
deployment_logs),可在部署详情里查看,不占容器日志空间。
常见问题
| 现象 | 原因 | 解决 |
|---|---|---|
Pod CreateContainerConfigError |
缺 Secret lokistack-secrets |
跑 install.sh,或手动 kubectl create secret |
Pod Pending,PVC Pending |
集群没有默认 StorageClass | pvc.yaml 里填 storageClassName |
Pod ImagePullBackOff |
节点拉不到 lghost/lokistack:latest |
换镜像地址(ACR/TCR/SWR/Harbor) |
kubectl apply -f kubernetes/ 报 ingress 错误 |
误把 examples 里的 ingress 一起 apply 了 | 只 apply 根目录的 yaml,ingress 单独处理 |
| 重启后数据丢失 | /app/data 没挂 PVC |
确认 deployment.yaml 的 volumeMounts |
| 两个 Pod 同时写 DB | 用了 RollingUpdate 或多副本 | 必须 replicas: 1 + strategy: Recreate |
集群凭证的最小权限(「资源」面板相关)
部署卡片上的「资源」按钮读的是部署目标集群的用量。平台里登记集群的 kubeconfig/token 可以是最小权限,只需下面几条:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: lokistack-viewer
namespace: log # 只授 Loki 所在的命名空间即可
rules:
# 读 StatefulSet 的 requests/limits
- apiGroups: ["apps"]
resources: ["statefulsets"]
verbs: ["get"]
# 读 Pod 就绪状态、重启次数
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# 读实时 CPU/内存用量(metrics-server 的 API 组,常被漏授)
- apiGroups: ["metrics.k8s.io"]
resources: ["pods"]
verbs: ["get", "list"]
⚠️
metrics.k8s.io是独立 API 组,很多「只读」ClusterRole(如内置view)在国内云 的 TKE/ACK 上并不包含它。缺这一条时:
- 页面不会报错,仍显示 limits、就绪状态、重启次数;
- 实时用量区域会提示「当前集群凭证缺少 metrics.k8s.io 权限」并给出需要补的规则;
- 补授后无需重启平台,刷新弹框即可看到用量。
集群若没装 metrics-server(kubectl top 报 Metrics API not available),
提示会变成「集群未安装 metrics-server」。
非 Kubernetes 部署
| 模式 | 采集方式 | 能力 |
|---|---|---|
host-docker(docker / docker-compose) |
SSH 到主机执行 docker stats --no-stream + docker inspect |
实时 CPU/内存、限额(若 docker run --memory/--cpus 有设)、重启次数 |
host-binary(裸进程) |
SSH 执行 ps 采集进程 CPU%/RSS |
仅实时占用(无 cgroup 限额,无峰值) |
Docker 模式下若容器没有设置 --memory / --cpus,页面会显示「未配置资源限额」,
容量参考值是宿主机内存(docker stats 的上限列),此时没有百分比可用于判断扩容。