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:
logan committed 2026-10-25 23:44:07 +08:00
1 parent 2d73661dd1
commit 9f7c522157
50 files changed
+1346 -149

No files matched your search

+71
View File
@@ -38,6 +38,49 @@ const DEFAULTS: RuleForm = {
windowMin: '15', threshold: '0', cooldownMin: '60', enabled: true,
}
interface AlertTemplate {
label: string
desc: string
query: string
windowMin: number
threshold: number
cooldownMin: number
}
/** 常用告警模板 — 只做预填,应用后可改 namespace / 阈值 / 窗口 */
const TEMPLATES: AlertTemplate[] = [
{
label: '业务 NS error',
desc: '指定命名空间(默认 astralx)内 error 日志',
query: '{namespace="astralx"} |~ "(?i)error"',
windowMin: 5, threshold: 10, cooldownMin: 30,
},
{
label: '全 NS error > 1000',
desc: '所有命名空间 error 日志总量超过 1000 条',
query: '{namespace=~".+"} |~ "(?i)error"',
windowMin: 15, threshold: 1000, cooldownMin: 60,
},
{
label: 'Ingress 5xx',
desc: 'ingress-nginx 5xx(需 JSON access log,平台可一键标准化)',
query: '{namespace="ingress-nginx"} | json | status >= 500',
windowMin: 5, threshold: 5, cooldownMin: 15,
},
{
label: 'Ingress 4xx',
desc: 'ingress-nginx 4xx(需 JSON access log)',
query: '{namespace="ingress-nginx"} | json | status >= 400 | status < 500',
windowMin: 5, threshold: 50, cooldownMin: 30,
},
{
label: 'FATAL',
desc: '所有命名空间出现 FATAL 即告警',
query: '{namespace=~".+"} |= "FATAL"',
windowMin: 5, threshold: 0, cooldownMin: 15,
},
]
/** 告警规则页:规则 CRUD + 立即检查 + 发送历史 */
const AlertsPage = memo(function AlertsPage() {
const [rules, setRules] = useState<AlertRule[]>([])
@@ -87,6 +130,14 @@ const AlertsPage = memo(function AlertsPage() {
setOpen(true)
}
const applyTemplate = (t: AlertTemplate) => {
form.setValue('name', t.label)
form.setValue('query', t.query)
form.setValue('windowMin', String(t.windowMin))
form.setValue('threshold', String(t.threshold))
form.setValue('cooldownMin', String(t.cooldownMin))
}
const onSubmit = form.handleSubmit(async (v) => {
setSubmitting(true)
try {
@@ -244,6 +295,26 @@ const AlertsPage = memo(function AlertsPage() {
</DialogHeader>
<Form {...form}>
<form onSubmit={onSubmit} className="space-y-4">
{!editing && (
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">快捷模板(点击预填,可再修改)</p>
<div className="flex flex-wrap gap-2">
{TEMPLATES.map((t) => (
<Button
key={t.label}
type="button"
variant="outline"
size="sm"
className="h-8 text-xs"
title={`${t.desc}\n${t.query}`}
onClick={() => applyTemplate(t)}
>
{t.label}
</Button>
))}
</div>
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<FormField control={form.control} name="name" render={({ field }) => (
<FormItem>