How a client reaches a broker
Every Pulsar connection happens in two steps. The first connection can go to any broker, because any broker can answer a lookup. The second connection must reach one specific broker. If every broker advertises the same address, the second connection lands on whichever broker the load balancer chooses, and the client receivesServiceNotReady ... Please redo the lookup until it happens to reach the owner.
That failure is intermittent rather than total. Topics owned by the broker the shared address reaches will work, which makes partial success a symptom of the problem rather than a sign of progress.
Reference architecture
To satisfy the second step, each broker needs its own externally resolvable address, and the ingress needs a way to tell those addresses apart. The only field in a Pulsar connection that carries the intended broker is the TLS server name, so the architecture is built around preserving it. Four properties make this work:- The load balancer forwards TCP without terminating TLS, so the server name survives to the gateway.
- The gateway holds the certificate, terminates TLS, and selects a route by server name.
- Each route forwards to one broker, not to a service that fronts all of them.
- Each broker advertises its own external hostname, so the address a client receives from a lookup matches a route.
Whichever component terminates TLS consumes the server name. Every hop behind it sees an undifferentiated TCP stream and can no longer tell brokers apart, which is why termination belongs at the gateway rather than at the load balancer.
Ports
Each broker exposes several listeners, and the port a client connects to determines which address the broker returns.
Clients connect on 6651. The gateway terminates TLS and forwards plaintext to 6652, which is why the port a client dials and the port a broker listens on are different. Brokers need no certificates of their own in this arrangement.
Configure the brokers
Enable the gateway listener and set the advertised domain on thePulsarBroker resource. Each broker then advertises <pod-name>-<advertisedDomain>, for example pulsar-broker-0-broker.example.com.
Configure the ingress
Create one route per broker, plus one for lookups. Match on the TLS server name and forward to that broker’s backend.
The lookup route may target the shared broker Service, because any broker can answer a lookup. The per-broker routes must each reach exactly one broker. How you express a single broker as a backend depends on the ingress: routing generated for an Istio gateway addresses the Pod through the headless Service, while Kubernetes Gateway API routes need a per-Pod Service. The rule set grows with the broker count, so adding brokers means adding routes.
Requirements
Before clients can connect, all of the following must be true:- Port 6651 reaches the ingress gateway as plain TCP, without TLS termination at the edge.
- DNS resolves the cluster hostname and every per-broker hostname to the ingress. A wildcard record for the external domain covers both.
- The certificate presented by the gateway covers the cluster hostname and every per-broker hostname.
- One routing rule exists per broker, matching on TLS server name.
- Clients connect with
pulsar+ssl://on 6651 and trust the certificate chain.