You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by nd...@apache.org on 2023/05/09 13:09:53 UTC

[hbase-operator-tools] 03/06: HBASE-27831 Introduce zookeeper-single-instance component

This is an automated email from the ASF dual-hosted git repository.

ndimiduk pushed a commit to branch 27834-introduce-ha-hdfs-overlay
in repository https://gitbox.apache.org/repos/asf/hbase-operator-tools.git

commit 76232bd61ed51a6fcd486da078f8b6ab7f18aa74
Author: Nick Dimiduk <nd...@apache.org>
AuthorDate: Mon May 1 13:24:22 2023 +0200

    HBASE-27831 Introduce zookeeper-single-instance component
---
 .../components/zookeeper/README.md                 |  23 ++
 .../zookeeper/single-instance/kustomization.yaml   |  35 ++
 .../components/zookeeper/single-instance/start.sh  | 352 +++++++++++++++++++++
 .../zookeeper/single-instance/zookeeper.yaml       | 142 +++++++++
 .../00-assert-zookeeper.yaml                       |  26 ++
 .../components_zookeeper_single/00-kustomize.yaml  |  21 ++
 .../components_zookeeper_single/kustomization.yaml |  21 ++
 .../00-assert-zookeeper.yaml                       |  49 +++
 .../components_zookeeper_single/00-kustomize.yaml  |  21 ++
 .../components_zookeeper_single/kustomization.yaml |  21 ++
 10 files changed, 711 insertions(+)

