feat: K8s 部署清单、Token 接入加固与日志/设置页优化
- kubernetes/: 30Gi PVC、单副本 Recreate、Secret/Service/NodePort/Ingress 清单与部署文档 - 数据安全: kubeconfig/token 统一加密存储,启动迁移历史明文,DB 0600 - Token 接入: 命名空间级最小权限提示、长期 Token、自签证书 TLS 兼容 - 部署: 命名空间级 Token 下跳过 Namespace patch/枚举,节点信息容错 - 日志页: namespace → app → pod 选择顺序与作用域收窄 - 设置页: 拆分为通用/告警/LDAP/镜像源四个 tab - 弹框: 统一 max-h 滚动与长命令换行,修复内容溢出
This commit is contained in:
1 parent
2d73661dd1
commit
9f7c522157
50 files changed
+1346
-149
No files matched your search
@@ -0,0 +1,79 @@
|
||||
# opsx-loki 部署到 Kubernetes
|
||||
|
||||
## 文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `namespace.yaml` | `log` 命名空间(已有可跳过) |
|
||||
| `secret.example.yaml` | JWT/ENCRYPTION 密钥模板(建议用 `kubectl create secret` 命令创建,不要提交真实值) |
|
||||
| `pvc.yaml` | 平台数据卷(30Gi,默认 StorageClass) |
|
||||
| `deployment.yaml` | 平台本体,**单副本 + Recreate** |
|
||||
| `service.yaml` | ClusterIP `opsx-loki:8080` |
|
||||
| `ingress.yaml` | 可选,按云厂商的 ingressClass 调整 |
|
||||
|
||||
## 部署步骤
|
||||
|
||||
```bash
|
||||
# 1) 密钥(只生成一次,之后复用;丢失会导致已保存的凭证无法解密)
|
||||
kubectl -n log create secret generic opsxloki-secrets \
|
||||
--from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
||||
--from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||
|
||||
# 2) 数据卷 + 平台
|
||||
kubectl apply -f kubernetes/namespace.yaml
|
||||
kubectl apply -f kubernetes/pvc.yaml
|
||||
# 修改 deployment.yaml 里的 image 为实际仓库地址后:
|
||||
kubectl apply -f kubernetes/deployment.yaml
|
||||
kubectl apply -f kubernetes/service.yaml
|
||||
|
||||
# 3) 可选:Ingress(不需要就跳过,继续走外部 WAF 回源)
|
||||
kubectl apply -f kubernetes/ingress.yaml
|
||||
```
|
||||
|
||||
## 持久化(重要)
|
||||
|
||||
- `/app/data` 挂 PVC,保存 `opsxloki.json`、`kubeconfigs/`、`known_hosts`。
|
||||
- **必须 `replicas: 1` + `strategy: Recreate`**:JSON DB 是单写者;滚动更新时两个 Pod 同时挂同一个 RWO PVC 会互相覆盖。
|
||||
- DB 写入本身是原子的(临时文件 + fsync + rename),容器被杀不会写坏文件。
|
||||
- 备份建议用 CSI VolumeSnapshot(AWS EBS / 腾讯 CBS / 华为 EVS / 阿里云 ESSD 都支持同一套 `snapshot.storage.k8s.io` API):
|
||||
|
||||
```yaml
|
||||
apiVersion: snapshot.storage.k8s.io/v1
|
||||
kind: VolumeSnapshot
|
||||
metadata:
|
||||
name: opsxloki-data-20261025
|
||||
namespace: log
|
||||
spec:
|
||||
volumeSnapshotClassName: <集群的 snapshotClass>
|
||||
source:
|
||||
persistentVolumeClaimName: opsxloki-data
|
||||
```
|
||||
|
||||
## 多云兼容
|
||||
|
||||
| 项 | 做法 |
|
||||
|---|---|
|
||||
| 存储类 | `pvc.yaml` 不写 `storageClassName`,用集群默认 SC;没有默认 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 |
|
||||
|
||||
## 与外部实例的关系
|
||||
|
||||
平台的 JSON DB 单写者,**不要两个实例共用同一份数据卷**。要么:
|
||||
- 集群内新实例 + 迁移旧 `opsxloki.json`(停旧实例后拷贝);或
|
||||
- 保留外部 229 实例做带外管理,集群内实例使用独立数据卷(两套数据)。
|
||||
|
||||
## 日志
|
||||
|
||||
- 平台**只写 stdout**(Go/GIN 默认),不写日志文件;`kubectl logs` / `docker logs` 可直接看,Pod 部署无需额外配置。
|
||||
- Docker Compose:已配置 `json-file` 轮转 `max-size=50m`、`max-file=5`。
|
||||
- Kubernetes:由 kubelet 统一轮转,节点级配置建议:
|
||||
```yaml
|
||||
# /var/lib/kubelet/config.yaml
|
||||
containerLogMaxSize: 50Mi
|
||||
containerLogMaxFiles: 5
|
||||
```
|
||||
也可以用 kubelet 启动参数 `--container-log-max-size=50Mi --container-log-max-files=5`。
|
||||
- Loki / Promtail 同样输出到 stdout,由容器运行时轮转;不要在容器内写业务日志文件。
|
||||
- 应用自身的部署日志写在 DB(`deployment_logs`),可在部署详情里查看,不占容器日志空间。
|
||||
@@ -0,0 +1,87 @@
|
||||
# opsx-loki 平台本体
|
||||
#
|
||||
# 关键约束:
|
||||
# 1) replicas 必须为 1:JSON DB 为单写者,多副本会互相覆盖。
|
||||
# 2) strategy 必须为 Recreate:RollingUpdate 期间会同时存在两个 Pod 挂同一个
|
||||
# RWO PVC,两个进程同时写 opsxloki.json 会导致数据丢失。
|
||||
# 3) /app/data 必须挂 PVC,否则重启后 DB / kubeconfig / known_hosts 全丢。
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: opsx-loki
|
||||
namespace: log
|
||||
labels:
|
||||
app: opsx-loki
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: opsx-loki
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: opsx-loki
|
||||
spec:
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: opsx-loki
|
||||
image: lghost/opsxloki:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
env:
|
||||
- name: DATA_DIR
|
||||
value: /app/data
|
||||
- name: JWT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: opsxloki-secrets
|
||||
key: JWT_SECRET
|
||||
- name: ENCRYPTION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: opsxloki-secrets
|
||||
key: ENCRYPTION_KEY
|
||||
# 可选:挂载本地集群 kubeconfig 时启用
|
||||
# - name: KUBECONFIG
|
||||
# value: /home/opsxloki/.kube/config
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /app/data
|
||||
# 可选:本地集群 kubeconfig(in-cluster 管理本集群时用)
|
||||
# - name: kubeconfig
|
||||
# mountPath: /home/opsxloki/.kube
|
||||
# readOnly: true
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 20
|
||||
failureThreshold: 5
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: opsxloki-data
|
||||
# - name: kubeconfig
|
||||
# secret:
|
||||
# secretName: opsxloki-kubeconfig
|
||||
@@ -0,0 +1,24 @@
|
||||
# 可选:通过集群 Ingress 暴露平台 UI。
|
||||
# 阿里云 ACK 用 ALB IngressClass;腾讯 TKE 用 qcloud;华为 CCE 用 nginx/cce。
|
||||
# 若继续走外部 WAF 回源到 Service,则不需要本文件。
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: opsx-loki
|
||||
namespace: log
|
||||
annotations:
|
||||
# 阿里云 ALB 示例;其他云改成对应 ingressClass
|
||||
alb.ingress.kubernetes.io/healthcheck-path: /api/v1/health
|
||||
spec:
|
||||
ingressClassName: alb
|
||||
rules:
|
||||
- host: opsx-loki.91ai.io
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: opsx-loki
|
||||
port:
|
||||
number: 8080
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: log
|
||||
@@ -0,0 +1,15 @@
|
||||
# 平台数据卷:opsxloki.json(JSON DB) + kubeconfigs + known_hosts。
|
||||
# storageClassName 留空 = 使用集群默认 SC:
|
||||
# AWS EBS(gp3) / 腾讯云 CBS / 华为云 EVS / 阿里云 ESSD 均可;
|
||||
# 若集群没有默认 SC,在这里填对应云的 SC 名称。
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: opsxloki-data
|
||||
namespace: log
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 30Gi
|
||||
@@ -0,0 +1,14 @@
|
||||
# 只做模板:不要提交真实密钥。
|
||||
# 推荐直接用命令创建(避免密钥落盘到 Git):
|
||||
# kubectl -n log create secret generic opsxloki-secrets \
|
||||
# --from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
|
||||
# --from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: opsxloki-secrets
|
||||
namespace: log
|
||||
type: Opaque
|
||||
stringData:
|
||||
JWT_SECRET: "REPLACE_WITH_32_BYTES_HEX"
|
||||
ENCRYPTION_KEY: "REPLACE_WITH_32_BYTES_HEX"
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: opsx-loki-nodeport
|
||||
namespace: log
|
||||
labels:
|
||||
app: opsx-loki
|
||||
spec:
|
||||
type: NodePort
|
||||
selector:
|
||||
app: opsx-loki
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: http
|
||||
nodePort: 30080
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: opsx-loki
|
||||
namespace: log
|
||||
labels:
|
||||
app: opsx-loki
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: opsx-loki
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: http
|
||||
Reference in new issue
Block a user