# ============================================================================= # OpenTelemetry Collector (contrib) — Deployment + Service, ns `monitoring`. # # The four apps' OTel SDKs export OTLP/HTTP to this collector (the # factory-config configmap, infrastructure/kubernetes/configmap.yaml: # OTEL_ENABLED: "true" (flipped on in staging) # OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector.monitoring.svc.cluster.local:4318 # — that FQDN is why this stack must live in namespace `monitoring`; see the # kustomization.yaml header in this directory for the full rationale). # # Pipeline (rendered inline — kept minimal + commented): # receivers: otlp (http 4318) # processors: batch + memory_limiter # traces: otlp → batch → otlp out (endpoint placeholder — Jaeger/Tempo/APM) # logs: otlp → batch → debug (staging only; switch to a real exporter) # # METRICS DOUBLE-COUNT GUARD: with OTEL_ENABLED=true the apps run BOTH an # OTLP metrics push (30 s periodic reader → this collector's /v1/metrics, # see packages/observability/src/otel.ts) AND a serverless Prometheus reader # (each app's own /metrics route, scraped by the factory-* jobs in # prometheus.yml). Feeding BOTH into the same Prometheus would double-count # every series. Staging default: the direct-scrape jobs (prometheus.yml) # are the metrics path and this collector's metrics pipeline is DISABLED # (commented below) — the collector carries TRACES + logs only. To switch # to collector-scrape: enable the prometheus exporter + add the # `otel-collector` scrape job, and REMOVE the factory-* scrape jobs. # # Traces: OTLP/HTTP in → batch → OTLP out (the endpoint is a placeholder — # point it at Jaeger/Tempo or a vendor; the apps tolerate an unreachable # trace pipeline: initOtel logs the export failure and continues). # Image pinned: otel/opentelemetry-collector-contrib:0.98.0 (0.98.x — the # line whose OTLP proto matches the SDK 1.30/0.57 exporter train the apps # pin; see the TASK-0135 report). # ============================================================================= apiVersion: apps/v1 kind: Deployment metadata: name: otel-collector namespace: monitoring labels: app.kubernetes.io/name: otel-collector app.kubernetes.io/part-of: ai-software-factory spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: otel-collector strategy: type: Recreate template: metadata: labels: app.kubernetes.io/name: otel-collector spec: containers: - name: otel-collector image: otel/opentelemetry-collector-contrib:0.98.0 imagePullPolicy: IfNotPresent args: - --config=/etc/otelcol/config.yaml ports: - containerPort: 4318 name: otlp-http volumeMounts: - name: config mountPath: /etc/otelcol readOnly: true livenessProbe: httpGet: path: / port: 13133 initialDelaySeconds: 15 periodSeconds: 15 readinessProbe: httpGet: path: / port: 13133 initialDelaySeconds: 5 periodSeconds: 10 resources: requests: cpu: 100m memory: 256Mi limits: cpu: 500m memory: 1Gi securityContext: allowPrivilegeEscalation: false runAsNonRoot: true # the contrib image runs as `otel` (uid 1000) runAsUser: 1000 runAsGroup: 1000 seccompProfile: type: RuntimeDefault volumes: - name: config configMap: name: otel-collector-config --- apiVersion: v1 kind: ConfigMap metadata: name: otel-collector-config namespace: monitoring labels: app.kubernetes.io/name: otel-collector app.kubernetes.io/part-of: ai-software-factory data: config.yaml: | receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 # (a `prometheus` receiver scraping the collector's own :8888 goes here # if the metrics pipeline below is enabled) processors: memory_limiter: check_interval: 1s limit_percentage: 80 spike_limit_percentage: 20 batch: timeout: 5s send_batch_size: 1024 exporters: debug: verbosity: basic otlp/traces: endpoint: trace-otlp.monitoring.svc.cluster.local:4317 # PLACEHOLDER: Jaeger/Tempo/your APM tls: insecure: true # prometheus: # DISABLED by default — the apps are scraped DIRECTLY # endpoint: 0.0.0.0:8888 # (jobs factory-* in prometheus.yml). Enable # metrics_endpoint: /metrics # this AND remove the factory-* scrape # force_flush_interval: 10s # jobs if you switch to collector-scrape. service: pipelines: traces: receivers: [otlp] processors: [memory_limiter, batch] exporters: [otlp/traces, debug] # metrics: # see the note on the prometheus exporter above # receivers: [otlp] # processors: [memory_limiter, batch] # exporters: [prometheus] logs: receivers: [otlp] processors: [memory_limiter, batch] exporters: [debug] --- apiVersion: v1 kind: Service metadata: name: otel-collector namespace: monitoring labels: app.kubernetes.io/name: otel-collector app.kubernetes.io/part-of: ai-software-factory spec: selector: app.kubernetes.io/name: otel-collector ports: - name: otlp-http port: 4318 targetPort: 4318