Skip to main content

Configure BYOC on Kubernetes

This guide installs a reference collector and connects the Speedscale Forwarder to it. Repeat the backend and exporter steps for every independent destination channel.

Prerequisites

  • A Kubernetes cluster such as EKS, GKE, AKS, k3s, or minikube
  • kubectl configured for the cluster and Helm 3
  • A Speedscale API key with BYOC enabled
  • Credentials and an existing destination for the backend you select

1. Add the Helm repositories

helm repo add speedscale https://speedscale.github.io/operator-helm/
helm repo add speedscale-byoc https://speedscale.github.io/speedscale-byoc/
helm repo update

2. Create the Speedscale API key Secret

kubectl create namespace speedscale
kubectl -n speedscale create secret generic speedscale-apikey \
--from-literal=SPEEDSCALE_API_KEY="<YOUR_API_KEY>" \
--from-literal=SPEEDSCALE_APP_URL="app.speedscale.com"

3. Install a backend collector

Install each collector in its own namespace. The chart README contains its complete IAM policy, credential, and configuration options.

Amazon S3 with static credentials

kubectl create namespace byoc-s3
kubectl -n byoc-s3 create secret generic s3-creds \
--from-literal=accessKeyId="<AWS_ACCESS_KEY_ID>" \
--from-literal=secretAccessKey="<AWS_SECRET_ACCESS_KEY>"

helm upgrade --install byoc-s3 speedscale-byoc/fluentbit-s3 \
-n byoc-s3 \
--set s3.bucket="<S3_BUCKET>" \
--set s3.region="<AWS_REGION>" \
--set s3.credentialsSecret="s3-creds"

Amazon S3 with EKS IAM Roles for Service Accounts

helm upgrade --install byoc-s3 speedscale-byoc/fluentbit-s3 \
-n byoc-s3 --create-namespace \
--set s3.bucket="<S3_BUCKET>" \
--set s3.region="<AWS_REGION>" \
--set irsa.enabled=true \
--set irsa.roleArn="arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>"

Native Google Cloud Storage

The chart reuses an existing bucket. Its Google service account (GSA) therefore needs storage.objects.create to write objects and storage.buckets.get to check that the bucket exists. roles/storage.objectCreator contains only the first permission, so add a narrowly scoped custom role for the second.

Create the GSA and custom role, then grant both roles on the bucket:

gcloud iam service-accounts create byoc-gcs \
--project=<GCP_PROJECT>

gcloud iam roles create speedscaleByocBucketReader \
--project=<GCP_PROJECT> \
--title="Speedscale BYOC bucket reader" \
--permissions=storage.buckets.get \
--stage=GA

gcloud storage buckets add-iam-policy-binding gs://<GCS_BUCKET> \
--member="serviceAccount:byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com" \
--role="roles/storage.objectCreator"

gcloud storage buckets add-iam-policy-binding gs://<GCS_BUCKET> \
--member="serviceAccount:byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com" \
--role="projects/<GCP_PROJECT>/roles/speedscaleByocBucketReader"

The GCS exporter documents the extra bucket-read permission required by reuse_if_exists. The predefined Storage Object Creator role does not include it.

With Workload Identity Federation enabled on the cluster and node pool, link the deterministic Kubernetes service account (KSA) byoc-gcs in namespace byoc-gcs to the GSA. Both this IAM binding and the annotation in the Helm values are required by the GKE service-account linking procedure:

gcloud iam service-accounts add-iam-policy-binding \
byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com \
--role="roles/iam.workloadIdentityUser" \
--member="serviceAccount:<GCP_PROJECT>.svc.id.goog[byoc-gcs/byoc-gcs]"

Configure the KSA name and GSA annotation in values-gcs.yaml:

gcs:
project: <GCP_PROJECT>
bucket: <GCS_BUCKET>
region: <GCS_REGION>
serviceAccount:
name: byoc-gcs
annotations:
iam.gke.io/gcp-service-account: byoc-gcs@<GCP_PROJECT>.iam.gserviceaccount.com
helm upgrade --install byoc-gcs speedscale-byoc/gcs \
-n byoc-gcs --create-namespace \
-f values-gcs.yaml

Loki and Grafana

helm upgrade --install byoc-grafana speedscale-byoc/grafana \
-n byoc-grafana --create-namespace

Elasticsearch and Kibana

helm upgrade --install byoc-elasticsearch speedscale-byoc/elasticsearch \
-n byoc-elasticsearch --create-namespace

For Azure Blob, Datadog, Dynatrace, New Relic, and advanced values, select the chart from the backend guide and follow its README.

4. Configure named Forwarder exporters

Add one entry under forwarder.exporters for every collector. Keep filters and DLP configuration explicit per destination:

forwarder:
exporters:
byoc_s3:
otel_endpoint: "http://otel-collector.byoc-s3.svc.cluster.local:4317"
filter_rule: standard
dlp_config_id: standard
byoc_gcs:
otel_endpoint: "http://byoc-gcs-gcs.byoc-gcs.svc.cluster.local:4317"
filter_rule: standard
dlp_config_id: standard
byoc_grafana:
otel_endpoint: "http://otel-collector.byoc-grafana.svc.cluster.local:4317"
filter_rule: standard
dlp_config_id: standard

Install or upgrade the operator with that values file:

helm upgrade --install speedscale-operator speedscale/speedscale-operator \
-n speedscale --create-namespace \
--set apiKeySecret=speedscale-apikey \
--set clusterName=<CLUSTER_NAME> \
-f values.yaml
caution

Use the receiver's actual protocol port. A reference collector normally uses OTLP/gRPC on 4317. Including http:// is recommended for compatibility with Forwarder versions older than v2.5.617; newer Forwarders also accept scheme-less gRPC endpoints.

5. Enable capture

Annotate the workload you want to capture:

kubectl patch deployment my-app -p \
'{"spec":{"template":{"metadata":{"annotations":{"capture.speedscale.com/enabled":"true"}}}}}'

The operator restarts or injects the required capture component according to the selected installation mode. Send a known request through the workload, then verify each BYOC hop.