Service exposition with ListenerClasses

The operator deploys a bootstrap Listener for each broker rolegroup, as well as a Listener for each broker pod.

The bootstrap Listener is used to negotiate clients' initial connection to the cluster, after which a connection is made to the relevant broker Listeners.

Every bootstrap Listener (regardless of the underlying rolegroup) will direct clients to the broker listeners of all brokers of all rolegroups.

They both default to only being accessible from within the Kubernetes cluster, but this can be changed by setting .spec.brokers.config.{bootstrap,broker}ListenerClass.

The cluster can be configured to be accessible from outside of Kubernetes like this:

spec:
  brokers:
    config:
      bootstrapListenerClass: external-stable (1)
      brokerListenerClass: external-unstable (2)
1 Bootstrap listeners should prioritize having a stable address, since they will be baked into the client configuration.
2 Broker listeners should prioritize having a direct connection, to minimize network transfer overhead.
All rolegroups should use the same ListenerClass, or at least ones with similar properties. Clients will be unable to access data stored on replicas in rolegroups with inaccessible ListenerClasses.