Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.popsink.com/llms.txt

Use this file to discover all available pages before exploring further.

This page is intended for integrators who install Popsink in their own Kubernetes cluster. The chart deploys a self-hosted Popsink data plane — the runtime that moves data from your sources to your targets. It connects to a control plane (managed by Popsink at control-plane.popsink.com, or your own) which orchestrates and monitors the deployment.

Architecture overview

The chart deploys the following components:
ComponentPurposeDefault
data-planeMain API + UI. Talks to the control plane, manages connectorsenabled
tansuStateless Kafka-compatible broker, S3-backedenabled
karapaceSchema Registry (Avro / JSON Schema) for Tansuenabled
metrics-exporterExports pipeline & connector metrics to the control planeenabled
kafka-uiWeb UI for Kafka inspectionenabled
postgresqlBitnami sub-chart, in-cluster Postgres for the data-plane DBenabled
You can disable any sub-component and bring your own:
  • External Kafkatansu.enabled=false, configure defaultKafka.*
  • External Schema Registrykarapace.enabled=false, configure schemaRegistry.*
  • External PostgreSQLpostgresql.enabled=false, configure externalDatabase.*
The chart does not manage ingress. You must set up your own ingress controller (Traefik, NGINX, Istio…) and point a DNS record to it. See Ingress below.

Prerequisites

Cluster

RequirementMinimum
Kubernetes1.23+
Helm3.8.0+
Worker nodes2 nodes, amd64
Per-node4 vCPU, 16 GB RAM
Persistent volumeSSD-backed StorageClass, ≥ 200 GB available
IngressTraefik / NGINX / Istio (or any IngressClass-compatible)
Object storageS3-compatible bucket (recommended for Tansu)

Access to Popsink images

All images are published to a private GAR registry:
europe-west1-docker.pkg.dev/popsink-common-438615/onprem
Popsink will provide you with a service-account JSON token to pull these images.
Let the chart create the imagePullSecret for you:
imagePullSecret:
  create: true
  registry: europe-west1-docker.pkg.dev/popsink-common-438615/onprem
  token: |
    <base64-encoded service account JSON, or the JSON itself>

Onboarding flow (control plane)

Before installing the chart, you need a deployment ID and a deployment JWT token issued by the control plane.
1

Open the control plane

Log into https://control-plane.popsink.com (or your own control plane).
2

Create a self-hosted deployment

Open Deployments → New deployment and pick Self-hosted.
3