diff --git a/hbase-kubernetes-deployment/components/zookeeper/README.md b/hbase-kubernetes-deployment/components/zookeeper/README.md
new file mode 100644
index 0000000..b6af185
--- /dev/null
+++ b/hbase-kubernetes-deployment/components/zookeeper/README.md
@@ -0,0 +1,23 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+Uses latest image from the apache zookeeper project.
+There is then a start script in 'single-instance/start.sh'
+which sets parameters for the zookeeper image and process
+on startup. Currently only logs to STDOUT/STDERR; there
+are no files in /var/log/zookeeper.
diff --git a/hbase-kubernetes-deployment/components/zookeeper/single-instance/kustomization.yaml b/hbase-kubernetes-deployment/components/zookeeper/single-instance/kustomization.yaml
new file mode 100644
index 0000000..1e87468
--- /dev/null
+++ b/hbase-kubernetes-deployment/components/zookeeper/single-instance/kustomization.yaml
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+---
+apiVersion: kustomize.config.k8s.io/v1alpha1
+kind: Component
+
+configMapGenerator:
+- name: zookeeper-scripts
+  files:
+  - start.sh
+# Publish where the zk ensemble can be found.
+- name: zookeeper-quorum
+  literals:
+    # Hard-coded. Default we expect a simple standalone zk at this location.
+    # One define is for hbase, the other for hadoop.
+    - HBASE_ZOOKEEPER_QUORUM="zookeeper-0.zookeeper-headless"
+    - HA_ZOOKEEPER_QUORUM="zookeeper-0.zookeeper-headless:2181"
+  options:
+    disableNameSuffixHash: true
+
+resources:
+- zookeeper.yaml
diff --git a/hbase-kubernetes-deployment/components/zookeeper/single-instance/start.sh b/hbase-kubernetes-deployment/components/zookeeper/single-instance/start.sh
new file mode 100755
index 0000000..d35e6d8
--- /dev/null
+++ b/hbase-kubernetes-deployment/components/zookeeper/single-instance/start.sh
@@ -0,0 +1,352 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Derived from work Copyright 2017 The Kubernetes Authors.
+# See https://github.com/kow3ns/kubernetes-zookeeper/blob/master/docker/scripts/start-zookeeper for more details
+# and then https://github.com/cloudurable/kube-zookeeper-statefulsets/
+# In the below we change the '--heap' argument to '--percentage' so
+# could set the server heap as a percentage of the container resource
+# limit rather than hard-code it.
+# Currently zookeeper.root.logger is CONSOLE only. We do not write
+# logs to files. Fix config. if you need it.
+#
+#
+# Usage: start-zookeeper [OPTIONS]
+# Starts a ZooKeeper server based on the supplied options.
+#     --servers           The number of servers in the ensemble. The default
+#                         value is 1.
+#     --data_dir          The directory where the ZooKeeper process will store its
+#                         snapshots. The default is /var/lib/zookeeper/data.
+#     --data_log_dir      The directory where the ZooKeeper process will store its
+#                         write ahead log. The default is
+#                         /var/lib/zookeeper/data/log.
+#     --conf_dir          The directory where the ZooKeeper process will store its
+#                         configuration. The default is /opt/zookeeper/conf.
+#     --client_port       The port on which the ZooKeeper process will listen for
+#                         client requests. The default is 2181.
+
+#     --election_port     The port on which the ZooKeeper process will perform
+#                         leader election. The default is 3888.
+
+#     --server_port       The port on which the ZooKeeper process will listen for
+#                         requests from other servers in the ensemble. The
+#                         default is 2888.
+
+#     --tick_time         The length of a ZooKeeper tick in ms. The default is
+#                         2000.
+
+#     --init_limit        The number of Ticks that an ensemble member is allowed
+#                         to perform leader election. The default is 10.
+
+#     --sync_limit        The maximum session timeout that the ensemble will
+#                         allows a client to request. The default is 5.
+
+#     --percentage        The percentage of container memory to give to the JVM.
+
+#     --max_client_cnxns  The maximum number of client connections that the
+#                         ZooKeeper process will accept simultaneously. The
+#                         default is 60.
+
+#     --snap_retain_count The maximum number of snapshots the ZooKeeper process
+#                         will retain if purge_interval is greater than 0. The
+#                         default is 3.
+
+#     --purge_interval    The number of hours the ZooKeeper process will wait
+#                         between purging its old snapshots. If set to 0 old
+#                         snapshots will never be purged. The default is 0.
+
+#     --max_session_timeout The maximum time in milliseconds for a client session
+#                         timeout. The default value is 2 * tick time.
+
+#     --min_session_timeout The minimum time in milliseconds for a client session
+#                         timeout. The default value is 20 * tick time.
+
+#     --log_level         The log level for the zookeeeper server. Either FATAL,
+#                         ERROR, WARN, INFO, DEBUG. The default is INFO.
+
+#     --quorum_listen_on_all_ips
+#                         When set to true the ZooKeeper server will listen for
+#                         connections from its peers on all available IP addresses,
+#                         and not only the address configured in the server list of
+#                         the configuration file. It affects the connections handling
+#                         the ZAB protocol and the Fast Leader Election protocol.
+#                         Default value is false.
+set -x
+
+ZOOKEEPER_HOME="$( ls -d /apache-zookeeper*  )"
+USER=`whoami`
+HOST=`hostname -s`
+DOMAIN=`hostname -d`
+LOG_LEVEL=INFO
+DATA_DIR="/var/lib/zookeeper/data"
+DATA_LOG_DIR="/var/lib/zookeeper/log"
+LOG_DIR="/var/log/zookeeper"
+CONF_DIR="/opt/zookeeper/conf"
+CLIENT_PORT=2181
+SERVER_PORT=2888
+ELECTION_PORT=3888
+PROM_PORT=7001
+TICK_TIME=2000
+INIT_LIMIT=10
+SYNC_LIMIT=5
+JVM_HEAP_PERCENTAGE_OF_RESOURCE_LIMIT=50
+MAX_CLIENT_CNXNS=1000
+SNAP_RETAIN_COUNT=3
+PURGE_INTERVAL=0
+SERVERS=1
+QUORUM_LISTEN_ON_ALL_IPS=false
+
+function print_usage() {
+echo "\
+Usage: start-zookeeper [OPTIONS]
+Starts a ZooKeeper server based on the supplied options.
+    --servers           The number of servers in the ensemble. The default
+                        value is 1.
+
+    --data_dir          The directory where the ZooKeeper process will store its
+                        snapshots. The default is /var/lib/zookeeper/data.
+
+    --data_log_dir      The directory where the ZooKeeper process will store its
+                        write ahead log. The default is
+                        /var/lib/zookeeper/data/log.
+
+    --conf_dir          The directoyr where the ZooKeeper process will store its
+                        configuration. The default is /opt/zookeeper/conf.
+
+    --client_port       The port on which the ZooKeeper process will listen for
+                        client requests. The default is 2181.
+
+    --election_port     The port on which the ZooKeeper process will perform
+                        leader election. The default is 3888.
+
+    --server_port       The port on which the ZooKeeper process will listen for
+                        requests from other servers in the ensemble. The
+                        default is 2888.
+
+    --tick_time         The length of a ZooKeeper tick in ms. The default is
+                        2000.
+
+    --init_limit        The number of Ticks that an ensemble member is allowed
+                        to perform leader election. The default is 10.
+
+    --sync_limit        The maximum session timeout that the ensemble will
+                        allows a client to request. The default is 5.
+
+    --percentage        The percentage of container memory to give to the JVM.
+
+    --max_client_cnxns  The maximum number of client connections that the
+                        ZooKeeper process will accept simultaneously. The
+                        default is 60.
+
+    --snap_retain_count The maximum number of snapshots the ZooKeeper process
+                        will retain if purge_interval is greater than 0. The
+                        default is 3.
+
+    --purge_interval    The number of hours the ZooKeeper process will wait
+                        between purging its old snapshots. If set to 0 old
+                        snapshots will never be purged. The default is 0.
+
+    --max_session_timeout The maximum time in milliseconds for a client session
+                        timeout. The default value is 2 * tick time.
+
+    --min_session_timeout The minimum time in milliseconds for a client session
+                        timeout. The default value is 20 * tick time.
+
+    --log_level         The log level for the zookeeeper server. Either FATAL,
+                        ERROR, WARN, INFO, DEBUG. The default is INFO.
+"
+}
+
+function create_data_dirs() {
+    if [ ! -d $DATA_DIR  ]; then
+        mkdir -p $DATA_DIR
+        chown -R $USER:$USER $DATA_DIR
+    fi
+
+    if [ ! -d $DATA_LOG_DIR  ]; then
+        mkdir -p $DATA_LOG_DIR
+        chown -R $USER:USER $DATA_LOG_DIR
+    fi
+
+    if [ ! -d $LOG_DIR  ]; then
+        mkdir -p $LOG_DIR
+        chown -R $USER:$USER $LOG_DIR
+    fi
+    if [ ! -f $ID_FILE ] && [ $SERVERS -gt 1 ]; then
+        echo $MY_ID >> $ID_FILE
+    fi
+}
+
+function print_servers() {
+    for (( i=1; i<=$SERVERS; i++ ))
+    do
+        echo "server.$i=$NAME-$((i-1)).$DOMAIN:$SERVER_PORT:$ELECTION_PORT"
+    done
+}
+
+function create_config() {
+    rm -f $CONFIG_FILE
+    echo "#This file was autogenerated DO NOT EDIT" >> $CONFIG_FILE
+    echo "clientPort=$CLIENT_PORT" >> $CONFIG_FILE
+    echo "dataDir=$DATA_DIR" >> $CONFIG_FILE
+    echo "dataLogDir=$DATA_LOG_DIR" >> $CONFIG_FILE
+    echo "tickTime=$TICK_TIME" >> $CONFIG_FILE
+    echo "initLimit=$INIT_LIMIT" >> $CONFIG_FILE
+    echo "syncLimit=$SYNC_LIMIT" >> $CONFIG_FILE
+    echo "maxClientCnxns=$MAX_CLIENT_CNXNS" >> $CONFIG_FILE
+    echo "minSessionTimeout=$MIN_SESSION_TIMEOUT" >> $CONFIG_FILE
+    echo "maxSessionTimeout=$MAX_SESSION_TIMEOUT" >> $CONFIG_FILE
+    echo "autopurge.snapRetainCount=$SNAP_RETAIN_COUNT" >> $CONFIG_FILE
+    echo "autopurge.purgeInteval=$PURGE_INTERVAL" >> $CONFIG_FILE
+    echo "quorumListenOnAllIPs=$QUORUM_LISTEN_ON_ALL_IPS" >> $CONFIG_FILE
+    # Allow running all zk commands.
+    echo "4lw.commands.whitelist=*" >> $CONFIG_FILE
+     if [ $SERVERS -gt 1 ]; then
+        print_servers >> $CONFIG_FILE
+    fi
+    echo "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider" >> $CONFIG_FILE
+    echo "metricsProvider.httpPort=$PROM_PORT" >> $CONFIG_FILE
+    cat $CONFIG_FILE >&2
+}
+
+function create_jvm_props() {
+    rm -f $JAVA_ENV_FILE
+    echo "SERVER_JVMFLAGS=\"-XX:MaxRAMPercentage=${JVM_HEAP_PERCENTAGE_OF_RESOURCE_LIMIT} \
+      -XX:InitialRAMPercentage=${JVM_HEAP_PERCENTAGE_OF_RESOURCE_LIMIT}\"" >> $JAVA_ENV_FILE
+    echo "ZOO_LOG_DIR=$LOG_DIR" >> $JAVA_ENV_FILE
+    echo "JVMFLAGS=" >> $JAVA_ENV_FILE
+}
+
+function create_log_props() {
+    rm -f $LOGGER_PROPS_FILE
+    echo "Creating ZooKeeper log4j configuration"
+    echo "zookeeper.root.logger=CONSOLE" >> $LOGGER_PROPS_FILE
+    echo "zookeeper.console.threshold="$LOG_LEVEL >> $LOGGER_PROPS_FILE
+    echo "log4j.rootLogger=\${zookeeper.root.logger}" >> $LOGGER_PROPS_FILE
+    echo "log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender" >> $LOGGER_PROPS_FILE
+    echo "log4j.appender.CONSOLE.Threshold=\${zookeeper.console.threshold}" >> $LOGGER_PROPS_FILE
+    echo "log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout" >> $LOGGER_PROPS_FILE
+    echo "log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n" >> $LOGGER_PROPS_FILE
+}
+
+optspec=":hv-:"
+while getopts "$optspec" optchar; do
+
+    case "${optchar}" in
+        -)
+            case "${OPTARG}" in
+                servers=*)
+                    SERVERS=${OPTARG##*=}
+                    ;;
+                data_dir=*)
+                    DATA_DIR=${OPTARG##*=}
+                    ;;
+                data_log_dir=*)
+                    DATA_LOG_DIR=${OPTARG##*=}
+                    ;;
+                log_dir=*)
+                    LOG_DIR=${OPTARG##*=}
+                    ;;
+                conf_dir=*)
+                    CONF_DIR=${OPTARG##*=}
+                    ;;
+                client_port=*)
+                    CLIENT_PORT=${OPTARG##*=}
+                    ;;
+                election_port=*)
+                    ELECTION_PORT=${OPTARG##*=}
+                    ;;
+                server_port=*)
+                    SERVER_PORT=${OPTARG##*=}
+                    ;;
+                tick_time=*)
+                    TICK_TIME=${OPTARG##*=}
+                    ;;
+                init_limit=*)
+                    INIT_LIMIT=${OPTARG##*=}
+                    ;;
+                sync_limit=*)
+                    SYNC_LIMIT=${OPTARG##*=}
+                    ;;
+                percentage=*)
+                    JVM_HEAP_PERCENTAGE_OF_RESOURCE_LIMIT=${OPTARG##*=}
+                    ;;
+                max_client_cnxns=*)
+                    MAX_CLIENT_CNXNS=${OPTARG##*=}
+                    ;;
+                snap_retain_count=*)
+                    SNAP_RETAIN_COUNT=${OPTARG##*=}
+                    ;;
+                purge_interval=*)
+                    PURGE_INTERVAL=${OPTARG##*=}
+                    ;;
+                max_session_timeout=*)
+                    MAX_SESSION_TIMEOUT=${OPTARG##*=}
+                    ;;
+                min_session_timeout=*)
+                    MIN_SESSION_TIMEOUT=${OPTARG##*=}
+                    ;;
+                quorum_listen_on_all_ips=*)
+                    QUORUM_LISTEN_ON_ALL_IPS=${OPTARG##*=}
+                    ;;
+                log_level=*)
+                    LOG_LEVEL=${OPTARG##*=}
+                    ;;
+                *)
+                    echo "Unknown option --${OPTARG}" >&2
+                    exit 1
+                    ;;
+            esac;;
+        h)
+            print_usage
+            exit
+            ;;
+        v)
+            echo "Parsing option: '-${optchar}'" >&2
+            ;;
+        *)
+            if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
+                echo "Non-option argument: '-${OPTARG}'" >&2
+            fi
+            ;;
+    esac
+done
+
+MIN_SESSION_TIMEOUT=${MIN_SESSION_TIMEOUT:- $((TICK_TIME*2))}
+MAX_SESSION_TIMEOUT=${MAX_SESSION_TIMEOUT:- $((TICK_TIME*20))}
+ID_FILE="$DATA_DIR/myid"
+if [ ! -d $CONF_DIR  ]; then
+  mkdir -p $CONF_DIR
+  chown -R $USER:$USER $CONF_DIR
+fi
+CONFIG_FILE="$CONF_DIR/zoo.cfg"
+LOGGER_PROPS_FILE="$CONF_DIR/log4j.properties"
+JAVA_ENV_FILE="$CONF_DIR/java.env"
+
+if [[ $HOST =~ (.*)-([0-9]+)$ ]]; then
+    NAME=${BASH_REMATCH[1]}
+    ORD=${BASH_REMATCH[2]}
+else
+    echo "Failed to parse name and ordinal of Pod"
+    exit 1
+fi
+
+MY_ID=$((ORD+1))
+
+export ZOOCFGDIR=${CONF_DIR}
+create_config && create_jvm_props && create_log_props && create_data_dirs && exec ${ZOOKEEPER_HOME}/bin/zkServer.sh start-foreground
diff --git a/hbase-kubernetes-deployment/components/zookeeper/single-instance/zookeeper.yaml b/hbase-kubernetes-deployment/components/zookeeper/single-instance/zookeeper.yaml
new file mode 100644
index 0000000..b010229
--- /dev/null
+++ b/hbase-kubernetes-deployment/components/zookeeper/single-instance/zookeeper.yaml
@@ -0,0 +1,142 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: zookeeper
+spec:
+  replicas: 1
+  serviceName: zookeeper-headless
+  selector:
+    matchLabels:
+      cluster: zookeeper # has to match .spec.template.metadata.labels
+      role: zookeeper
+  updateStrategy:
+    type: RollingUpdate
+  podManagementPolicy: Parallel
+  template:
+    metadata:
+      labels:
+        cluster: zookeeper
+        role: zookeeper
+    spec:
+      containers:
+      - image: zookeeper
+        name: zookeeper
+        imagePullPolicy: IfNotPresent
+        resources:
+          requests:
+            cpu: '0.1'
+            memory: 768Mi
+          limits:
+            cpu: '1.0'
+            memory: 1Gi
+        env:
+        - name: JAVA_HOME
+          value: /usr/local/openjdk-11
+        - name: LANG
+          value: C.UTF-8
+        - name: PATH
+          value: /usr/local/openjdk-11/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+        - name: ZK_LOG_DIR
+          value: /var/log/zookeeper
+        ports:
+        - containerPort: 2181
+          name: client
+        - containerPort: 2888
+          name: server
+        - containerPort: 3888
+          name: leader-election
+        - containerPort: 7001
+          name: metrics
+        command:
+        - sh
+        - -c
+        - |-
+          export LOG_DIR="${ZK_LOG_DIR}"
+          /usr/bin/zookeeper/start.sh --servers=1 --percentage=50
+        readinessProbe:
+          exec:
+            command:
+            - /bin/bash
+            - -c
+            - |-
+              [ "$(echo ruok | nc 127.0.0.1 2181)" == "imok"  ]
+          initialDelaySeconds: 10
+          timeoutSeconds: 5
+        livenessProbe:
+          exec:
+            command:
+            - /bin/bash
+            - -c
+            - |-
+              [ "$(echo ruok | nc 127.0.0.1 2181)" == "imok"  ]
+          initialDelaySeconds: 10
+          timeoutSeconds: 5
+        volumeMounts:
+        - name: datadir
+          mountPath: /var/lib/zookeeper
+        - mountPath: /usr/bin/zookeeper
+          name: zookeeper-scripts
+        - mountPath: /var/log/zookeeper
+          name: zk-logs
+      volumes:
+      - emptyDir: {}
+        name: zk-logs
+      - configMap:
+          name: zookeeper-scripts
+          defaultMode: 0555
+        name: zookeeper-scripts
+  volumeClaimTemplates:
+  - metadata:
+      name: datadir
+    spec:
+      accessModes: [ "ReadWriteOnce"  ]
+      resources:
+        requests:
+          storage: 2Gi
+---
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: zookeeper-pdb
+spec:
+  selector:
+    matchLabels:
+      cluster: zookeeper
+  maxUnavailable: 1
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: zookeeper-headless
+spec:
+  ports:
+    - port: 2888
+      name: server
+    - port: 3888
+      name: leader-election
+    - port: 2181
+      name: client
+    - port: 8080
+      name: http
+  clusterIP: None
+  publishNotReadyAddresses: true
+  # Select our zookeeper app. This is what gets us dns entries
+  # https://kubernetes.io/docs/concepts/services-networking/service/#with-selectors
+  selector:
+    cluster: zookeeper
diff --git a/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/00-assert-zookeeper.yaml b/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/00-assert-zookeeper.yaml
new file mode 100644
index 0000000..4e109f0
--- /dev/null
+++ b/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/00-assert-zookeeper.yaml
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Asserts on the ZooKeeper portion of the deployment.
+#
+---
+# assert that there is a `StatefulSet` named "zookeeper" that has one live instance.
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: zookeeper
+status:
+  availableReplicas: 1
diff --git a/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/00-kustomize.yaml b/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/00-kustomize.yaml
new file mode 100644
index 0000000..b365471
--- /dev/null
+++ b/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/00-kustomize.yaml
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+
+commands:
+- script: ../../bin/kustomize_into_tmpdir.sh
diff --git a/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/kustomization.yaml b/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/kustomization.yaml
new file mode 100644
index 0000000..e70699d
--- /dev/null
+++ b/hbase-kubernetes-deployment/tests/integration/components_zookeeper_single/kustomization.yaml
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+---
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+components:
+  - ../../../components/zookeeper/single-instance
diff --git a/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/00-assert-zookeeper.yaml b/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/00-assert-zookeeper.yaml
new file mode 100644
index 0000000..41fc2d8
--- /dev/null
+++ b/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/00-assert-zookeeper.yaml
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Asserts on the ZooKeeper portion of the deployment.
+#
+---
+# assert that there is a `ConfigMap` named "zookeeper-scripts-XXX"
+# TODO: kuttl does not support generated names
+#apiVersion: v1
+#kind: ConfigMap
+#metadata:
+#  name: zookeeper-scripts-c94h8k249d
+---
+# assert that there is a `ConfigMap` named "zookeeper-quorum"
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: zookeeper-quorum
+---
+# assert that there is a `PodDisruptionBudget` named "zookeeper-pdb"
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: zookeeper-pdb
+---
+# assert that there is a `StatefulSet` named "zookeeper" that:
+# - provides pods labeled role:zookeeper
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: zookeeper
+spec:
+  template:
+    metadata:
+      labels:
+        role: zookeeper
diff --git a/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/00-kustomize.yaml b/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/00-kustomize.yaml
new file mode 100644
index 0000000..b365471
--- /dev/null
+++ b/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/00-kustomize.yaml
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+
+commands:
+- script: ../../bin/kustomize_into_tmpdir.sh
diff --git a/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/kustomization.yaml b/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/kustomization.yaml
new file mode 100644
index 0000000..e70699d
--- /dev/null
+++ b/hbase-kubernetes-deployment/tests/unit/components_zookeeper_single/kustomization.yaml
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+---
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+components:
+  - ../../../components/zookeeper/single-instance