Dogfood signoz (#38569)

This commit is contained in:
Robert Fairburn
2026-01-22 12:33:27 -06:00
committed by GitHub
parent e154caf2cb
commit e0631aff76
8 changed files with 839 additions and 4 deletions
+1
View File
@@ -38,6 +38,7 @@ env:
TF_VAR_elastic_token: ${{ secrets.ELASTIC_APM_SECRET_TOKEN }}
TF_VAR_geolite2_license: ${{ secrets.MAXMIND_LICENSE }}
TF_VAR_dogfood_sidecar_enroll_secret: ${{ secrets.DOGFOOD_SERVERS_CANARY_ENROLL_SECRET }}
TF_VAR_otel_bearer_token: ${{ secrets.DOGFOOD_SIGNOZ_OTEL_BEARER_TOKEN }}
TF_VAR_android_service_credentials: ${{ secrets.FLEET_DEV_ANDROID_SERVICE_CREDENTIALS }}
TF_VAR_cloudfront_public_key: ${{ secrets.CLOUDFRONT_SIGNING_PUBLIC_KEY }}
TF_VAR_cloudfront_private_key: ${{ secrets.CLOUDFRONT_SIGNING_PRIVATE_KEY }}
@@ -0,0 +1,85 @@
name: Deploy Dogfood SigNoz
on:
workflow_dispatch:
inputs:
workspace:
description: "Terraform workspace to deploy SigNoz into."
required: true
default: "fleet"
dry_run:
description: Dry run only? No "terraform apply"
type: boolean
default: false
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id}}
cancel-in-progress: true
defaults:
run:
shell: bash
working-directory: infrastructure/dogfood/terraform/aws-tf-module/signoz
env:
AWS_REGION: us-east-2
AWS_IAM_ROLE: arn:aws:iam::160035666661:role/github-actions-role
TF_ACTIONS_WORKING_DIR: infrastructure/dogfood/terraform/aws-tf-module/signoz
TF_WORKSPACE: ${{ github.event.inputs.workspace }}
TF_VAR_otel_bearer_token: ${{ secrets.DOGFOOD_SIGNOZ_OTEL_BEARER_TOKEN }}
permissions:
id-token: write
contents: read
jobs:
deploy:
name: Deploy Dogfood SigNoz
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- id: fail-on-main
run: "false"
if: ${{ github.ref == 'main' }}
- uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # v1.7.0
with:
role-to-assume: ${{ env.AWS_IAM_ROLE }}
aws-region: ${{ env.AWS_REGION }}
- uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3
with:
terraform_version: 1.10.2
terraform_wrapper: false
- name: Set up kubectl
uses: azure/setup-kubectl@18a212d6b26e63d2e08d083e82f0597a6095f08c # v4.0.0
with:
version: v1.31.0
- name: Configure kubeconfig
run: aws eks update-kubeconfig --region "${AWS_REGION}" --name signoz
- name: Terraform Init
id: init
run: terraform init
- name: Terraform fmt
id: fmt
run: terraform fmt -check
continue-on-error: true
- name: Terraform Validate
id: validate
run: terraform validate -no-color
- name: Terraform Plan
id: plan
run: terraform plan -no-color
continue-on-error: true
- name: Terraform Apply
if: inputs.dry_run == false
id: apply
run: terraform apply -auto-approve
@@ -70,6 +70,7 @@ data "aws_iam_policy_document" "gha-permissions" {
"s3:*",
"lambda:*",
"ecs:*",
"eks:*",
"rds:*",
"rds-data:*",
"secretsmanager:*",
@@ -47,6 +47,10 @@ variable "cloudfront_private_key" {}
variable "webhook_url" {
description = "Webhook URL used for Webhook Logging Destination"
}
variable "otel_bearer_token" {
sensitive = true
description = "Bearer token for OTLP ingest into SigNoz."
}
data "aws_caller_identity" "current" {}
@@ -55,9 +59,13 @@ locals {
fleet_image = var.fleet_image # Set this to the version of fleet to be deployed
geolite2_image = "${aws_ecr_repository.fleet.repository_url}:${split(":", var.fleet_image)[1]}-geolite2-${formatdate("YYYYMMDDhhmm", timestamp())}"
extra_environment_variables = {
FLEET_LICENSE_KEY = var.fleet_license
FLEET_LOGGING_DEBUG = "true"
FLEET_LOGGING_JSON = "true"
FLEET_LICENSE_KEY = var.fleet_license
FLEET_LOGGING_DEBUG = "true"
FLEET_LOGGING_JSON = "true"
FLEET_LOGGING_TRACING_ENABLED = "true"
FLEET_LOGGING_TRACING_TYPE = "opentelemetry"
OTEL_SERVICE_NAME = local.customer
OTEL_EXPORTER_OTLP_ENDPOINT = "https://otlp.signoz.dogfood.fleetdm.com"
# FLEET_LOGGING_TRACING_ENABLED = "true"
# FLEET_LOGGING_TRACING_TYPE = "elasticapm"
FLEET_MYSQL_MAX_OPEN_CONNS = "10"
@@ -85,6 +93,9 @@ locals {
sentry_secrets = {
FLEET_SENTRY_DSN = "${aws_secretsmanager_secret.sentry.arn}:FLEET_SENTRY_DSN::"
}
signoz_secrets = {
OTEL_EXPORTER_OTLP_HEADERS = "${aws_secretsmanager_secret.signoz_otel_bearer_token.arn}:OTEL_EXPORTER_OTLP_HEADERS::"
}
# idp_metadata_file = "${path.module}/files/idp-metadata.xml"
/*
@@ -201,13 +212,19 @@ module "main" {
)
extra_execution_iam_policies = concat(
module.mdm.extra_execution_iam_policies,
[aws_iam_policy.sentry.arn, aws_iam_policy.osquery_sidecar.arn, aws_iam_policy.entra_conditional_access.arn],
[
aws_iam_policy.sentry.arn,
aws_iam_policy.osquery_sidecar.arn,
aws_iam_policy.entra_conditional_access.arn,
aws_iam_policy.signoz_otel_bearer_token.arn
],
module.cloudfront-software-installers.extra_execution_iam_policies,
) #, module.saml_auth_proxy.fleet_extra_execution_policies)
extra_secrets = merge(
local.entra_conditional_access_secrets,
module.mdm.extra_secrets,
local.sentry_secrets,
local.signoz_secrets,
module.cloudfront-software-installers.extra_secrets
)
private_key_secret_name = "${local.customer}-fleet-server-private-key"
@@ -427,6 +444,31 @@ data "aws_iam_policy_document" "sentry" {
}
}
resource "aws_secretsmanager_secret" "signoz_otel_bearer_token" {
name = "${local.customer}-signoz-otel-bearer-token"
}
resource "aws_secretsmanager_secret_version" "signoz_otel_bearer_token" {
secret_id = aws_secretsmanager_secret.signoz_otel_bearer_token.id
secret_string = jsonencode({
OTEL_EXPORTER_OTLP_HEADERS = "Authorization=Bearer ${var.otel_bearer_token}"
})
}
resource "aws_iam_policy" "signoz_otel_bearer_token" {
name = "fleet-signoz-otel-bearer-token-policy"
policy = data.aws_iam_policy_document.signoz_otel_bearer_token.json
}
data "aws_iam_policy_document" "signoz_otel_bearer_token" {
statement {
actions = [
"secretsmanager:GetSecretValue",
]
resources = [aws_secretsmanager_secret.signoz_otel_bearer_token.arn]
}
}
module "migrations" {
depends_on = [
module.geolite2
@@ -761,3 +803,7 @@ module "cloudfront-software-installers" {
enable_logging = true
logging_s3_bucket = module.logging_alb.log_s3_bucket_id
}
output "vpc" {
value = module.main.vpc
}
@@ -0,0 +1,569 @@
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.68.0"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.11"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.23"
}
}
backend "s3" {
bucket = "fleet-terraform-state20220408141538466600000002"
key = "dogfood/signoz/terraform.tfstate"
workspace_key_prefix = "dogfood"
region = "us-east-2"
encrypt = true
kms_key_id = "9f98a443-ffd7-4dbe-a9c3-37df89b2e42a"
dynamodb_table = "tf-remote-state-lock"
assume_role = {
role_arn = "arn:aws:iam::353365949058:role/terraform-dogfood"
}
}
}
provider "aws" {
default_tags {
tags = {
environment = "dogfood-signoz"
terraform = "https://github.com/fleetdm/fleet/tree/main/infrastructure/dogfood/terraform/aws-tf-module/signoz"
workspace = terraform.workspace
}
}
}
# Read shared VPC from remote state
data "terraform_remote_state" "dogfood" {
backend = "s3"
workspace = "fleet"
config = {
bucket = "fleet-terraform-remote-state"
key = "fleet"
region = "us-east-2"
dynamodb_table = "fleet-terraform-state-lock"
}
}
# Providers for Helm/Kubernetes after cluster is created
provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
token = data.aws_eks_cluster_auth.signoz.token
}
}
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
token = data.aws_eks_cluster_auth.signoz.token
}
data "aws_region" "current" {}
data "aws_eks_cluster_auth" "signoz" {
name = module.eks.cluster_name
}
data "aws_route53_zone" "dogfood" {
name = "dogfood.fleetdm.com."
}
locals {
cluster_name = "signoz"
signoz_domain = "signoz.dogfood.fleetdm.com"
otlp_domain = "otlp.signoz.dogfood.fleetdm.com"
signoz_alb_name = "signoz-dogfood"
alb_subnets = join(",", compact(data.terraform_remote_state.dogfood.outputs.vpc.private_subnets))
common_ingress_annotations = {
"alb.ingress.kubernetes.io/scheme" = "internal"
"alb.ingress.kubernetes.io/subnets" = local.alb_subnets
"alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTPS\":443}]"
"alb.ingress.kubernetes.io/certificate-arn" = module.acm.acm_certificate_arn
"alb.ingress.kubernetes.io/backend-protocol" = "HTTP"
"alb.ingress.kubernetes.io/target-type" = "ip"
"alb.ingress.kubernetes.io/group.name" = local.signoz_alb_name
"alb.ingress.kubernetes.io/load-balancer-name" = local.signoz_alb_name
}
signoz_ingress_annotations = local.common_ingress_annotations
otlp_ingress_annotations = merge(local.common_ingress_annotations, {
"alb.ingress.kubernetes.io/backend-protocol-version" = "GRPC"
})
}
module "acm" {
source = "terraform-aws-modules/acm/aws"
version = "4.3.1"
domain_name = local.signoz_domain
subject_alternative_names = [local.otlp_domain]
zone_id = data.aws_route53_zone.dogfood.zone_id
wait_for_validation = true
}
# Use shared fleet VPC
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 21.0"
name = local.cluster_name
kubernetes_version = "1.31"
endpoint_public_access = true
vpc_id = data.terraform_remote_state.dogfood.outputs.vpc.vpc_id
subnet_ids = data.terraform_remote_state.dogfood.outputs.vpc.private_subnets
# IMPORTANT: Install critical addons BEFORE node group to avoid circular dependency
# Nodes need VPC CNI to become Ready, but terraform waits for nodes to be Ready
# before creating addons. This causes a deadlock where nodes are stuck NotReady.
# Solution: Use addons with before_compute=true to install VPC CNI before node group completes.
addons = {
vpc-cni = {
most_recent = true
before_compute = true
}
kube-proxy = {
most_recent = true
before_compute = true
}
coredns = {
most_recent = true
before_compute = true
}
}
# Managed node group
eks_managed_node_groups = {
default = {
min_size = 2
max_size = 3
desired_size = 2
instance_types = ["t3.xlarge"]
}
}
# Enable cluster creator admin access
enable_cluster_creator_admin_permissions = true
# Enable OIDC provider for IRSA (IAM Roles for Service Accounts)
enable_irsa = true
}
# IAM Role for EBS CSI Driver Service Account (IRSA)
module "ebs_csi_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.0"
role_name = "${local.cluster_name}-ebs-csi-driver"
attach_ebs_csi_policy = true
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
}
}
}
# IAM Role for AWS Load Balancer Controller Service Account (IRSA)
module "load_balancer_controller_irsa_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.0"
role_name = "${local.cluster_name}-aws-load-balancer-controller"
attach_load_balancer_controller_policy = true
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:aws-load-balancer-controller"]
}
}
}
# EBS CSI Driver addon with IRSA support
# This must be created separately to avoid circular dependency with OIDC provider
resource "aws_eks_addon" "ebs_csi" {
cluster_name = module.eks.cluster_name
addon_name = "aws-ebs-csi-driver"
addon_version = data.aws_eks_addon_version.ebs_csi.version
service_account_role_arn = module.ebs_csi_irsa_role.iam_role_arn
depends_on = [
module.ebs_csi_irsa_role,
module.eks
]
}
data "aws_eks_addon_version" "ebs_csi" {
addon_name = "aws-ebs-csi-driver"
kubernetes_version = module.eks.cluster_version
most_recent = true
}
# Wait for EBS CSI driver to be active
resource "time_sleep" "wait_for_ebs_csi" {
depends_on = [aws_eks_addon.ebs_csi]
create_duration = "60s"
}
# Create gp3 storage class using EBS CSI driver
resource "kubernetes_storage_class_v1" "gp3" {
metadata {
name = "gp3"
annotations = {
"storageclass.kubernetes.io/is-default-class" = "true"
}
}
storage_provisioner = "ebs.csi.aws.com"
reclaim_policy = "Delete"
allow_volume_expansion = true
volume_binding_mode = "WaitForFirstConsumer"
parameters = {
type = "gp3"
encrypted = "true"
fsType = "ext4"
}
depends_on = [time_sleep.wait_for_ebs_csi]
}
# AWS Load Balancer Controller via Helm (managed add-on not available for 1.31 in all regions)
resource "helm_release" "aws_load_balancer_controller" {
name = "aws-load-balancer-controller"
repository = "https://aws.github.io/eks-charts"
chart = "aws-load-balancer-controller"
namespace = "kube-system"
wait = true
wait_for_jobs = false
set {
name = "clusterName"
value = module.eks.cluster_name
}
set {
name = "region"
value = data.aws_region.current.region
}
set {
name = "vpcId"
value = data.terraform_remote_state.dogfood.outputs.vpc.vpc_id
}
set {
name = "serviceAccount.create"
value = "true"
}
set {
name = "serviceAccount.name"
value = "aws-load-balancer-controller"
}
set {
name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
value = module.load_balancer_controller_irsa_role.iam_role_arn
}
depends_on = [
module.eks,
module.load_balancer_controller_irsa_role
]
}
# SigNoz via Helm
resource "helm_release" "signoz" {
name = "signoz"
repository = "https://charts.signoz.io"
chart = "signoz"
namespace = "signoz"
timeout = 3600 # 60 minutes - allows for worst-case AWS delays during both apply and destroy
create_namespace = true
wait = true
wait_for_jobs = false
# OTEL Collector configuration overrides for production stability
values = [
file("${path.module}/otel-collector-values.yaml"),
yamlencode({
signoz = {
ingress = {
annotations = local.signoz_ingress_annotations
}
}
otelCollector = {
ingress = {
annotations = local.otlp_ingress_annotations
}
}
})
]
set {
name = "cloud"
value = "false"
}
set {
name = "signoz.service.type"
value = "ClusterIP"
}
set {
name = "signoz.ingress.enabled"
value = "true"
}
set {
name = "signoz.ingress.className"
value = "alb"
}
set {
name = "signoz.ingress.hosts[0].host"
value = local.signoz_domain
}
set {
name = "signoz.ingress.hosts[0].paths[0].path"
value = "/*"
}
set {
name = "signoz.ingress.hosts[0].paths[0].pathType"
value = "ImplementationSpecific"
}
set {
name = "signoz.ingress.hosts[0].paths[0].port"
value = "8080"
}
# OTLP collector should be internal only (not publicly accessible)
set {
name = "otelCollector.service.type"
value = "ClusterIP"
}
set {
name = "otelCollector.ingress.enabled"
value = "true"
}
set {
name = "otelCollector.ingress.className"
value = "alb"
}
set {
name = "otelCollector.ingress.hosts[0].host"
value = local.otlp_domain
}
set {
name = "otelCollector.ingress.hosts[0].paths[0].path"
value = "/*"
}
set {
name = "otelCollector.ingress.hosts[0].paths[0].pathType"
value = "ImplementationSpecific"
}
set {
name = "otelCollector.ingress.hosts[0].paths[0].port"
value = "4317"
}
# Clickhouse storage configuration
set {
name = "clickhouse.persistence.size"
value = "200Gi"
}
set {
name = "clickhouse.persistence.storageClass"
value = "gp3"
}
# Zookeeper storage configuration
set {
name = "zookeeper.persistence.storageClass"
value = "gp3"
}
# SigNoz (alertmanager) storage configuration
set {
name = "alertmanager.persistence.storageClass"
value = "gp3"
}
# ClickHouse resource configuration for loadtest
# Default 100m CPU and 200Mi memory are way too low for high-volume telemetry
set {
name = "clickhouse.resources.requests.cpu"
value = "2000m"
}
set {
name = "clickhouse.resources.requests.memory"
value = "4Gi"
}
set {
name = "clickhouse.resources.limits.cpu"
value = "4000m"
}
set {
name = "clickhouse.resources.limits.memory"
value = "8Gi"
}
# OTEL Collector resource configuration for loadtest
set {
name = "otelCollector.resources.requests.memory"
value = "8Gi"
}
set {
name = "otelCollector.resources.limits.memory"
value = "12Gi"
}
set {
name = "otelCollector.resources.requests.cpu"
value = "1000m"
}
set {
name = "otelCollector.resources.limits.cpu"
value = "4000m"
}
# Only need 1 replica since we have 1 LoadBalancer endpoint
set {
name = "otelCollector.replicaCount"
value = "1"
}
# Uncomment to force redeployment
#
# set {
# name = "redeployAt"
# value = timestamp()
# }
depends_on = [
module.eks,
kubernetes_storage_class_v1.gp3,
helm_release.aws_load_balancer_controller
]
}
resource "kubernetes_secret" "otel_bearer_token" {
metadata {
name = "signoz-otel-bearer-token"
namespace = "signoz"
}
type = "Opaque"
data = {
OTEL_BEARER_TOKEN = var.otel_bearer_token
}
}
resource "null_resource" "patch_otel_collector_bearer_env" {
triggers = {
token_hash = sha256(var.otel_bearer_token)
helm_release = tostring(helm_release.signoz.metadata[0].revision)
}
provisioner "local-exec" {
command = <<-EOT
set -euo pipefail
kubectl -n signoz set env deployment/signoz-otel-collector \
--containers=collector \
--from=secret/${kubernetes_secret.otel_bearer_token.metadata[0].name}
EOT
}
depends_on = [
helm_release.signoz,
kubernetes_secret.otel_bearer_token
]
}
data "aws_lb" "signoz" {
name = local.signoz_alb_name
depends_on = [null_resource.wait_for_signoz_alb]
}
# Route53 records may require a 2nd apply if the load balancer changes in the EKS cluster.
resource "aws_route53_record" "signoz" {
zone_id = data.aws_route53_zone.dogfood.zone_id
name = local.signoz_domain
type = "A"
alias {
name = data.aws_lb.signoz.dns_name
zone_id = data.aws_lb.signoz.zone_id
evaluate_target_health = true
}
}
resource "null_resource" "wait_for_signoz_alb" {
depends_on = [helm_release.signoz]
triggers = {
alb_name = local.signoz_alb_name
run_id = timestamp()
}
provisioner "local-exec" {
command = <<-EOT
set -euo pipefail
for i in $(seq 1 60); do
if aws elbv2 describe-load-balancers --names "${local.signoz_alb_name}" --region "${data.aws_region.current.region}" >/dev/null 2>&1; then
exit 0
fi
sleep 10
done
echo "Timed out waiting for ALB ${local.signoz_alb_name}" >&2
exit 1
EOT
}
}
resource "aws_route53_record" "otlp" {
zone_id = data.aws_route53_zone.dogfood.zone_id
name = local.otlp_domain
type = "A"
alias {
name = data.aws_lb.signoz.dns_name
zone_id = data.aws_lb.signoz.zone_id
evaluate_target_health = true
}
}
@@ -0,0 +1,84 @@
# OTEL Collector configuration overrides for production stability
# These settings fix ClickHouse timeout issues by adding proper timeouts,
# retry logic, and sending queues.
otelCollector:
# Enable low cardinality exception grouping to reduce exception noise
lowCardinalityExceptionGrouping: true
config:
extensions:
health_check:
endpoint: 0.0.0.0:13133
bearertokenauth:
scheme: "Bearer"
token: ${env:OTEL_BEARER_TOKEN}
receivers:
otlp:
protocols:
grpc:
auth:
authenticator: bearertokenauth
http:
auth:
authenticator: bearertokenauth
exporters:
# Logs exporter with balanced queue sizes for throughput and memory
clickhouselogsexporter:
timeout: 60s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
sending_queue:
enabled: true
num_consumers: 10
queue_size: 10000
# Traces exporter must handle spans after tail_sampling
clickhousetraces:
timeout: 120s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
sending_queue:
enabled: true
num_consumers: 10
queue_size: 10000
# Metadata exporter with increased timeout and retry support
metadataexporter:
timeout: 60s
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
processors:
# Optimized batch processor to send data more frequently
# Smaller batches reduce memory pressure
batch:
send_batch_size: 2000
timeout: 5s
# Memory limiter to prevent out-of-memory by applying back pressure
memory_limiter:
check_interval: 1s
limit_mib: 11264
spike_limit_mib: 512
service:
extensions:
- health_check
- bearertokenauth
pipelines:
traces:
processors:
- memory_limiter
- batch
@@ -0,0 +1,28 @@
output "cluster_name" {
description = "EKS cluster name"
value = module.eks.cluster_name
}
output "cluster_endpoint" {
description = "EKS cluster endpoint"
value = module.eks.cluster_endpoint
}
output "cluster_certificate_authority_data" {
description = "EKS cluster CA certificate"
value = module.eks.cluster_certificate_authority_data
}
output "configure_kubectl" {
value = "aws eks update-kubeconfig --region ${data.aws_region.current.region} --name ${module.eks.cluster_name}"
}
output "signoz_ui_url" {
value = "https://${local.signoz_domain}"
}
# Output for programmatic access - internal LoadBalancer hostname
output "otel_collector_endpoint" {
description = "Internal OTLP collector endpoint (https://host:port)"
value = "https://${local.otlp_domain}:443"
}
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
NAMESPACE="${NAMESPACE:-signoz}"
ENDPOINT="${OTLP_ENDPOINT:-otlp.signoz.dogfood.fleetdm.com:443}"
TOKEN="${OTEL_BEARER_TOKEN:-}"
DURATION="${DURATION:-15s}"
IMAGE="${TELEMETRYGEN_IMAGE:-ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest}"
if [[ -z "${TOKEN}" ]]; then
echo "OTEL_BEARER_TOKEN is required." >&2
exit 1
fi
kubectl -n "${NAMESPACE}" run signoz-telemetrygen \
--rm -i --restart=Never \
--image "${IMAGE}" \
--command -- /telemetrygen traces \
--otlp-endpoint "${ENDPOINT}" \
--otlp-header "authorization=\"Bearer ${TOKEN}\"" \
--duration "${DURATION}"