Datadog and New Relic are powerful, but expensive. For teams that want full-stack observability (traces, metrics, logs) without the per-seat or per-GB billing, SigNoz is the strongest open-source alternative. It’s built on ClickHouse for fast analytical queries and natively supports OpenTelemetry, so instrumentation is vendor-neutral.
This guide deploys SigNoz on Google Kubernetes Engine (GKE) using Helm, with persistent ClickHouse storage on GCP disks and an OTel Collector endpoint your applications can send telemetry to immediately.
Architecture
Your App (OTel SDK)
│
▼ gRPC :4317 / HTTP :4318
OTel Collector ◄── bundled inside SigNoz
│
▼
SigNoz Query Service + Frontend (:3301)
│
▼
ClickHouse (traces, metrics, logs storage)
SigNoz ships everything as a single Helm chart. ClickHouse runs as a StatefulSet inside the same namespace with a persistent volume per pod.
Prerequisites
- GCP project with billing enabled
gcloudCLI authenticated (gcloud auth login)kubectlandhelm3.8+ installed- A GKE cluster (we’ll create one below)
Step 1: Create a GKE Cluster
A standard cluster with a dedicated node pool for observability workloads:
gcloud container clusters create signoz-cluster \
--project <your-project> \
--zone us-central1-a \
--num-nodes 3 \
--machine-type e2-standard-4 \
--disk-size 50 \
--enable-autoscaling \
--min-nodes 2 \
--max-nodes 6 \
--release-channel regular
# Get credentials
gcloud container clusters get-credentials signoz-cluster \
--zone us-central1-a \
--project <your-project>
Node sizing: ClickHouse is memory-hungry.
e2-standard-4(4 vCPU / 16 GB) is the minimum for a comfortable production setup. Usee2-standard-8for higher ingestion rates.
Step 2: Add the SigNoz Helm Repository
helm repo add signoz https://charts.signoz.io
helm repo update
# Confirm the chart is available
helm search repo signoz
# NAME CHART VERSION APP VERSION
# signoz/signoz 0.x.x ...
Step 3: Configure Values for GCP
Create a signoz-values.yaml to set GCP-specific storage and resource limits:
# signoz-values.yaml
global:
storageClass: "standard-rwo" # GCP persistent disk (ReadWriteOnce)
cloud: gcp
clickhouse:
replicaCount: 1 # increase to 3 for HA
persistence:
enabled: true
storageClass: "standard-rwo"
size: 50Gi
resources:
requests:
cpu: "1"
memory: "4Gi"
limits:
cpu: "4"
memory: "8Gi"
queryService:
resources:
requests:
cpu: "200m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
frontend:
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
otelCollector:
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"
otelCollectorMetrics:
resources:
requests:
cpu: "100m"
memory: "128Mi"
# Expose the OTel collector endpoint as a LoadBalancer
# so applications outside GKE can send telemetry
otelCollector:
serviceType: LoadBalancer
For internal-only access (apps on the same GKE cluster), keep
serviceType: ClusterIPand use the Kubernetes service DNS name.
Step 4: Install SigNoz
kubectl create namespace monitoring
helm install signoz signoz/signoz \
--namespace monitoring \
--values signoz-values.yaml \
--wait --timeout 15m
Watch the pods come up:
kubectl get pods -n monitoring -w
# Expected (all Running):
# signoz-clickhouse-0 1/1 Running
# signoz-query-service-xxx 1/1 Running
# signoz-frontend-xxx 1/1 Running
# signoz-otel-collector-xxx 1/1 Running
# signoz-otel-collector-metrics-xxx 1/1 Running
# signoz-alertmanager-xxx 1/1 Running
ClickHouse may take 3–5 minutes to initialise its schema on first boot. That is normal.
Step 5: Access the SigNoz UI
Port-forward locally to verify everything works before exposing publicly:
kubectl port-forward svc/signoz-frontend 3301:3301 -n monitoring
Open http://localhost:3301. You will see the SigNoz dashboard. Create your admin account on first login.
Expose via GCP Load Balancer (optional)
To make the UI accessible from a browser without port-forwarding:
kubectl patch svc signoz-frontend -n monitoring \
-p '{"spec": {"type": "LoadBalancer"}}'
# Get the external IP (takes ~60s)
kubectl get svc signoz-frontend -n monitoring
Protect the UI with Cloud Armor or an IAP-enabled ingress before exposing it publicly.
Step 6: Get the OTel Collector Endpoint
# Internal (from within GKE)
kubectl get svc signoz-otel-collector -n monitoring
# The service name inside the cluster:
# signoz-otel-collector.monitoring.svc.cluster.local:4317 (gRPC)
# signoz-otel-collector.monitoring.svc.cluster.local:4318 (HTTP)
# External IP (if you set LoadBalancer above)
kubectl get svc signoz-otel-collector -n monitoring
# EXTERNAL-IP: 34.xx.xx.xx
Step 7: Instrument Your Application
Point your app’s OTel SDK at the collector. No code changes are needed if you already use OpenTelemetry. Just update the endpoint.
Environment variables (any language):
OTEL_EXPORTER_OTLP_ENDPOINT=http://<collector-ip>:4318
OTEL_SERVICE_NAME=my-service
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
Python example:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint="http://<collector-ip>:4318/v1/traces")
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
Node.js example:
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: 'http://<collector-ip>:4318/v1/traces',
}),
serviceName: 'my-service',
});
sdk.start();
Kubernetes workload (inject via env):
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://signoz-otel-collector.monitoring.svc.cluster.local:4318"
- name: OTEL_SERVICE_NAME
value: "my-service"
- name: OTEL_RESOURCE_ATTRIBUTES
value: "deployment.environment=production,team=platform"
Step 8: Send Logs via OTel Collector
To forward Kubernetes pod logs to SigNoz, deploy the OTel Collector as a DaemonSet using the filelog receiver:
# otel-logs-config.yaml
config:
receivers:
filelog:
include: ["/var/log/pods/*/*/*.log"]
include_file_path: true
operators:
- type: json_parser
timestamp:
parse_from: attributes.time
layout: "%Y-%m-%dT%H:%M:%S.%fZ"
exporters:
otlp:
endpoint: "signoz-otel-collector.monitoring.svc.cluster.local:4317"
tls:
insecure: true
service:
pipelines:
logs:
receivers: [filelog]
exporters: [otlp]
Step 9: Verify Data in SigNoz
- Open the SigNoz UI at
http://localhost:3301(or your Load Balancer IP) - Go to Services. Your instrumented services should appear within 30 seconds of sending the first trace
- Go to Traces. Search by service name, filter by duration or status code
- Go to Logs. Query by service, severity, or keyword
- Go to Metrics. View RED metrics (Rate, Errors, Duration) per service
Upgrading SigNoz
helm repo update
helm upgrade signoz signoz/signoz \
--namespace monitoring \
--values signoz-values.yaml \
--wait
ClickHouse schema migrations run automatically on upgrade.
Cost Estimate (GCP)
For a small team (< 10 services, ~10M spans/day):
- 3×
e2-standard-4nodes: ~$150/month - 3× 50 GB persistent disks: ~$15/month
- Load Balancer: ~$20/month
- Total: ~$185/month
Compare to Datadog at $15 to $31 per host per month. For a 20-host environment that’s $300 to $620/month before ingestion costs.
Summary
SigNoz on GKE gives you a production-grade observability stack (traces, metrics, and logs) with no per-seat pricing and full data ownership. The setup is a one-time Helm install; after that, onboarding a new service is just pointing its OTel SDK at the collector endpoint. ClickHouse handles the heavy analytical workload efficiently, and the OTel-native design means your instrumentation works with any backend without rewrites.
Was this article helpful?
Need help setting this up for your team?
nerdSolv designs and deploys cloud-native infrastructure on Azure, AWS, and GCP.
Talk to us →