KubeBlocks
BlogsEnterprise
⌘K
​
Blogs

Overview
Quickstart
Architecture

Operations

Lifecycle Management
Vertical Scaling
Horizontal Scaling
Volume Expansion
Configuration
Minor Version Upgrade
Manage Services

Backup And Restore

Backup
Restore

Monitoring

Observability for ZooKeeper Clusters
FAQs
  1. Prerequisites
  2. Default Services
  3. Expose the ZooKeeper Service Externally
    1. Service Types
  4. Verify the External Service
  5. Connect via the External Endpoint
  6. Disable External Exposure
  7. Cleanup

Manage ZooKeeper Services in KubeBlocks

This guide explains how to expose a ZooKeeper cluster's client port externally using a cloud provider LoadBalancer, and how to disable it when no longer needed.

Prerequisites

    Before proceeding, verify your environment meets these requirements:

    • A functional Kubernetes cluster (v1.21+ recommended)
    • kubectl v1.21+ installed and configured with cluster access
    • Helm installed (installation guide)
    • KubeBlocks installed (installation guide)
    • ZooKeeper Add-on installed and a ZooKeeper cluster running (see Quickstart)

    Default Services

    KubeBlocks creates two ClusterIP services for each ZooKeeper cluster:

    kubectl get service -n demo -l app.kubernetes.io/instance=zookeeper-cluster
    Example Output
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE zookeeper-cluster-zookeeper ClusterIP 172.20.214.61 <none> 2181/TCP,2888/TCP,8080/TCP 8h zookeeper-cluster-zookeeper-readable ClusterIP 172.20.212.120 <none> 2181/TCP,2888/TCP,8080/TCP 8h
    ServiceRoutes toUse case
    zookeeper-cluster-zookeeperLeader onlyWrite operations, coordination
    zookeeper-cluster-zookeeper-readableAll nodesRead-heavy workloads

    Both services expose the following ports:

    PortNameDescription
    2181clientClient connections
    2888quorumFollower-to-leader sync
    8080adminAdmin server (HTTP)

    For in-cluster access (e.g., from Kafka pods), these ClusterIP services are sufficient. External exposure is only needed when clients outside the Kubernetes cluster need to connect.

    Expose the ZooKeeper Service Externally

    Service Types

    TypeUse CaseCost
    ClusterIPIn-cluster access onlyFree
    NodePortDevelopment / testingLow
    LoadBalancerProduction external accessCloud LB cost

    Create an Expose OpsRequest to add a LoadBalancer service that routes to the leader:

    apiVersion: operations.kubeblocks.io/v1alpha1 kind: OpsRequest metadata: name: zk-expose-enable namespace: demo spec: type: Expose clusterName: zookeeper-cluster expose: - componentName: zookeeper services: - name: internet serviceType: LoadBalancer # Cloud provider annotations — adjust for your environment annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb service.beta.kubernetes.io/aws-load-balancer-internal: "false" roleSelector: leader switch: Enable

    Apply it:

    kubectl apply -f zk-expose-enable.yaml

    Monitor the progress:

    kubectl get ops zk-expose-enable -n demo -w
    Example Output
    NAME TYPE CLUSTER STATUS PROGRESS AGE zk-expose-enable Expose zookeeper-cluster Succeed 1/1 5s

    Add a services section to the Cluster resource:

    apiVersion: apps.kubeblocks.io/v1 kind: Cluster metadata: name: zookeeper-cluster namespace: demo spec: terminationPolicy: Delete services: - name: zookeeper-internet serviceName: internet componentSelector: zookeeper roleSelector: leader annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb service.beta.kubernetes.io/aws-load-balancer-internal: "false" spec: type: LoadBalancer ports: - name: client port: 2181 protocol: TCP targetPort: 2181 componentSpecs: - name: zookeeper componentDef: zookeeper serviceVersion: "3.9.4" replicas: 3 resources: limits: cpu: '0.5' memory: 0.5Gi requests: cpu: '0.5' memory: 0.5Gi volumeClaimTemplates: - name: data spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi - name: snapshot-log spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi
    NOTE

    Cloud Provider Annotations

    Adjust the annotations for your cloud provider:

    • AWS
      service.beta.kubernetes.io/aws-load-balancer-type: nlb service.beta.kubernetes.io/aws-load-balancer-internal: "false" # "true" for VPC-internal
    • Azure
      service.beta.kubernetes.io/azure-load-balancer-internal: "false"
    • GCP
      cloud.google.com/l4-rbs: "enabled"
    • Alibaba Cloud
      service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "internet"

    Verify the External Service

    kubectl get service -n demo -l app.kubernetes.io/instance=zookeeper-cluster
    Example Output
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE zookeeper-cluster-zookeeper ClusterIP 172.20.214.61 <none> 2181/TCP,2888/TCP,8080/TCP 8h zookeeper-cluster-zookeeper-internet LoadBalancer 172.20.95.145 a3f9688f32658409e90fbc71ecd128fd-ef3cc6918432f88f.elb.ap-southeast-1.amazonaws.com 2181:30411/TCP,2888:31938/TCP,8080:32272/TCP 68s zookeeper-cluster-zookeeper-readable ClusterIP 172.20.212.120 <none> 2181/TCP,2888/TCP,8080/TCP 8h

    The LoadBalancer DNS name may take 2–5 minutes to become resolvable after provisioning.

    Connect via the External Endpoint

    Once the DNS resolves, connect using the ZooKeeper CLI or any ZooKeeper client:

    zkCli.sh -server <EXTERNAL-IP>:2181

    Or test with netcat:

    echo "ruok" | nc <EXTERNAL-IP> 2181

    Expected response: imok

    Disable External Exposure

    apiVersion: operations.kubeblocks.io/v1alpha1 kind: OpsRequest metadata: name: zk-expose-disable namespace: demo spec: clusterName: zookeeper-cluster type: Expose expose: - componentName: zookeeper services: - name: internet serviceType: LoadBalancer roleSelector: leader switch: Disable preConditionDeadlineSeconds: 0

    Apply it:

    kubectl apply -f zk-expose-disable.yaml
    Example Output
    NAME TYPE CLUSTER STATUS PROGRESS AGE zk-expose-disable Expose zookeeper-cluster Succeed 1/1 5s

    Remove the spec.services field:

    kubectl patch cluster zookeeper-cluster -n demo --type=json \ -p='[{"op": "remove", "path": "/spec/services"}]'

    Verify the LoadBalancer service is removed:

    kubectl get service -n demo -l app.kubernetes.io/instance=zookeeper-cluster

    The zookeeper-cluster-zookeeper-internet service should no longer appear.

    Cleanup

    kubectl delete cluster zookeeper-cluster -n demo kubectl delete ns demo

    © 2026 KUBEBLOCKS INC