feat(collectors): Promtail DaemonSet 的部署命名空间固定为 log,表单隐藏该字段
=== 需求 ===
创建 Loki 部署后添加采集策略(Promtail DaemonSet)时,"部署节点命名空间"
不该让用户选 —— 采集器必须和 LokiStack 放在一起(log)。
=== 前端 ===
CollectorFormDialog:选择 k8s-daemonset 时整块隐藏 namespace 字段
(连同分类型提示、手动输入开关一起),改为一条只读说明:
「采集器部署命名空间固定为 Loki 所在命名空间(通常 log),与 LokiStack
放在一起,无需选择。要限制采集范围请用下面的『只采集这些命名空间』。」
提交时 DaemonSet 不传 namespace(原来会传用户填的值)。
顺带修掉隐藏后暴露的 tsc 报错:placeholder 里 `collectorType === 'k8s-daemonset'`
在收窄后的分支里已成不可能比较,改为常量 'default'。
=== 后端(强制约束,不只靠前端)===
services/collector.go:
Create:type == k8s-daemonset 时强制清空 req.Namespace
→ 渲染与部署两侧都会回退到 d.loki.Namespace
Update:DaemonSet 忽略 updates["namespace"]
原始渲染逻辑本就有"为空则用 LokiDeployment.Namespace,再兜底 log"。
为什么后端也要拦:API 直接调用(脚本/其他客户端)不该能把采集器
部署到任意命名空间——那样会出现"平台显示在 log、实际 DaemonSet 在别处"
的状态漂移。
=== 实测(0108617e4180)===
现有采集器 promtail-pre: type=k8s-daemonset namespace='log'
PUT {"namespace":"evil-ns"} → 返回 success,但读回仍是 'log' ✅ 被忽略
tsc 通过;Pod = Hub latest = 0108617e4180
This commit is contained in:
1 parent
2e97c04f84
commit
9448868a71
4 files changed
+26
-2
No files matched your search
@@ -274,6 +274,13 @@ func (s *CollectorService) Create(req *CreateCollectorRequest) (*models.Collecto
|
||||
refType = "host"
|
||||
}
|
||||
|
||||
// DaemonSet 的部署命名空间固定为 Loki 所在命名空间(通常 log):
|
||||
// 采集器与 LokiStack 放在一起,用户不需要也不应该选。
|
||||
// 这里强制清空,渲染与部署两侧都会回退到 d.loki.Namespace。
|
||||
if req.Type == "k8s-daemonset" {
|
||||
req.Namespace = ""
|
||||
}
|
||||
|
||||
collector := models.Collector{
|
||||
ID: repository.GetDB().NextID("collectors"),
|
||||
Name: req.Name,
|
||||
@@ -374,6 +381,11 @@ func (s *CollectorService) Update(id uint, updates map[string]interface{}) error
|
||||
if v, ok := updates["labels"].(string); ok {
|
||||
db.Collectors[i].Labels = v
|
||||
}
|
||||
// DaemonSet 的 namespace 一律不接受修改(固定跟随 Loki 所在命名空间)
|
||||
if v, ok := updates["namespace"].(string); ok && v != "" && db.Collectors[i].Type != "k8s-daemonset" {
|
||||
db.Collectors[i].Namespace = v
|
||||
db.Collectors[i].StatusMessage = "部署命名空间已保存,点击部署以应用新配置"
|
||||
}
|
||||
// targetNamespaces: 采集哪些命名空间([]string;空=全集群)
|
||||
if v, ok := updates["targetNamespaces"]; ok {
|
||||
var nss []string
|
||||
|
||||
@@ -81,6 +81,7 @@ const collectors = {
|
||||
namespaceHintSidecar: 'The namespace where the TARGET Deployment lives. The platform finds that Deployment there and injects a Fluent Bit sidecar; collected logs also carry this namespace label. It is NOT a log filter.',
|
||||
namespaceHintDaemonset: 'The namespace where the Promtail DaemonSet is deployed. The DaemonSet collects container logs from ALL namespaces in the cluster — it does not filter by namespace (usually just the Loki namespace, e.g. log).',
|
||||
namespaceHintHost: 'Not used in host mode.',
|
||||
namespaceFixedDaemonset: 'The DaemonSet is always deployed into the Loki namespace (usually log), together with LokiStack — nothing to choose. To limit what gets collected, use "Only collect from these namespaces" below.',
|
||||
targetNamespaces: 'Only collect from these namespaces',
|
||||
targetNamespacesHint: 'Leave empty to collect container stdout from ALL namespaces. Selecting specific ones cuts log volume significantly.',
|
||||
targetNamespacesAll: 'All namespaces',
|
||||
|
||||
@@ -85,6 +85,7 @@ const collectors = {
|
||||
namespaceHintSidecar: '填「目标应用(Deployment)所在的命名空间」。平台会在该命名空间里找到目标 Deployment 并注入 Fluent Bit sidecar,采集到的日志也会打上这个 namespace 标签。它不是日志过滤条件。',
|
||||
namespaceHintDaemonset: '填「Promtail DaemonSet 部署到哪个命名空间」。DaemonSet 会采集整个集群所有命名空间的容器日志,不按命名空间过滤(一般就用 Loki 所在的 log)。',
|
||||
namespaceHintHost: '主机模式不使用该字段。',
|
||||
namespaceFixedDaemonset: '采集器部署命名空间固定为 Loki 所在命名空间(通常 log),与 LokiStack 放在一起,无需选择。要限制采集范围请用下面的「只采集这些命名空间」。',
|
||||
targetNamespaces: '只采集这些命名空间',
|
||||
targetNamespacesHint: '不选 = 采集整个集群所有命名空间的容器标准输出。选了就只采这几个(能显著减少日志量)。',
|
||||
targetNamespacesAll: '全集群',
|
||||
|
||||
@@ -212,7 +212,8 @@ export const CollectorFormDialog = memo(function CollectorFormDialog({
|
||||
: undefined,
|
||||
targetDeployment:
|
||||
values.type === 'k8s-fluentbit-sidecar' ? values.targetDeployment : undefined,
|
||||
namespace: values.type !== 'host-promtail' ? values.namespace : undefined,
|
||||
// DaemonSet 的后端会强制用 Loki 所在命名空间(固定 log),这里不传
|
||||
namespace: values.type !== 'host-promtail' && values.type !== 'k8s-daemonset' ? values.namespace : undefined,
|
||||
// DaemonSet 的日志路径由平台固定为 /var/log/pods/<uid>/*.log,不需要用户填;
|
||||
// 真要限制范围用 targetNamespaces(空 = 全集群)
|
||||
logPath: values.type === 'k8s-daemonset' ? '' : values.logPath,
|
||||
@@ -368,6 +369,9 @@ export const CollectorFormDialog = memo(function CollectorFormDialog({
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{/* DaemonSet 的部署命名空间固定跟随 Loki(通常在 log),
|
||||
与 LokiStack 放在一起,用户不需要选,所以整块隐藏。 */}
|
||||
{!isDaemonsetType && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="namespace"
|
||||
@@ -390,7 +394,7 @@ export const CollectorFormDialog = memo(function CollectorFormDialog({
|
||||
placeholder={!clusterID ? t('form.nsPickCluster') : namespacesLoading ? t('form.nsLoading') : t('form.nsPick')}
|
||||
/>
|
||||
) : (
|
||||
<Input placeholder={collectorType === 'k8s-daemonset' ? 'logging' : 'default'} {...field} onChange={(event) => {
|
||||
<Input placeholder="default" {...field} onChange={(event) => {
|
||||
field.onChange(event)
|
||||
if (isSidecarType) form.setValue('targetDeployment', '')
|
||||
}} />
|
||||
@@ -416,6 +420,12 @@ export const CollectorFormDialog = memo(function CollectorFormDialog({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isDaemonsetType && (
|
||||
<div className="col-span-2 rounded-md border border-dashed px-3 py-2 text-xs text-muted-foreground">
|
||||
{t('form.namespaceFixedDaemonset')}
|
||||
</div>
|
||||
)}
|
||||
{isSidecarType && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
Reference in new issue
Block a user