diff --git a/api/v1alpha1/collectionagent/casting.schema.json b/api/v1alpha1/collectionagent/casting.schema.json index 8998b545..b540bab6 100644 --- a/api/v1alpha1/collectionagent/casting.schema.json +++ b/api/v1alpha1/collectionagent/casting.schema.json @@ -30,7 +30,8 @@ }, "CollectionagentCollectorKind": { "enum": [ - "agent" + "agent", + "deployment" ], "type": "string" }, diff --git a/api/v1alpha1/collectionagent/collector_kind.go b/api/v1alpha1/collectionagent/collector_kind.go index 11999e9f..6557d10a 100644 --- a/api/v1alpha1/collectionagent/collector_kind.go +++ b/api/v1alpha1/collectionagent/collector_kind.go @@ -19,7 +19,8 @@ var _ fmt.Stringer = (*CollectorKind)(nil) var _ jsonschema.Enum = (*CollectorKind)(nil) var ( - CollectorKindAgent CollectorKind = CollectorKind{s: "agent"} + CollectorKindAgent CollectorKind = CollectorKind{s: "agent"} + CollectorKindDeployment CollectorKind = CollectorKind{s: "deployment"} ) type CollectorKind struct { @@ -37,7 +38,7 @@ func (kind CollectorKind) ConfigKey() string { } func CollectorKinds() []CollectorKind { - return []CollectorKind{CollectorKindAgent} + return []CollectorKind{CollectorKindAgent, CollectorKindDeployment} } func (kind CollectorKind) MarshalJSON() ([]byte, error) { diff --git a/docs/examples/collectionagent/kubernetes/kustomize/README.md b/docs/examples/collectionagent/kubernetes/kustomize/README.md new file mode 100644 index 00000000..b5377ce5 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/README.md @@ -0,0 +1,115 @@ +# Kubernetes Collection Agent + +| Field | Value | +| --- | --- | +| **Kind** | `CollectionAgent` | +| **Mode** | `kubernetes` | +| **Flavor** | `kustomize` | + +## Overview + +Deploys the SigNoz Collection Agents on a Kubernetes cluster as plain +manifests composed by kustomize, exporting to any SigNoz: Self-Hosted +Community, Self-Hosted Enterprise, or SigNoz Cloud. + +Kubernetes telemetry comes from two collectors with different scopes, one +casting each: + +- `agent/` runs on every node as a DaemonSet: + - Pod and container metrics from the kubelet through the `kubeletstats` + receiver + - Node metrics from the mounted host filesystem through the `hostmetrics` + receiver + - Pod logs from `/var/log/pods` through the `filelog` receiver + - OTLP intake for your applications on host ports 4317 (gRPC) and 4318 + (HTTP), also reachable node-locally as a service +- `deployment/` runs once per cluster as a Deployment: + - Cluster metrics (workload status, pod phase, node conditions, + allocatables) from the API server through the `k8s_cluster` receiver + - Kubernetes events as logs through the `k8s_events` receiver + +Run both. The SigNoz Kubernetes views require both sources: entity +resolution breaks when either the kubelet metrics or the cluster-level +metrics are missing. Together they match what the SigNoz k8s-infra chart +deploys. Both castings share the `metadata.name`, so they compose into one +namespace. + +Kubernetes metadata lands on every signal through the `k8sattributes` +processor, and the collector config enters the cluster through a +`configMapGenerator`: a config change re-hashes the ConfigMap name and rolls +the workload on the next apply. + +## Prerequisites + +- A Kubernetes cluster and `kubectl` configured against it +- A running SigNoz to receive the telemetry + +## Configuration + +The node agent (`agent/casting.yaml`): + +```yaml +apiVersion: v1alpha1 +kind: CollectionAgent +metadata: + name: signoz +spec: + deployment: + mode: kubernetes + flavor: kustomize + collector: + spec: + env: + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + K8S_CLUSTER_NAME: +``` + +The cluster collector (`deployment/casting.yaml`): + +```yaml +apiVersion: v1alpha1 +kind: CollectionAgent +metadata: + name: signoz +spec: + deployment: + mode: kubernetes + flavor: kustomize + collector: + kind: deployment + spec: + env: + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + K8S_CLUSTER_NAME: +``` + +`K8S_CLUSTER_NAME` names the cluster on every signal as `k8s.cluster.name`. +Set it: the SigNoz Kubernetes views require it on every entity, and queries +fail silently without it. + +## Forge + +```bash +foundryctl forge -f agent/casting.yaml -p agent/pours +foundryctl forge -f deployment/casting.yaml -p deployment/pours +``` + +Each collector kind pours a kustomize root of its own under +`/pours/collectionagent/collector//`: `kustomization.yaml`, the +namespace, RBAC, service, the workload manifest, and the collector config the +configMapGenerator reads. A casting file declaring both kinds pours a root per +document, and casting applies each. + +## Cast + +```bash +foundryctl cast -f agent/casting.yaml -p agent/pours +foundryctl cast -f deployment/casting.yaml -p deployment/pours +``` + +This runs `kubectl apply -k` against the pours using your current kubeconfig +context. To inspect what would be applied first: + +```bash +kubectl kustomize agent/pours/collectionagent/collector/agent +``` diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/casting.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/casting.yaml new file mode 100644 index 00000000..d2af34d0 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/casting.yaml @@ -0,0 +1,13 @@ +apiVersion: v1alpha1 +kind: CollectionAgent +metadata: + name: signoz +spec: + deployment: + mode: kubernetes + flavor: kustomize + collector: + spec: + env: + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + K8S_CLUSTER_NAME: diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/casting.yaml.lock b/docs/examples/collectionagent/kubernetes/kustomize/agent/casting.yaml.lock new file mode 100644 index 00000000..54cb2789 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/casting.yaml.lock @@ -0,0 +1,519 @@ +apiVersion: v1alpha1 +kind: CollectionAgent +metadata: + name: signoz +spec: + collector: + kind: agent + spec: + cluster: + replicas: 1 + config: + data: + collector/agent/agent.yaml: | + exporters: + otlphttp/signoz: + endpoint: ${env:SIGNOZ_INGESTION_ENDPOINT} + extensions: + health_check: + endpoint: 0.0.0.0:13133 + path: /healthz + processors: + batch: + send_batch_max_size: 2048 + send_batch_size: 1000 + timeout: 10s + k8sattributes: + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + filter: + node_from_env_var: K8S_NODE_NAME + passthrough: false + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 5s + limit_mib: 4000 + spike_limit_mib: 800 + resourcedetection: + detectors: + - k8snode + - env + - system + k8snode: + auth_type: serviceAccount + node_from_env_var: K8S_NODE_NAME + override: false + system: + resource_attributes: + host.id: + enabled: false + host.name: + enabled: false + os.type: + enabled: true + timeout: 2s + receivers: + filelog/k8s: + exclude: + - /var/log/pods/signoz_signoz-collector-*/*/*.log + - /var/log/pods/kube-system_*/*/*.log + include: + - /var/log/pods/*/*/*.log + include_file_name: false + include_file_path: true + operators: + - id: container-parser + type: container + start_at: end + hostmetrics: + collection_interval: 30s + root_path: /hostfs + scrapers: + cpu: {} + disk: + exclude: + devices: + - ^ram\d+$ + - ^zram\d+$ + - ^loop\d+$ + - ^fd\d+$ + - ^hd[a-z]\d+$ + - ^sd[a-z]\d+$ + - ^vd[a-z]\d+$ + - ^xvd[a-z]\d+$ + - ^nvme\d+n\d+p\d+$ + match_type: regexp + filesystem: + exclude_fs_types: + fs_types: + - autofs + - binfmt_misc + - bpf + - cgroup2? + - configfs + - debugfs + - devpts + - devtmpfs + - fusectl + - hugetlbfs + - iso9660 + - mqueue + - nsfs + - overlay + - proc + - procfs + - pstore + - rpc_pipefs + - securityfs + - selinuxfs + - squashfs + - sysfs + - tracefs + match_type: strict + exclude_mount_points: + match_type: regexp + mount_points: + - /dev/* + - /proc/* + - /sys/* + - /run/credentials/* + - /run/k3s/containerd/* + - /var/lib/docker/* + - /var/lib/containers/storage/* + - /var/lib/kubelet/* + - /snap/* + load: {} + memory: {} + network: + exclude: + interfaces: + - ^veth.*$ + - ^docker.*$ + - ^br-.*$ + - ^flannel.*$ + - ^cali.*$ + - ^cbr.*$ + - ^cni.*$ + - ^dummy.*$ + - ^tailscale.*$ + - ^lo$ + match_type: regexp + kubeletstats: + auth_type: serviceAccount + collection_interval: 30s + endpoint: ${env:K8S_HOST_IP}:10250 + extra_metadata_labels: + - container.id + - k8s.volume.type + insecure_skip_verify: true + k8s_api_config: + auth_type: serviceAccount + metric_groups: + - container + - pod + - node + - volume + metrics: + container.cpu.usage: + enabled: true + container.uptime: + enabled: true + k8s.container.cpu.node.utilization: + enabled: true + k8s.container.cpu_limit_utilization: + enabled: true + k8s.container.cpu_request_utilization: + enabled: true + k8s.container.memory.node.utilization: + enabled: true + k8s.container.memory_limit_utilization: + enabled: true + k8s.container.memory_request_utilization: + enabled: true + k8s.node.cpu.usage: + enabled: true + k8s.node.uptime: + enabled: true + k8s.pod.cpu.usage: + enabled: true + k8s.pod.cpu_limit_utilization: + enabled: true + k8s.pod.cpu_request_utilization: + enabled: true + k8s.pod.memory_limit_utilization: + enabled: true + k8s.pod.memory_request_utilization: + enabled: true + k8s.pod.uptime: + enabled: true + node: ${env:K8S_NODE_NAME} + otlp/grpc: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + max_recv_msg_size_mib: 16 + otlp/http: + protocols: + http: + endpoint: 0.0.0.0:4318 + service: + extensions: + - health_check + pipelines: + logs: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - filelog/k8s + metrics: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - hostmetrics + - kubeletstats + traces: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + enabled: true + env: + K8S_CLUSTER_NAME: + OTEL_COLLECTOR_ROLE: agent + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + image: otel/opentelemetry-collector-contrib:0.139.0 + version: 0.139.0 + status: + config: + data: + collector/agent/agent.yaml: | + exporters: + otlphttp/signoz: + endpoint: ${env:SIGNOZ_INGESTION_ENDPOINT} + extensions: + health_check: + endpoint: 0.0.0.0:13133 + path: /healthz + processors: + batch: + send_batch_max_size: 2048 + send_batch_size: 1000 + timeout: 10s + k8sattributes: + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + filter: + node_from_env_var: K8S_NODE_NAME + passthrough: false + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 5s + limit_mib: 4000 + spike_limit_mib: 800 + resourcedetection: + detectors: + - k8snode + - env + - system + k8snode: + auth_type: serviceAccount + node_from_env_var: K8S_NODE_NAME + override: false + system: + resource_attributes: + host.id: + enabled: false + host.name: + enabled: false + os.type: + enabled: true + timeout: 2s + receivers: + filelog/k8s: + exclude: + - /var/log/pods/signoz_signoz-collector-*/*/*.log + - /var/log/pods/kube-system_*/*/*.log + include: + - /var/log/pods/*/*/*.log + include_file_name: false + include_file_path: true + operators: + - id: container-parser + type: container + start_at: end + hostmetrics: + collection_interval: 30s + root_path: /hostfs + scrapers: + cpu: {} + disk: + exclude: + devices: + - ^ram\d+$ + - ^zram\d+$ + - ^loop\d+$ + - ^fd\d+$ + - ^hd[a-z]\d+$ + - ^sd[a-z]\d+$ + - ^vd[a-z]\d+$ + - ^xvd[a-z]\d+$ + - ^nvme\d+n\d+p\d+$ + match_type: regexp + filesystem: + exclude_fs_types: + fs_types: + - autofs + - binfmt_misc + - bpf + - cgroup2? + - configfs + - debugfs + - devpts + - devtmpfs + - fusectl + - hugetlbfs + - iso9660 + - mqueue + - nsfs + - overlay + - proc + - procfs + - pstore + - rpc_pipefs + - securityfs + - selinuxfs + - squashfs + - sysfs + - tracefs + match_type: strict + exclude_mount_points: + match_type: regexp + mount_points: + - /dev/* + - /proc/* + - /sys/* + - /run/credentials/* + - /run/k3s/containerd/* + - /var/lib/docker/* + - /var/lib/containers/storage/* + - /var/lib/kubelet/* + - /snap/* + load: {} + memory: {} + network: + exclude: + interfaces: + - ^veth.*$ + - ^docker.*$ + - ^br-.*$ + - ^flannel.*$ + - ^cali.*$ + - ^cbr.*$ + - ^cni.*$ + - ^dummy.*$ + - ^tailscale.*$ + - ^lo$ + match_type: regexp + kubeletstats: + auth_type: serviceAccount + collection_interval: 30s + endpoint: ${env:K8S_HOST_IP}:10250 + extra_metadata_labels: + - container.id + - k8s.volume.type + insecure_skip_verify: true + k8s_api_config: + auth_type: serviceAccount + metric_groups: + - container + - pod + - node + - volume + metrics: + container.cpu.usage: + enabled: true + container.uptime: + enabled: true + k8s.container.cpu.node.utilization: + enabled: true + k8s.container.cpu_limit_utilization: + enabled: true + k8s.container.cpu_request_utilization: + enabled: true + k8s.container.memory.node.utilization: + enabled: true + k8s.container.memory_limit_utilization: + enabled: true + k8s.container.memory_request_utilization: + enabled: true + k8s.node.cpu.usage: + enabled: true + k8s.node.uptime: + enabled: true + k8s.pod.cpu.usage: + enabled: true + k8s.pod.cpu_limit_utilization: + enabled: true + k8s.pod.cpu_request_utilization: + enabled: true + k8s.pod.memory_limit_utilization: + enabled: true + k8s.pod.memory_request_utilization: + enabled: true + k8s.pod.uptime: + enabled: true + node: ${env:K8S_NODE_NAME} + otlp/grpc: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + max_recv_msg_size_mib: 16 + otlp/http: + protocols: + http: + endpoint: 0.0.0.0:4318 + service: + extensions: + - health_check + pipelines: + logs: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - filelog/k8s + metrics: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - hostmetrics + - kubeletstats + traces: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + env: + K8S_CLUSTER_NAME: + OTEL_COLLECTOR_ROLE: agent + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + deployment: + flavor: kustomize + mode: kubernetes diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/agent.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/agent.yaml new file mode 100644 index 00000000..e46107c7 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/agent.yaml @@ -0,0 +1,244 @@ +exporters: + otlphttp/signoz: + endpoint: ${env:SIGNOZ_INGESTION_ENDPOINT} +extensions: + health_check: + endpoint: 0.0.0.0:13133 + path: /healthz +processors: + batch: + send_batch_max_size: 2048 + send_batch_size: 1000 + timeout: 10s + k8sattributes: + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + filter: + node_from_env_var: K8S_NODE_NAME + passthrough: false + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 5s + limit_mib: 4000 + spike_limit_mib: 800 + resourcedetection: + detectors: + - k8snode + - env + - system + k8snode: + auth_type: serviceAccount + node_from_env_var: K8S_NODE_NAME + override: false + system: + resource_attributes: + host.id: + enabled: false + host.name: + enabled: false + os.type: + enabled: true + timeout: 2s +receivers: + filelog/k8s: + exclude: + - /var/log/pods/signoz_signoz-collector-*/*/*.log + - /var/log/pods/kube-system_*/*/*.log + include: + - /var/log/pods/*/*/*.log + include_file_name: false + include_file_path: true + operators: + - id: container-parser + type: container + start_at: end + hostmetrics: + collection_interval: 30s + root_path: /hostfs + scrapers: + cpu: {} + disk: + exclude: + devices: + - ^ram\d+$ + - ^zram\d+$ + - ^loop\d+$ + - ^fd\d+$ + - ^hd[a-z]\d+$ + - ^sd[a-z]\d+$ + - ^vd[a-z]\d+$ + - ^xvd[a-z]\d+$ + - ^nvme\d+n\d+p\d+$ + match_type: regexp + filesystem: + exclude_fs_types: + fs_types: + - autofs + - binfmt_misc + - bpf + - cgroup2? + - configfs + - debugfs + - devpts + - devtmpfs + - fusectl + - hugetlbfs + - iso9660 + - mqueue + - nsfs + - overlay + - proc + - procfs + - pstore + - rpc_pipefs + - securityfs + - selinuxfs + - squashfs + - sysfs + - tracefs + match_type: strict + exclude_mount_points: + match_type: regexp + mount_points: + - /dev/* + - /proc/* + - /sys/* + - /run/credentials/* + - /run/k3s/containerd/* + - /var/lib/docker/* + - /var/lib/containers/storage/* + - /var/lib/kubelet/* + - /snap/* + load: {} + memory: {} + network: + exclude: + interfaces: + - ^veth.*$ + - ^docker.*$ + - ^br-.*$ + - ^flannel.*$ + - ^cali.*$ + - ^cbr.*$ + - ^cni.*$ + - ^dummy.*$ + - ^tailscale.*$ + - ^lo$ + match_type: regexp + kubeletstats: + auth_type: serviceAccount + collection_interval: 30s + endpoint: ${env:K8S_HOST_IP}:10250 + extra_metadata_labels: + - container.id + - k8s.volume.type + insecure_skip_verify: true + k8s_api_config: + auth_type: serviceAccount + metric_groups: + - container + - pod + - node + - volume + metrics: + container.cpu.usage: + enabled: true + container.uptime: + enabled: true + k8s.container.cpu.node.utilization: + enabled: true + k8s.container.cpu_limit_utilization: + enabled: true + k8s.container.cpu_request_utilization: + enabled: true + k8s.container.memory.node.utilization: + enabled: true + k8s.container.memory_limit_utilization: + enabled: true + k8s.container.memory_request_utilization: + enabled: true + k8s.node.cpu.usage: + enabled: true + k8s.node.uptime: + enabled: true + k8s.pod.cpu.usage: + enabled: true + k8s.pod.cpu_limit_utilization: + enabled: true + k8s.pod.cpu_request_utilization: + enabled: true + k8s.pod.memory_limit_utilization: + enabled: true + k8s.pod.memory_request_utilization: + enabled: true + k8s.pod.uptime: + enabled: true + node: ${env:K8S_NODE_NAME} + otlp/grpc: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + max_recv_msg_size_mib: 16 + otlp/http: + protocols: + http: + endpoint: 0.0.0.0:4318 +service: + extensions: + - health_check + pipelines: + logs: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - filelog/k8s + metrics: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - hostmetrics + - kubeletstats + traces: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/clusterrole.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/clusterrole.yaml new file mode 100644 index 00000000..448a9fc3 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/clusterrole.yaml @@ -0,0 +1,64 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-agent + name: signoz-collector-agent +rules: +- apiGroups: + - "" + resources: + - pods + - namespaces + - nodes + - persistentvolumeclaims + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - list + - watch +- apiGroups: + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - nodes + - endpoints + verbs: + - list + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - nodes/proxy + verbs: + - get +- apiGroups: + - "" + resources: + - nodes/stats + verbs: + - get diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/clusterrolebinding.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/clusterrolebinding.yaml new file mode 100644 index 00000000..0e838835 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-agent + name: signoz-collector-agent +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: signoz-collector-agent +subjects: +- kind: ServiceAccount + name: signoz-collector-agent + namespace: signoz diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/kustomization.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/kustomization.yaml new file mode 100644 index 00000000..5afc7c02 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/kustomization.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +configMapGenerator: +- files: + - agent.yaml + name: signoz-collector-agent +kind: Kustomization +labels: +- includeSelectors: false + includeTemplates: true + pairs: + foundry.signoz.io/kind: CollectionAgent + foundry.signoz.io/managed-by: foundry + foundry.signoz.io/name: signoz +namespace: signoz +resources: +- namespace.yaml +- serviceaccount.yaml +- clusterrole.yaml +- clusterrolebinding.yaml +- service.yaml +- workload.yaml diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/namespace.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/namespace.yaml new file mode 100644 index 00000000..b0391bcc --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: signoz diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/service.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/service.yaml new file mode 100644 index 00000000..eca6e782 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-agent + name: signoz-collector-agent +spec: + internalTrafficPolicy: Local + ports: + - name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: otlp-grpc + - name: otlp-http + port: 4318 + protocol: TCP + targetPort: otlp-http + selector: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/name: signoz-collector-agent + type: ClusterIP diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/serviceaccount.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/serviceaccount.yaml new file mode 100644 index 00000000..527b965a --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/serviceaccount.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-agent + name: signoz-collector-agent diff --git a/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/workload.yaml b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/workload.yaml new file mode 100644 index 00000000..96ac337e --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/agent/pours/collectionagent/collector/agent/workload.yaml @@ -0,0 +1,129 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-agent + name: signoz-collector-agent +spec: + minReadySeconds: 5 + selector: + matchLabels: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/name: signoz-collector-agent + template: + metadata: + labels: + app.kubernetes.io/component: collector-agent + app.kubernetes.io/instance: signoz + app.kubernetes.io/name: signoz-collector-agent + spec: + containers: + - args: + - --config=/conf/agent.yaml + env: + - name: K8S_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: K8S_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: K8S_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: K8S_POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: K8S_CLUSTER_NAME + value: + - name: OTEL_COLLECTOR_ROLE + value: agent + - name: SIGNOZ_INGESTION_ENDPOINT + value: http://:4318 + - name: OTEL_RESOURCE_ATTRIBUTES + value: k8s.cluster.name=$(K8S_CLUSTER_NAME),k8s.node.name=$(K8S_NODE_NAME),host.name=$(K8S_NODE_NAME) + image: otel/opentelemetry-collector-contrib:0.139.0 + livenessProbe: + failureThreshold: 6 + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: collector-agent + ports: + - containerPort: 13133 + hostPort: 13133 + name: health-check + protocol: TCP + - containerPort: 8888 + hostPort: 8888 + name: metrics + protocol: TCP + - containerPort: 4317 + hostPort: 4317 + name: otlp-grpc + protocol: TCP + - containerPort: 4318 + hostPort: 4318 + name: otlp-http + protocol: TCP + readinessProbe: + failureThreshold: 6 + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + requests: + cpu: 100m + memory: 100Mi + volumeMounts: + - mountPath: /conf + name: config + - mountPath: /var/log + name: varlog + readOnly: true + - mountPath: /var/lib/docker/containers + name: varlibdockercontainers + readOnly: true + - mountPath: /hostfs + mountPropagation: HostToContainer + name: hostfs + readOnly: true + serviceAccountName: signoz-collector-agent + tolerations: + - operator: Exists + volumes: + - configMap: + name: signoz-collector-agent + name: config + - hostPath: + path: /var/log + name: varlog + - hostPath: + path: /var/lib/docker/containers + name: varlibdockercontainers + - hostPath: + path: / + name: hostfs diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/casting.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/casting.yaml new file mode 100644 index 00000000..22312df3 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/casting.yaml @@ -0,0 +1,14 @@ +apiVersion: v1alpha1 +kind: CollectionAgent +metadata: + name: signoz +spec: + deployment: + mode: kubernetes + flavor: kustomize + collector: + kind: deployment + spec: + env: + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + K8S_CLUSTER_NAME: diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/casting.yaml.lock b/docs/examples/collectionagent/kubernetes/kustomize/deployment/casting.yaml.lock new file mode 100644 index 00000000..91aaef29 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/casting.yaml.lock @@ -0,0 +1,285 @@ +apiVersion: v1alpha1 +kind: CollectionAgent +metadata: + name: signoz +spec: + collector: + kind: deployment + spec: + cluster: + replicas: 1 + config: + data: + collector/deployment/deployment.yaml: | + exporters: + otlphttp/signoz: + endpoint: ${env:SIGNOZ_INGESTION_ENDPOINT} + extensions: + health_check: + endpoint: 0.0.0.0:13133 + path: /healthz + processors: + batch: + send_batch_max_size: 2048 + send_batch_size: 1000 + timeout: 10s + k8sattributes: + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + passthrough: false + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 5s + limit_mib: 4000 + spike_limit_mib: 800 + resourcedetection: + detectors: + - env + override: false + timeout: 2s + receivers: + k8s_cluster: + allocatable_types_to_report: + - cpu + - memory + collection_interval: 30s + metrics: + k8s.container.status.reason: + enabled: true + k8s.container.status.state: + enabled: true + k8s.node.condition: + enabled: true + k8s.pod.status_reason: + enabled: true + node_conditions_to_report: + - Ready + - MemoryPressure + - DiskPressure + - PIDPressure + - NetworkUnavailable + resource_attributes: + container.runtime: + enabled: true + container.runtime.version: + enabled: true + k8s.container.status.last_terminated_reason: + enabled: true + k8s.kubelet.version: + enabled: true + k8s.pod.qos_class: + enabled: true + k8s_events: + auth_type: serviceAccount + otlp/grpc: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + max_recv_msg_size_mib: 16 + otlp/http: + protocols: + http: + endpoint: 0.0.0.0:4318 + service: + extensions: + - health_check + pipelines: + logs: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - k8s_events + metrics: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - k8s_cluster + traces: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + enabled: true + env: + K8S_CLUSTER_NAME: + OTEL_COLLECTOR_ROLE: deployment + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + image: otel/opentelemetry-collector-contrib:0.139.0 + version: 0.139.0 + status: + config: + data: + collector/deployment/deployment.yaml: | + exporters: + otlphttp/signoz: + endpoint: ${env:SIGNOZ_INGESTION_ENDPOINT} + extensions: + health_check: + endpoint: 0.0.0.0:13133 + path: /healthz + processors: + batch: + send_batch_max_size: 2048 + send_batch_size: 1000 + timeout: 10s + k8sattributes: + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + passthrough: false + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 5s + limit_mib: 4000 + spike_limit_mib: 800 + resourcedetection: + detectors: + - env + override: false + timeout: 2s + receivers: + k8s_cluster: + allocatable_types_to_report: + - cpu + - memory + collection_interval: 30s + metrics: + k8s.container.status.reason: + enabled: true + k8s.container.status.state: + enabled: true + k8s.node.condition: + enabled: true + k8s.pod.status_reason: + enabled: true + node_conditions_to_report: + - Ready + - MemoryPressure + - DiskPressure + - PIDPressure + - NetworkUnavailable + resource_attributes: + container.runtime: + enabled: true + container.runtime.version: + enabled: true + k8s.container.status.last_terminated_reason: + enabled: true + k8s.kubelet.version: + enabled: true + k8s.pod.qos_class: + enabled: true + k8s_events: + auth_type: serviceAccount + otlp/grpc: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + max_recv_msg_size_mib: 16 + otlp/http: + protocols: + http: + endpoint: 0.0.0.0:4318 + service: + extensions: + - health_check + pipelines: + logs: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - k8s_events + metrics: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - k8s_cluster + traces: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + env: + K8S_CLUSTER_NAME: + OTEL_COLLECTOR_ROLE: deployment + SIGNOZ_INGESTION_ENDPOINT: http://:4318 + deployment: + flavor: kustomize + mode: kubernetes diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/clusterrole.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/clusterrole.yaml new file mode 100644 index 00000000..afa90bcd --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/clusterrole.yaml @@ -0,0 +1,66 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-deployment + name: signoz-collector-deployment +rules: +- apiGroups: + - "" + resources: + - events + - namespaces + - namespaces/status + - nodes + - nodes/spec + - pods + - pods/status + - replicationcontrollers + - replicationcontrollers/status + - resourcequotas + - services + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - daemonsets + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: + - extensions + resources: + - daemonsets + - deployments + - replicasets + verbs: + - get + - list + - watch +- apiGroups: + - batch + resources: + - jobs + - cronjobs + verbs: + - get + - list + - watch +- apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/clusterrolebinding.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/clusterrolebinding.yaml new file mode 100644 index 00000000..6d913967 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-deployment + name: signoz-collector-deployment +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: signoz-collector-deployment +subjects: +- kind: ServiceAccount + name: signoz-collector-deployment + namespace: signoz diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/deployment.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/deployment.yaml new file mode 100644 index 00000000..e1517782 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/deployment.yaml @@ -0,0 +1,127 @@ +exporters: + otlphttp/signoz: + endpoint: ${env:SIGNOZ_INGESTION_ENDPOINT} +extensions: + health_check: + endpoint: 0.0.0.0:13133 + path: /healthz +processors: + batch: + send_batch_max_size: 2048 + send_batch_size: 1000 + timeout: 10s + k8sattributes: + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + passthrough: false + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 5s + limit_mib: 4000 + spike_limit_mib: 800 + resourcedetection: + detectors: + - env + override: false + timeout: 2s +receivers: + k8s_cluster: + allocatable_types_to_report: + - cpu + - memory + collection_interval: 30s + metrics: + k8s.container.status.reason: + enabled: true + k8s.container.status.state: + enabled: true + k8s.node.condition: + enabled: true + k8s.pod.status_reason: + enabled: true + node_conditions_to_report: + - Ready + - MemoryPressure + - DiskPressure + - PIDPressure + - NetworkUnavailable + resource_attributes: + container.runtime: + enabled: true + container.runtime.version: + enabled: true + k8s.container.status.last_terminated_reason: + enabled: true + k8s.kubelet.version: + enabled: true + k8s.pod.qos_class: + enabled: true + k8s_events: + auth_type: serviceAccount + otlp/grpc: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + max_recv_msg_size_mib: 16 + otlp/http: + protocols: + http: + endpoint: 0.0.0.0:4318 +service: + extensions: + - health_check + pipelines: + logs: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - k8s_events + metrics: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc + - k8s_cluster + traces: + exporters: + - otlphttp/signoz + processors: + - memory_limiter + - resourcedetection + - k8sattributes + - batch + receivers: + - otlp/http + - otlp/grpc diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/kustomization.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/kustomization.yaml new file mode 100644 index 00000000..7dc0c7d9 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/kustomization.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +configMapGenerator: +- files: + - deployment.yaml + name: signoz-collector-deployment +kind: Kustomization +labels: +- includeSelectors: false + includeTemplates: true + pairs: + foundry.signoz.io/kind: CollectionAgent + foundry.signoz.io/managed-by: foundry + foundry.signoz.io/name: signoz +namespace: signoz +resources: +- namespace.yaml +- serviceaccount.yaml +- clusterrole.yaml +- clusterrolebinding.yaml +- service.yaml +- workload.yaml diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/namespace.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/namespace.yaml new file mode 100644 index 00000000..b0391bcc --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: signoz diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/service.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/service.yaml new file mode 100644 index 00000000..c8b1712a --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-deployment + name: signoz-collector-deployment +spec: + ports: + - name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: otlp-grpc + - name: otlp-http + port: 4318 + protocol: TCP + targetPort: otlp-http + selector: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/name: signoz-collector-deployment + type: ClusterIP diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/serviceaccount.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/serviceaccount.yaml new file mode 100644 index 00000000..f6134582 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/serviceaccount.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-deployment + name: signoz-collector-deployment diff --git a/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/workload.yaml b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/workload.yaml new file mode 100644 index 00000000..13492e49 --- /dev/null +++ b/docs/examples/collectionagent/kubernetes/kustomize/deployment/pours/collectionagent/collector/deployment/workload.yaml @@ -0,0 +1,103 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: signoz-collector-deployment + name: signoz-collector-deployment +spec: + minReadySeconds: 5 + progressDeadlineSeconds: 120 + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/name: signoz-collector-deployment + template: + metadata: + labels: + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/instance: signoz + app.kubernetes.io/name: signoz-collector-deployment + spec: + containers: + - args: + - --config=/conf/deployment.yaml + env: + - name: K8S_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: K8S_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: K8S_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: K8S_POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: K8S_CLUSTER_NAME + value: + - name: OTEL_COLLECTOR_ROLE + value: deployment + - name: SIGNOZ_INGESTION_ENDPOINT + value: http://:4318 + - name: OTEL_RESOURCE_ATTRIBUTES + value: k8s.cluster.name=$(K8S_CLUSTER_NAME) + image: otel/opentelemetry-collector-contrib:0.139.0 + livenessProbe: + failureThreshold: 6 + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: collector-deployment + ports: + - containerPort: 13133 + name: health-check + protocol: TCP + - containerPort: 4317 + name: otlp-grpc + protocol: TCP + - containerPort: 4318 + name: otlp-http + protocol: TCP + readinessProbe: + failureThreshold: 6 + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + requests: + cpu: 100m + memory: 100Mi + volumeMounts: + - mountPath: /conf + name: config + serviceAccountName: signoz-collector-deployment + volumes: + - configMap: + name: signoz-collector-deployment + name: config diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/casting.go b/internal/casting/collectionagent/kuberneteskustomizecasting/casting.go new file mode 100644 index 00000000..66a5e693 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/casting.go @@ -0,0 +1,111 @@ +package kuberneteskustomizecasting + +import ( + "bytes" + "context" + "log/slog" + "path/filepath" + "strings" + + "github.com/signoz/foundry/api/v1alpha1/collectionagent" + "github.com/signoz/foundry/internal/domain" + foundryerrors "github.com/signoz/foundry/internal/errors" + collectionagentmolding "github.com/signoz/foundry/internal/molding/collectionagent" + "github.com/signoz/foundry/internal/pourer" + "github.com/signoz/foundry/internal/tooler" + "github.com/signoz/foundry/internal/tooler/kubetooler" +) + +type kubernetesKustomizeCasting struct { + logger *slog.Logger +} + +func New(logger *slog.Logger) *kubernetesKustomizeCasting { + return &kubernetesKustomizeCasting{logger: logger} +} + +func (c *kubernetesKustomizeCasting) Enricher(ctx context.Context, config *collectionagent.Casting) (collectionagentmolding.MoldingEnricher, error) { + return newKubernetesKustomizeMoldingEnricher(), nil +} + +func (c *kubernetesKustomizeCasting) Forge(ctx context.Context, config collectionagent.Casting, p *pourer.Pourer) error { + tmpls := []*domain.Template{kustomizationTemplate, namespaceTemplate} + + // The workload follows the collector kind's scope: the agent runs on + // every node, the deployment runs replicated behind the service. + switch config.Spec.Collector.Kind { + case collectionagent.CollectorKindAgent: + tmpls = append(tmpls, + agentServiceaccountTemplate, + agentClusterroleTemplate, + agentClusterrolebindingTemplate, + agentServiceTemplate, + daemonsetTemplate, + ) + case collectionagent.CollectorKindDeployment: + tmpls = append(tmpls, + deploymentServiceaccountTemplate, + deploymentClusterroleTemplate, + deploymentClusterrolebindingTemplate, + deploymentServiceTemplate, + deploymentTemplate, + ) + default: + return foundryerrors.Newf(foundryerrors.TypeUnsupported, "unsupported collector kind %q", config.Spec.Collector.Kind) + } + + // The kind's directory is a kustomize root of its own, so a casting file + // holding several collection agents pours a tree per document. + dir := filepath.Dir(config.Spec.Collector.Kind.ConfigKey()) + + for _, tmpl := range tmpls { + buf := bytes.NewBuffer(nil) + if err := tmpl.Execute(buf, config); err != nil { + return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to execute %s template", tmpl.Name()) + } + + p.AddYAML(buf.Bytes(), dir, strings.TrimSuffix(tmpl.Name(), ".gotmpl")) + } + + // The collector config, inside the kustomize root so the configMapGenerator + // reaches it by relative path. + for path, content := range config.Spec.Collector.Spec.Config.Data { + p.AddYAML([]byte(content), path) + } + + return nil +} + +func (c *kubernetesKustomizeCasting) Cast(ctx context.Context, config collectionagent.Casting, outputPath string, p *pourer.Pourer, toolers []tooler.Tooler) error { + kube, err := kubetooler.Lookup(toolers) + if err != nil { + return err + } + + c.logger.InfoContext(ctx, "applying kustomize manifests", + slog.String("release", config.Metadata.Name), + slog.String("namespace", config.Metadata.Name), + ) + + return kube.Apply(ctx, c.release(config, outputPath, p)) +} + +func (c *kubernetesKustomizeCasting) Melt(ctx context.Context, config collectionagent.Casting, outputPath string, p *pourer.Pourer, toolers []tooler.Tooler) error { + kube, err := kubetooler.Lookup(toolers) + if err != nil { + return err + } + + return kube.Delete(ctx, c.release(config, outputPath, p)) +} + +// release addresses the collector kind's own kustomize root: the kind's config +// key names the directory. +func (c *kubernetesKustomizeCasting) release(config collectionagent.Casting, outputPath string, p *pourer.Pourer) kubetooler.Release { + return kubetooler.Release{ + Release: domain.Release{Name: config.Metadata.Name, Owner: config.Labels()}, + Namespace: config.Metadata.Name, + Dir: filepath.Join(outputPath, p.Dir(), filepath.Dir(config.Spec.Collector.Kind.ConfigKey())), + FieldManager: "foundry-" + strings.ToLower(config.Kind().String()), + } +} diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/embed.go b/internal/casting/collectionagent/kuberneteskustomizecasting/embed.go new file mode 100644 index 00000000..0eed4fb7 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/embed.go @@ -0,0 +1,29 @@ +package kuberneteskustomizecasting + +import ( + "embed" + + "github.com/signoz/foundry/internal/domain" +) + +//go:embed templates/*.gotmpl templates/agent/*.gotmpl templates/deployment/*.gotmpl +var templates embed.FS + +var ( + kustomizationTemplate = domain.MustNewTemplateFromFS(templates, "templates/kustomization.yaml.gotmpl", domain.FormatYAML) + namespaceTemplate = domain.MustNewTemplateFromFS(templates, "templates/namespace.yaml.gotmpl", domain.FormatYAML) + + agentServiceaccountTemplate = domain.MustNewTemplateFromFS(templates, "templates/agent/serviceaccount.yaml.gotmpl", domain.FormatYAML) + agentClusterroleTemplate = domain.MustNewTemplateFromFS(templates, "templates/agent/clusterrole.yaml.gotmpl", domain.FormatYAML) + agentClusterrolebindingTemplate = domain.MustNewTemplateFromFS(templates, "templates/agent/clusterrolebinding.yaml.gotmpl", domain.FormatYAML) + agentServiceTemplate = domain.MustNewTemplateFromFS(templates, "templates/agent/service.yaml.gotmpl", domain.FormatYAML) + daemonsetTemplate = domain.MustNewTemplateFromFS(templates, "templates/agent/workload.yaml.gotmpl", domain.FormatYAML) + agentYAMLTemplate = domain.MustNewTemplateFromFS(templates, "templates/agent/collector.yaml.gotmpl", domain.FormatYAML) + + deploymentServiceaccountTemplate = domain.MustNewTemplateFromFS(templates, "templates/deployment/serviceaccount.yaml.gotmpl", domain.FormatYAML) + deploymentClusterroleTemplate = domain.MustNewTemplateFromFS(templates, "templates/deployment/clusterrole.yaml.gotmpl", domain.FormatYAML) + deploymentClusterrolebindingTemplate = domain.MustNewTemplateFromFS(templates, "templates/deployment/clusterrolebinding.yaml.gotmpl", domain.FormatYAML) + deploymentServiceTemplate = domain.MustNewTemplateFromFS(templates, "templates/deployment/service.yaml.gotmpl", domain.FormatYAML) + deploymentTemplate = domain.MustNewTemplateFromFS(templates, "templates/deployment/workload.yaml.gotmpl", domain.FormatYAML) + deploymentYAMLTemplate = domain.MustNewTemplateFromFS(templates, "templates/deployment/collector.yaml.gotmpl", domain.FormatYAML) +) diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/embed_test.go b/internal/casting/collectionagent/kuberneteskustomizecasting/embed_test.go new file mode 100644 index 00000000..a306a2ed --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/embed_test.go @@ -0,0 +1,72 @@ +package kuberneteskustomizecasting + +import ( + "bytes" + "testing" + + "github.com/signoz/foundry/api/v1alpha1/collectionagent" + "github.com/signoz/foundry/internal/domain" + "github.com/stretchr/testify/assert" +) + +func castingWithKind(t *testing.T, kind collectionagent.CollectorKind) collectionagent.Casting { + t.Helper() + + config := *collectionagent.Default() + config.Spec.Collector.Kind = kind + + return config +} + +func TestTemplates_RenderValidYAML(t *testing.T) { + tests := []struct { + name string + template *domain.Template + kind collectionagent.CollectorKind + }{ + {name: "KustomizationTemplate_AgentRendersValidYAML", template: kustomizationTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "KustomizationTemplate_DeploymentRendersValidYAML", template: kustomizationTemplate, kind: collectionagent.CollectorKindDeployment}, + {name: "NamespaceTemplate_RendersValidYAML", template: namespaceTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "AgentServiceaccountTemplate_RendersValidYAML", template: agentServiceaccountTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "AgentClusterroleTemplate_RendersValidYAML", template: agentClusterroleTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "AgentClusterrolebindingTemplate_RendersValidYAML", template: agentClusterrolebindingTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "AgentServiceTemplate_RendersValidYAML", template: agentServiceTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "DaemonsetTemplate_RendersValidYAML", template: daemonsetTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "DeploymentServiceaccountTemplate_RendersValidYAML", template: deploymentServiceaccountTemplate, kind: collectionagent.CollectorKindDeployment}, + {name: "DeploymentClusterroleTemplate_RendersValidYAML", template: deploymentClusterroleTemplate, kind: collectionagent.CollectorKindDeployment}, + {name: "DeploymentClusterrolebindingTemplate_RendersValidYAML", template: deploymentClusterrolebindingTemplate, kind: collectionagent.CollectorKindDeployment}, + {name: "DeploymentServiceTemplate_RendersValidYAML", template: deploymentServiceTemplate, kind: collectionagent.CollectorKindDeployment}, + {name: "DeploymentTemplate_RendersValidYAML", template: deploymentTemplate, kind: collectionagent.CollectorKindDeployment}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + material, err := tt.template.Render(castingWithKind(t, tt.kind), "out.yaml") + assert.NoError(t, err) + assert.NotEmpty(t, material.FmtContents()) + }) + } +} + +func TestEnricherConfigTemplates_RenderValidYAML(t *testing.T) { + tests := []struct { + name string + template *domain.Template + kind collectionagent.CollectorKind + }{ + {name: "AgentTemplate_RendersValidYAML", template: agentYAMLTemplate, kind: collectionagent.CollectorKindAgent}, + {name: "DeploymentTemplate_RendersValidYAML", template: deploymentYAMLTemplate, kind: collectionagent.CollectorKindDeployment}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + buf := bytes.NewBuffer(nil) + err := tt.template.Execute(buf, castingWithKind(t, tt.kind)) + assert.NoError(t, err) + + var parsed map[string]any + assert.NoError(t, domain.UnmarshalYAML(buf.Bytes(), &parsed)) + assert.Contains(t, parsed, "service") + }) + } +} diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/enricher.go b/internal/casting/collectionagent/kuberneteskustomizecasting/enricher.go new file mode 100644 index 00000000..b3320e3c --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/enricher.go @@ -0,0 +1,45 @@ +package kuberneteskustomizecasting + +import ( + "bytes" + "context" + + "github.com/signoz/foundry/api/v1alpha1" + "github.com/signoz/foundry/api/v1alpha1/collectionagent" + "github.com/signoz/foundry/internal/domain" + foundryerrors "github.com/signoz/foundry/internal/errors" + collectionagentmolding "github.com/signoz/foundry/internal/molding/collectionagent" +) + +var _ collectionagentmolding.MoldingEnricher = (*kubernetesKustomizeMoldingEnricher)(nil) + +type kubernetesKustomizeMoldingEnricher struct{} + +func newKubernetesKustomizeMoldingEnricher() *kubernetesKustomizeMoldingEnricher { + return &kubernetesKustomizeMoldingEnricher{} +} + +func (e *kubernetesKustomizeMoldingEnricher) EnrichStatus(ctx context.Context, kind v1alpha1.MoldingKind, config *collectionagent.Casting) error { + if kind != v1alpha1.MoldingKindCollector { + return nil + } + + var tmpl *domain.Template + switch config.Spec.Collector.Kind { + case collectionagent.CollectorKindAgent: + tmpl = agentYAMLTemplate + case collectionagent.CollectorKindDeployment: + tmpl = deploymentYAMLTemplate + default: + return foundryerrors.Newf(foundryerrors.TypeUnsupported, "unsupported collector kind %q", config.Spec.Collector.Kind) + } + + buf := bytes.NewBuffer(nil) + if err := tmpl.Execute(buf, config); err != nil { + return foundryerrors.Wrapf(err, foundryerrors.TypeInternal, "failed to execute %s template", config.Spec.Collector.Kind) + } + + config.Spec.Collector.Status.Config.Set(config.Spec.Collector.Kind.ConfigKey(), buf.Bytes()) + + return nil +} diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/clusterrole.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/clusterrole.yaml.gotmpl new file mode 100644 index 00000000..c519a651 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/clusterrole.yaml.gotmpl @@ -0,0 +1,65 @@ +{{- $name := print $.Metadata.Name "-collector-agent" -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-agent + app.kubernetes.io/managed-by: kustomize +rules: + - apiGroups: + - "" + resources: + - pods + - namespaces + - nodes + - persistentvolumeclaims + verbs: + - get + - list + - watch + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - extensions + resources: + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + - endpoints + verbs: + - list + - watch + - apiGroups: + - batch + resources: + - jobs + verbs: + - list + - watch + - apiGroups: + - "" + resources: + - nodes/proxy + verbs: + - get + - apiGroups: + - "" + resources: + - nodes/stats + verbs: + - get diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/clusterrolebinding.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/clusterrolebinding.yaml.gotmpl new file mode 100644 index 00000000..98d1cc45 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/clusterrolebinding.yaml.gotmpl @@ -0,0 +1,18 @@ +{{- $name := print $.Metadata.Name "-collector-agent" -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-agent + app.kubernetes.io/managed-by: kustomize +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ $name }} +subjects: + - kind: ServiceAccount + name: {{ $name }} + namespace: {{ $.Metadata.Name }} diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/collector.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/collector.yaml.gotmpl new file mode 100644 index 00000000..6062ff65 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/collector.yaml.gotmpl @@ -0,0 +1,204 @@ +# The agent's Kubernetes additions, held to the shipped k8s-infra chart +# (0.16.0, app 0.139.0, default render; the gate-0 source). Divergences are +# recorded in the ledger. Bodies replace the molding base; pipeline lists +# merge per the molding's listTypes. +receivers: + filelog/k8s: + include: + - /var/log/pods/*/*/*.log + exclude: + # The collectors' own logs (self-log loop) and kube-system noise, + # matching the shipped chart's excludes. + - /var/log/pods/{{ $.Metadata.Name }}_{{ $.Metadata.Name }}-collector-*/*/*.log + - /var/log/pods/kube-system_*/*/*.log + include_file_name: false + include_file_path: true + start_at: end + operators: + - id: container-parser + type: container + hostmetrics: + collection_interval: 30s + root_path: /hostfs + scrapers: + cpu: {} + load: {} + memory: {} + disk: + exclude: + match_type: regexp + devices: + - ^ram\d+$ + - ^zram\d+$ + - ^loop\d+$ + - ^fd\d+$ + - ^hd[a-z]\d+$ + - ^sd[a-z]\d+$ + - ^vd[a-z]\d+$ + - ^xvd[a-z]\d+$ + - ^nvme\d+n\d+p\d+$ + filesystem: + exclude_fs_types: + match_type: strict + fs_types: + - autofs + - binfmt_misc + - bpf + - cgroup2? + - configfs + - debugfs + - devpts + - devtmpfs + - fusectl + - hugetlbfs + - iso9660 + - mqueue + - nsfs + - overlay + - proc + - procfs + - pstore + - rpc_pipefs + - securityfs + - selinuxfs + - squashfs + - sysfs + - tracefs + exclude_mount_points: + match_type: regexp + mount_points: + - /dev/* + - /proc/* + - /sys/* + - /run/credentials/* + - /run/k3s/containerd/* + - /var/lib/docker/* + - /var/lib/containers/storage/* + - /var/lib/kubelet/* + - /snap/* + network: + exclude: + match_type: regexp + interfaces: + - ^veth.*$ + - ^docker.*$ + - ^br-.*$ + - ^flannel.*$ + - ^cali.*$ + - ^cbr.*$ + - ^cni.*$ + - ^dummy.*$ + - ^tailscale.*$ + - ^lo$ + kubeletstats: + auth_type: serviceAccount + collection_interval: 30s + endpoint: ${env:K8S_HOST_IP}:10250 + insecure_skip_verify: true + node: ${env:K8S_NODE_NAME} + k8s_api_config: + auth_type: serviceAccount + extra_metadata_labels: + - container.id + - k8s.volume.type + metric_groups: + - container + - pod + - node + - volume + metrics: + container.cpu.usage: + enabled: true + container.uptime: + enabled: true + k8s.container.cpu.node.utilization: + enabled: true + k8s.container.memory.node.utilization: + enabled: true + k8s.container.cpu_limit_utilization: + enabled: true + k8s.container.cpu_request_utilization: + enabled: true + k8s.container.memory_limit_utilization: + enabled: true + k8s.container.memory_request_utilization: + enabled: true + k8s.node.cpu.usage: + enabled: true + k8s.node.uptime: + enabled: true + k8s.pod.cpu.usage: + enabled: true + k8s.pod.cpu_limit_utilization: + enabled: true + k8s.pod.cpu_request_utilization: + enabled: true + k8s.pod.memory_limit_utilization: + enabled: true + k8s.pod.memory_request_utilization: + enabled: true + k8s.pod.uptime: + enabled: true + +processors: + k8sattributes: + passthrough: false + filter: + node_from_env_var: K8S_NODE_NAME + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + resourcedetection: + detectors: + - k8snode + - env + - system + k8snode: + auth_type: serviceAccount + node_from_env_var: K8S_NODE_NAME + system: + resource_attributes: + host.id: + enabled: false + host.name: + enabled: false + os.type: + enabled: true + override: false + timeout: 2s + +service: + pipelines: + metrics: + receivers: + - hostmetrics + - kubeletstats + processors: + - k8sattributes + logs: + receivers: + - filelog/k8s + processors: + - k8sattributes + traces: + processors: + - k8sattributes diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/service.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/service.yaml.gotmpl new file mode 100644 index 00000000..61d66345 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/service.yaml.gotmpl @@ -0,0 +1,28 @@ +{{- $name := print $.Metadata.Name "-collector-agent" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-agent + app.kubernetes.io/managed-by: kustomize +spec: + type: ClusterIP + # Traffic to the agent's ClusterIP stays on the caller's own node, so the + # service name is a stable node-local endpoint. + internalTrafficPolicy: Local + selector: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-agent + ports: + - name: otlp-grpc + port: 4317 + targetPort: otlp-grpc + protocol: TCP + - name: otlp-http + port: 4318 + targetPort: otlp-http + protocol: TCP diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/serviceaccount.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/serviceaccount.yaml.gotmpl new file mode 100644 index 00000000..d62a1d58 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/serviceaccount.yaml.gotmpl @@ -0,0 +1,10 @@ +{{- $name := print $.Metadata.Name "-collector-agent" -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-agent + app.kubernetes.io/managed-by: kustomize diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/workload.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/workload.yaml.gotmpl new file mode 100644 index 00000000..dfe9e56a --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/agent/workload.yaml.gotmpl @@ -0,0 +1,132 @@ +{{- $name := print $.Metadata.Name "-collector-" $.Spec.Collector.Kind -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-{{ $.Spec.Collector.Kind }} + app.kubernetes.io/managed-by: kustomize +spec: + minReadySeconds: 5 + selector: + matchLabels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-{{ $.Spec.Collector.Kind }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-{{ $.Spec.Collector.Kind }} + spec: + serviceAccountName: {{ $name }} + tolerations: + - operator: Exists + containers: + - name: collector-{{ $.Spec.Collector.Kind }} + image: {{ $.Spec.Collector.Spec.Image }} + args: + - "--config=/conf/agent.yaml" + env: + - name: K8S_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: K8S_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: K8S_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: K8S_POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- range $key, $val := $.Spec.Collector.Spec.Env }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + {{- if not (index $.Spec.Collector.Spec.Env "OTEL_RESOURCE_ATTRIBUTES") }} + # host.name on every signal is the real node's name; the env + # detector picks these up first. + - name: OTEL_RESOURCE_ATTRIBUTES + value: "{{ if index $.Spec.Collector.Spec.Env "K8S_CLUSTER_NAME" }}k8s.cluster.name=$(K8S_CLUSTER_NAME),{{ end }}k8s.node.name=$(K8S_NODE_NAME),host.name=$(K8S_NODE_NAME)" + {{- end }} + ports: + - name: health-check + containerPort: 13133 + hostPort: 13133 + protocol: TCP + - name: metrics + containerPort: 8888 + hostPort: 8888 + protocol: TCP + - name: otlp-grpc + containerPort: 4317 + hostPort: 4317 + protocol: TCP + - name: otlp-http + containerPort: 4318 + hostPort: 4318 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 + resources: + requests: + cpu: 100m + memory: 100Mi + volumeMounts: + - name: config + mountPath: /conf + - name: varlog + mountPath: /var/log + readOnly: true + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + - name: hostfs + mountPath: /hostfs + readOnly: true + mountPropagation: HostToContainer + volumes: + - name: config + configMap: + name: {{ $name }} + - name: varlog + hostPath: + path: /var/log + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers + - name: hostfs + hostPath: + path: / diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/clusterrole.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/clusterrole.yaml.gotmpl new file mode 100644 index 00000000..1b7f9cd7 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/clusterrole.yaml.gotmpl @@ -0,0 +1,67 @@ +{{- $name := print $.Metadata.Name "-collector-deployment" -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/managed-by: kustomize +rules: + - apiGroups: + - "" + resources: + - events + - namespaces + - namespaces/status + - nodes + - nodes/spec + - pods + - pods/status + - replicationcontrollers + - replicationcontrollers/status + - resourcequotas + - services + verbs: + - get + - list + - watch + - apiGroups: + - apps + resources: + - daemonsets + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch + - apiGroups: + - extensions + resources: + - daemonsets + - deployments + - replicasets + verbs: + - get + - list + - watch + - apiGroups: + - batch + resources: + - jobs + - cronjobs + verbs: + - get + - list + - watch + - apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/clusterrolebinding.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/clusterrolebinding.yaml.gotmpl new file mode 100644 index 00000000..19469d99 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/clusterrolebinding.yaml.gotmpl @@ -0,0 +1,18 @@ +{{- $name := print $.Metadata.Name "-collector-deployment" -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/managed-by: kustomize +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ $name }} +subjects: + - kind: ServiceAccount + name: {{ $name }} + namespace: {{ $.Metadata.Name }} diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/collector.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/collector.yaml.gotmpl new file mode 100644 index 00000000..1c6e4e56 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/collector.yaml.gotmpl @@ -0,0 +1,84 @@ +# The environment-scoped collector's Kubernetes additions: the once-per- +# cluster signals, held to the shipped k8s-infra chart (0.16.0, app 0.139.0, +# default render; the gate-0 source). Divergences are recorded in the ledger. +receivers: + k8s_cluster: + collection_interval: 30s + allocatable_types_to_report: + - cpu + - memory + node_conditions_to_report: + - Ready + - MemoryPressure + - DiskPressure + - PIDPressure + - NetworkUnavailable + metrics: + k8s.container.status.reason: + enabled: true + k8s.container.status.state: + enabled: true + k8s.node.condition: + enabled: true + k8s.pod.status_reason: + enabled: true + resource_attributes: + container.runtime: + enabled: true + container.runtime.version: + enabled: true + k8s.container.status.last_terminated_reason: + enabled: true + k8s.kubelet.version: + enabled: true + k8s.pod.qos_class: + enabled: true + k8s_events: + auth_type: serviceAccount + +processors: + k8sattributes: + passthrough: false + extract: + metadata: + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + - k8s.node.name + - k8s.node.uid + - k8s.pod.name + - k8s.pod.uid + - k8s.pod.start_time + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + resourcedetection: + detectors: + - env + override: false + timeout: 2s + +service: + pipelines: + metrics: + receivers: + - k8s_cluster + processors: + - k8sattributes + logs: + receivers: + - k8s_events + processors: + - k8sattributes + traces: + processors: + - k8sattributes diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/service.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/service.yaml.gotmpl new file mode 100644 index 00000000..e9c4ccfc --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/service.yaml.gotmpl @@ -0,0 +1,25 @@ +{{- $name := print $.Metadata.Name "-collector-deployment" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/managed-by: kustomize +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-deployment + ports: + - name: otlp-grpc + port: 4317 + targetPort: otlp-grpc + protocol: TCP + - name: otlp-http + port: 4318 + targetPort: otlp-http + protocol: TCP diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/serviceaccount.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/serviceaccount.yaml.gotmpl new file mode 100644 index 00000000..6c0348f9 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/serviceaccount.yaml.gotmpl @@ -0,0 +1,10 @@ +{{- $name := print $.Metadata.Name "-collector-deployment" -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-deployment + app.kubernetes.io/managed-by: kustomize diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/workload.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/workload.yaml.gotmpl new file mode 100644 index 00000000..c01da1f5 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/deployment/workload.yaml.gotmpl @@ -0,0 +1,104 @@ +{{- $name := print $.Metadata.Name "-collector-" $.Spec.Collector.Kind -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $name }} + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-{{ $.Spec.Collector.Kind }} + app.kubernetes.io/managed-by: kustomize +spec: + replicas: {{ derefIntDefault $.Spec.Collector.Spec.Cluster.Replicas 1 }} + minReadySeconds: 5 + progressDeadlineSeconds: 120 + selector: + matchLabels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-{{ $.Spec.Collector.Kind }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ $name }} + app.kubernetes.io/instance: {{ $.Metadata.Name }} + app.kubernetes.io/component: collector-{{ $.Spec.Collector.Kind }} + spec: + serviceAccountName: {{ $name }} + containers: + - name: collector-{{ $.Spec.Collector.Kind }} + image: {{ $.Spec.Collector.Spec.Image }} + args: + - "--config=/conf/deployment.yaml" + env: + - name: K8S_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: K8S_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: K8S_HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: K8S_POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- range $key, $val := $.Spec.Collector.Spec.Env }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + {{- if and (not (index $.Spec.Collector.Spec.Env "OTEL_RESOURCE_ATTRIBUTES")) (index $.Spec.Collector.Spec.Env "K8S_CLUSTER_NAME") }} + - name: OTEL_RESOURCE_ATTRIBUTES + value: "k8s.cluster.name=$(K8S_CLUSTER_NAME)" + {{- end }} + ports: + - name: health-check + containerPort: 13133 + protocol: TCP + - name: otlp-grpc + containerPort: 4317 + protocol: TCP + - name: otlp-http + containerPort: 4318 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /healthz + port: 13133 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 6 + resources: + requests: + cpu: 100m + memory: 100Mi + volumeMounts: + - name: config + mountPath: /conf + volumes: + - name: config + configMap: + name: {{ $name }} diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/kustomization.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/kustomization.yaml.gotmpl new file mode 100644 index 00000000..137a7a66 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/kustomization.yaml.gotmpl @@ -0,0 +1,25 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: {{ $.Metadata.Name }} + +labels: + - pairs: + {{- range $key, $value := $.Labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + includeSelectors: false + includeTemplates: true + +resources: + - namespace.yaml + - serviceaccount.yaml + - clusterrole.yaml + - clusterrolebinding.yaml + - service.yaml + - workload.yaml + +configMapGenerator: + - name: {{ $.Metadata.Name }}-collector-{{ $.Spec.Collector.Kind }} + files: + - {{ $.Spec.Collector.Kind }}.yaml diff --git a/internal/casting/collectionagent/kuberneteskustomizecasting/templates/namespace.yaml.gotmpl b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/namespace.yaml.gotmpl new file mode 100644 index 00000000..9b9cf693 --- /dev/null +++ b/internal/casting/collectionagent/kuberneteskustomizecasting/templates/namespace.yaml.gotmpl @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: {{ $.Metadata.Name }} diff --git a/internal/casting/collectionagent/registry.go b/internal/casting/collectionagent/registry.go index f4b5399a..1d8adb04 100644 --- a/internal/casting/collectionagent/registry.go +++ b/internal/casting/collectionagent/registry.go @@ -6,10 +6,12 @@ import ( "github.com/signoz/foundry/api/v1alpha1" "github.com/signoz/foundry/internal/casting/collectionagent/dockercomposecasting" "github.com/signoz/foundry/internal/casting/collectionagent/dockerswarmcasting" + "github.com/signoz/foundry/internal/casting/collectionagent/kuberneteskustomizecasting" foundryerrors "github.com/signoz/foundry/internal/errors" "github.com/signoz/foundry/internal/tooler" "github.com/signoz/foundry/internal/tooler/dockercomposetooler" "github.com/signoz/foundry/internal/tooler/dockerswarmtooler" + "github.com/signoz/foundry/internal/tooler/kubetooler" ) type CastingItem struct { @@ -39,6 +41,13 @@ func NewRegistry(logger *slog.Logger) *Registry { Casting: dockerswarmcasting.New(logger), Toolers: []tooler.Tooler{dockerswarmtooler.New(logger)}, }, + { + Mode: v1alpha1.ModeKubernetes, + Flavor: v1alpha1.FlavorKustomize, + }: { + Casting: kuberneteskustomizecasting.New(logger), + Toolers: []tooler.Tooler{kubetooler.New(logger)}, + }, }, } } diff --git a/internal/molding/collectionagent/collectormolding/collector.go b/internal/molding/collectionagent/collectormolding/collector.go index e621dec4..05db8412 100644 --- a/internal/molding/collectionagent/collectormolding/collector.go +++ b/internal/molding/collectionagent/collectormolding/collector.go @@ -47,6 +47,8 @@ func (m *collector) MoldV1Alpha1(ctx context.Context, config *collectionagent.Ca switch kind { case collectionagent.CollectorKindAgent: tmpl = agentConfig + case collectionagent.CollectorKindDeployment: + tmpl = deploymentConfig default: return foundryerrors.Newf(foundryerrors.TypeUnsupported, "unsupported collector kind %q", kind) } diff --git a/internal/molding/collectionagent/collectormolding/collector_test.go b/internal/molding/collectionagent/collectormolding/collector_test.go index 406247e6..d612e1e6 100644 --- a/internal/molding/collectionagent/collectormolding/collector_test.go +++ b/internal/molding/collectionagent/collectormolding/collector_test.go @@ -96,6 +96,20 @@ func TestMoldAgent(t *testing.T) { } } +// Every kind molds its base config at its own config key and reports its +// role through the env. +func TestMoldKinds(t *testing.T) { + for _, kind := range collectionagent.CollectorKinds() { + t.Run(kind.String()+"_MoldsConfigAtKindKey", func(t *testing.T) { + c := newCasting(t, kind, "") + require.NoError(t, New(slog.Default()).MoldV1Alpha1(context.Background(), c)) + + assert.NotEmpty(t, c.Spec.Collector.Status.Config.Data[kind.ConfigKey()]) + assert.Equal(t, kind.String(), c.Spec.Collector.Status.Env["OTEL_COLLECTOR_ROLE"]) + }) + } +} + func TestMoldAgentErrors(t *testing.T) { tests := []struct { name string diff --git a/internal/molding/collectionagent/collectormolding/template.go b/internal/molding/collectionagent/collectormolding/template.go index ea55b7dc..38a8c797 100644 --- a/internal/molding/collectionagent/collectormolding/template.go +++ b/internal/molding/collectionagent/collectormolding/template.go @@ -9,5 +9,9 @@ import ( //go:embed templates/*.gotmpl var templates embed.FS -// agentConfig is the agent collector's base config. -var agentConfig *domain.Template = domain.MustNewTemplateFromFS(templates, "templates/agent.yaml.gotmpl", domain.FormatYAML) +// Per-kind base configs. Both share the same core today (OTLP in, SigNoz +// out); evidence for a kind-level divergence lands in its own file. +var ( + agentConfig *domain.Template = domain.MustNewTemplateFromFS(templates, "templates/agent.yaml.gotmpl", domain.FormatYAML) + deploymentConfig *domain.Template = domain.MustNewTemplateFromFS(templates, "templates/deployment.yaml.gotmpl", domain.FormatYAML) +) diff --git a/internal/molding/collectionagent/collectormolding/template_test.go b/internal/molding/collectionagent/collectormolding/template_test.go index 154f4c70..e2e91240 100644 --- a/internal/molding/collectionagent/collectormolding/template_test.go +++ b/internal/molding/collectionagent/collectormolding/template_test.go @@ -8,4 +8,5 @@ import ( func TestCollector(t *testing.T) { assert.NotEmpty(t, agentConfig) + assert.NotEmpty(t, deploymentConfig) } diff --git a/internal/molding/collectionagent/collectormolding/templates/deployment.yaml.gotmpl b/internal/molding/collectionagent/collectormolding/templates/deployment.yaml.gotmpl new file mode 100644 index 00000000..f8d7a0ed --- /dev/null +++ b/internal/molding/collectionagent/collectormolding/templates/deployment.yaml.gotmpl @@ -0,0 +1,50 @@ +extensions: + health_check: + endpoint: 0.0.0.0:13133 + path: /healthz + +receivers: + otlp/grpc: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + max_recv_msg_size_mib: 16 + otlp/http: + protocols: + http: + endpoint: 0.0.0.0:4318 + +processors: + memory_limiter: + check_interval: 5s + limit_mib: 4000 + spike_limit_mib: 800 + resourcedetection: + detectors: + - env + - system + timeout: 5s + batch: + send_batch_size: 1000 + send_batch_max_size: 2048 + timeout: 10s + +exporters: + otlphttp/signoz: + endpoint: ${env:SIGNOZ_INGESTION_ENDPOINT} + +service: + extensions: [health_check] + pipelines: + traces: + receivers: [otlp/http, otlp/grpc] + processors: [memory_limiter, resourcedetection, batch] + exporters: [otlphttp/signoz] + metrics: + receivers: [otlp/http, otlp/grpc] + processors: [memory_limiter, resourcedetection, batch] + exporters: [otlphttp/signoz] + logs: + receivers: [otlp/http, otlp/grpc] + processors: [memory_limiter, resourcedetection, batch] + exporters: [otlphttp/signoz]