Fill the wizard

  • Optional pre-fill of PostgreSQL credentials (not stored).
  • Retention strategy — pick S3-compatible storage (recommended) or PostgreSQL.
  • FQDN — the public URL where the data plane will be reachable (e.g. https://popsink.your-company.com).
4

Copy the values snippet

The wizard outputs a values-control-plane.yaml snippet containing controlPlaneUrl, deploymentId and deploymentJwtToken. Use these values verbatim — they identify and authenticate your data plane against the control plane.
5

Wait for connection

Keep the wizard open. After helm install, the control plane will switch from Awaiting connection… to Connected once the data plane registers.

Required secrets to generate yourself

Beyond the values handed by the control plane, you must generate four secrets locally:
SecretFormatHow to generate
adminCredentials.username / passwordanyPick a strong password
jwt.secretrandom string ≥ 32 charsopenssl rand -base64 48
connectorConfigEncryptionKey.keyURL-safe base64-encoded 32-byte Fernet keypython -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
postgresql.auth.password (or externalDatabase.password)anyopenssl rand -base64 24
These four secrets encrypt connector credentials, sign user sessions and protect the admin login. Lose them and you lose access to your stored connector configs. Back them up in your secret manager.
If you prefer to manage secrets out of band (Vault, Sealed Secrets, External Secrets Operator…), set the corresponding existingSecret field instead.

Tansu storage (S3)

Tansu is a stateless Kafka broker that stores log segments in S3. You must provide an S3-compatible bucket and a way to authenticate.
tansu:
  storage:
    engine: "s3://my-popsink-bucket/kafka/"
    aws:
      region: eu-west-1
      irsaRoleArn:    arn:aws:iam::123456789012:role/popsink-tansu
      assumedRoleArn: arn:aws:iam::123456789012:role/popsink-tansu
The bucket must exist, be writable by the configured identity, and ideally have object versioning enabled.
If you don’t want Tansu, set tansu.enabled=false and karapace.enabled=false, then point the data plane at your existing Kafka:
tansu:    { enabled: false }
karapace: { enabled: false }

defaultKafka:
  bootstrapServer: kafka.example.com:9093
  securityProtocol: SASL_SSL
  saslMechanism: SCRAM-SHA-512
  saslUsername: popsink
  saslPassword: <secret>
  caCert: |-
    -----BEGIN CERTIFICATE-----

  cert: ""
  key:  ""

schemaRegistry:
  url: https://schema-registry.example.com
  username: popsink
  password: <secret>

Ingress

The chart’s built-in ingress.enabled flag is off by default and we recommend leaving it that way: ingress in production usually needs company-specific annotations (cert-manager, WAF, allow-lists). Provide your own Ingress resource that exposes:
  • the data-plane HTTP service (<release>-data-plane, port 80),
  • on the FQDN you declared in the control plane (ingressUrl).
Example with NGINX + cert-manager:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: popsink
  namespace: popsink
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts: [popsink.your-company.com]
      secretName: popsink-tls
  rules:
    - host: popsink.your-company.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: <release>-data-plane
                port: { number: 80 }
If you want the chart to render an Ingress for you, set ingress.enabled=true and configure ingress.hostname, ingress.ingressClassName, ingress.tls.
The value of ingressUrl in the chart must match the public URL the control plane redirects users to (it is also used for OAuth-style callbacks):
ingressUrl: "https://popsink.your-company.com"

Putting it together — minimal values.yaml

values.yaml
# ───── Identity (from the control-plane wizard) ─────
controlPlaneUrl:         https://control-plane-api.popsink.com/api
controlPlaneFrontendUrl: https://control-plane.popsink.com
deploymentMode: SELF_HOSTED
deploymentId:   <uuid-from-wizard>
deploymentJwtToken:
  token: <jwt-from-wizard>

# ───── Public URL of this data plane ─────
ingressUrl: https://popsink.your-company.com

# ───── Image pull ─────
imagePullSecret:
  create: true
  token: <gar-service-account-json>

# ───── Secrets you generated ─────
adminCredentials:
  username: admin
  password: <strong-password>
jwt:
  secret: <openssl rand -base64 48>
connectorConfigEncryptionKey:
  key: <fernet-key>

# ───── In-cluster Postgres (default) ─────
postgresql:
  enabled: true
  auth:
    password: <strong-password>
  primary:
    persistence:
      size: 50Gi
      storageClass: <your-ssd-class>

# ───── Tansu + S3 ─────
tansu:
  enabled: true
  storage:
    engine: "s3://my-popsink-bucket/kafka/"
    aws:
      region: eu-west-1
      irsaRoleArn:    arn:aws:iam::123:role/popsink-tansu
      assumedRoleArn: arn:aws:iam::123:role/popsink-tansu

karapace:
  enabled: true

Install

# 1. Create the namespace
kubectl create namespace popsink

# 2. Install (chart is published as an OCI artifact)
helm install popsink \
  oci://ghcr.io/popsink/charts/data-plane \
  -n popsink \
  -f values.yaml \
  --version <chart-version>
Use helm search repo or check the chart’s Chart.yaml (version:) to pin the chart version. Pinning avoids surprise upgrades.
Watch the rollout:
kubectl -n popsink get pods -w
When all pods are Ready, head back to the control-plane deployment page — the status should flip from Awaiting connection… to Connected within a minute. Open ingressUrl and log in with the adminCredentials you set.

Production checklist

  • Pin the chart version (--version) and the application image (image.tag) — never deploy latest.
  • Use external PostgreSQL (postgresql.enabled=false, externalDatabase.*) backed by managed snapshots, not the in-cluster Bitnami chart.
  • Use external S3 with versioning + lifecycle policy for Tansu.
  • Set explicit resources.requests/limits on every component (defaults target small-medium clusters; tune for your workload).
  • Configure replicaCount ≥ 2 on data-plane (default), keep tansu.replicaCount=3 (default).
  • Enable pdb.create: true (default) — at least 1 pod stays during node drains.
  • Provide imagePullSecrets via a sealed secret / external secrets controller, not plain values.
  • Back up the four secrets (admin credentials, JWT secret, Fernet key, DB password) in your secret manager.
  • Keep allowDesignLogin: false (default) and pipelineMode: false unless explicitly told otherwise — these are dev-only switches.
  • Ingress: TLS-only, cert-manager (or equivalent), restrict source ranges if your data plane is internet-exposed only for known IPs.

Upgrade

helm upgrade popsink \
  oci://ghcr.io/popsink/charts/data-plane \
  -n popsink \
  -f values.yaml \
  --version <new-chart-version>
The data plane runs DB migrations on startup. Watch a pod’s logs:
kubectl -n popsink logs -l app.kubernetes.io/component=data-plane -f

Uninstall

helm uninstall popsink -n popsink
By default the PostgreSQL PVC and Tansu/S3 data are kept (postgresql.primary.persistentVolumeClaimRetentionPolicy.whenDeleted=Retain, S3 buckets are external). Delete them manually if you want a clean slate:
kubectl -n popsink delete pvc -l app.kubernetes.io/instance=popsink
aws s3 rm s3://my-popsink-bucket/kafka/ --recursive   # ⚠ destroys all topics

Troubleshooting

SymptomLikely cause
Control plane stays on “Awaiting connection…”Wrong controlPlaneUrl / deploymentId / deploymentJwtToken, or egress to the control plane is blocked
data-plane pods crash-loop on connector-config-encryption-keyFernet key is not a valid URL-safe base64-encoded 32-byte string
tansu pods CrashLoopBackOff with S3 errorsstorage.engine, region, or IAM role/credentials are wrong; bucket missing
ImagePullBackOff on every podimagePullSecret.token not set / not a valid GAR service-account JSON
Login at ingressUrl fails with redirect loopingressUrl doesn’t match the public URL fronted by your ingress
Workers (connectors) never become LIVEThe data-plane pod cannot reach Tansu / Karapace inside the cluster — check NetworkPolicy
Ingress 502 on /api/livezService name in your Ingress doesn’t match <release>-data-plane
For deeper logs:
kubectl -n popsink logs -l app.kubernetes.io/component=data-plane --tail=200
kubectl -n popsink logs -l app.kubernetes.io/component=tansu       --tail=200
kubectl -n popsink logs -l app.kubernetes.io/component=karapace    --tail=200

Reference — most useful values

A full list lives in values.yaml (annotated with @param blocks). The most common knobs are:
PathWhat it does
controlPlaneUrl / controlPlaneFrontendUrlControl plane API and UI URLs
deploymentId, deploymentJwtToken.tokenIdentity vs. control plane
ingressUrlPublic URL of this data plane
image.tagPin the data-plane image version
replicaCountData-plane API replicas (default 2)
resourcesData-plane CPU / memory requests / limits
imagePullSecret.* / global.imagePullSecretsHow to authenticate to the GAR registry
adminCredentials.*First admin login
jwt.secretSigns user session tokens
connectorConfigEncryptionKey.keyEncrypts connector credentials at rest
tansu.enabled, tansu.storage.*In-cluster Kafka or BYO; S3 backend
karapace.enabled / schemaRegistry.*In-cluster Schema Registry or BYO
postgresql.enabled / externalDatabase.*In-cluster Postgres or BYO
metricsExporter.*Pushes metrics to the control plane
kafkaUi.*Optional Kafka inspection UI
pdb.createPodDisruptionBudget (default true)
autoscaling.hpa.*, autoscaling.vpa.*HPA / VPA — disabled by default

Further reading

Installation prerequisites

Hardware, ingress and storage requirements for a Popsink-ready cluster.

Self-hosted onboarding

The control-plane wizard that issues your deploymentId and JWT token.