# ============================================================================= # Kubernetes Event Exporter - Phase O-2.2 # ============================================================================= # 建立者: Claude Code (首席架構師) # 日期: 2026-04-02 (台北時間) # 用途: 將 K8s Event 轉為結構化 Log 送往 SigNoz,保留 30 天 # 解決: K8s Event 預設僅保留 ~1 小時的致命盲區 # ============================================================================= --- apiVersion: v1 kind: ServiceAccount metadata: name: event-exporter namespace: observability --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: event-exporter rules: - apiGroups: [""] resources: ["events"] verbs: ["get", "watch", "list"] - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "watch", "list"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: event-exporter roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: event-exporter subjects: - kind: ServiceAccount name: event-exporter namespace: observability --- apiVersion: v1 kind: ConfigMap metadata: name: event-exporter-config namespace: observability data: config.yaml: | # Phase O-2.2: K8s Event → SigNoz (OTLP HTTP) logLevel: info logFormat: json route: routes: # Warning 和 Error 事件: 全量保留 (RCA 關鍵資料) - match: - receiver: signoz-warning drop: - type: "Normal" reason: "Scheduled" - type: "Normal" reason: "Pulling" - type: "Normal" reason: "Pulled" - type: "Normal" reason: "Created" - type: "Normal" reason: "Started" # Normal 事件中的關鍵類型: 選擇性保留 - match: - receiver: signoz-normal drop: - type: "Warning" receivers: - name: signoz-warning webhook: endpoint: http://192.168.0.188:24318/v1/logs headers: Content-Type: application/json layout: severity: "{{ .Type }}" body: "{{ .Message }}" attributes: k8s.event.reason: "{{ .Reason }}" k8s.event.type: "{{ .Type }}" k8s.event.action: "{{ .Action }}" k8s.event.count: "{{ .Count }}" k8s.namespace.name: "{{ .InvolvedObject.Namespace }}" k8s.object.kind: "{{ .InvolvedObject.Kind }}" k8s.object.name: "{{ .InvolvedObject.Name }}" k8s.event.source.component: "{{ .Source.Component }}" k8s.event.source.host: "{{ .Source.Host }}" k8s.event.first_timestamp: "{{ .FirstTimestamp }}" k8s.event.last_timestamp: "{{ .LastTimestamp }}" - name: signoz-normal webhook: endpoint: http://192.168.0.188:24318/v1/logs headers: Content-Type: application/json layout: severity: "Normal" body: "{{ .Message }}" attributes: k8s.event.reason: "{{ .Reason }}" k8s.event.type: "{{ .Type }}" k8s.namespace.name: "{{ .InvolvedObject.Namespace }}" k8s.object.kind: "{{ .InvolvedObject.Kind }}" k8s.object.name: "{{ .InvolvedObject.Name }}" --- apiVersion: apps/v1 kind: Deployment metadata: name: event-exporter namespace: observability labels: app.kubernetes.io/name: event-exporter phase: o-2 spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: event-exporter template: metadata: labels: app.kubernetes.io/name: event-exporter spec: serviceAccountName: event-exporter # PSA restricted 合規 securityContext: runAsNonRoot: true runAsUser: 65534 seccompProfile: type: RuntimeDefault containers: - name: event-exporter image: ghcr.io/resmoio/kubernetes-event-exporter:v1.7 args: - -conf=/etc/event-exporter/config.yaml securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] resources: requests: cpu: 20m memory: 32Mi limits: cpu: 100m memory: 64Mi volumeMounts: - name: config mountPath: /etc/event-exporter readOnly: true volumes: - name: config configMap: name: event-exporter-config