diff --git a/ansible/group_vars/all/kolla b/ansible/group_vars/all/kolla
index 41351a8d85f190f9263d0d4bec53d3d0af9e9df7..a64e5da49fc3c27ed33a175b304848420c9c0fd7 100644
--- a/ansible/group_vars/all/kolla
+++ b/ansible/group_vars/all/kolla
@@ -181,6 +181,8 @@ overcloud_container_image_regex_map:
     enabled: "{{ kolla_enable_swift | bool }}"
   - regex: tgtd
     enabled: "{{ kolla_enable_cinder | bool or kolla_enable_ironic | bool }}"
+  - regex: zookeeper
+    enabled: "{{ kolla_enable_zookeeper | bool or kolla_enable_kafka | bool }}"
 
 # List of regular expressions matching names of container images to build for
 # overcloud hosts.
@@ -302,6 +304,8 @@ kolla_enable_haproxy: "yes"
 kolla_enable_heat: "yes"
 kolla_enable_horizon: "yes"
 kolla_enable_ironic: "yes"
+# Kafka is not currently supported
+kolla_enable_kafka: "no"
 kolla_enable_kibana: "{{ 'yes' if kolla_enable_central_logging | bool else 'no' }}"
 kolla_enable_magnum: "no"
 kolla_enable_manila: "no"
@@ -315,6 +319,7 @@ kolla_enable_osprofiler: "no"
 kolla_enable_sahara: "no"
 kolla_enable_skydive: "no"
 kolla_enable_swift: "no"
+kolla_enable_zookeeper: "no"
 
 ###############################################################################
 # Passwords and credentials.
diff --git a/ansible/kolla-openstack.yml b/ansible/kolla-openstack.yml
index 018916e70c02b5b482c96c568ac5b0c8a8565529..babf5d5653451747112e170d7a19f5ecf360eda8 100644
--- a/ansible/kolla-openstack.yml
+++ b/ansible/kolla-openstack.yml
@@ -113,6 +113,7 @@
             - { name: neutron_ml2, file: neutron/ml2_conf.ini }
             - { name: nova, file: nova.conf }
             - { name: sahara, file: sahara.conf }
+            - { name: zookeeper, file: zookeeper.cfg }
 
         - name: Initialise a fact containing extra configuration
           set_fact:
@@ -213,4 +214,5 @@
       kolla_extra_neutron_ml2: "{{ kolla_extra_config.neutron_ml2 | default }}"
       kolla_extra_nova: "{{ kolla_extra_config.nova | default }}"
       kolla_extra_sahara: "{{ kolla_extra_config.sahara | default }}"
+      kolla_extra_zookeeper: "{{ kolla_extra_config.zookeeper | default }}"
       kolla_extra_config_path: "{{ kayobe_config_path }}/kolla/config"
diff --git a/ansible/roles/kolla-ansible/defaults/main.yml b/ansible/roles/kolla-ansible/defaults/main.yml
index 4d2496188f6820e83fbc6a6e1dc43894765a6400..70c01d6c08afa8be0845dd0ad7505f47ef67219d 100644
--- a/ansible/roles/kolla-ansible/defaults/main.yml
+++ b/ansible/roles/kolla-ansible/defaults/main.yml
@@ -207,6 +207,7 @@ kolla_openstack_logging_debug:
 #kolla_enable_horizon:
 #kolla_enable_influxdb:
 #kolla_enable_ironic:
+#kolla_enable_kafka:
 #kolla_enable_kuryr:
 #kolla_enable_magnum:
 #kolla_enable_manila:
@@ -227,6 +228,7 @@ kolla_openstack_logging_debug:
 #kolla_enable_telegraf:
 #kolla_enable_tempest:
 #kolla_enable_watcher:
+#kolla_enable_zookeeper:
 
 #######################
 # Nova options
diff --git a/ansible/roles/kolla-ansible/templates/overcloud-components.j2 b/ansible/roles/kolla-ansible/templates/overcloud-components.j2
index de3c274ea183dcf730ee4b387e5c5b6465e87f72..baded2d1defbb127dbd3ca01418e8c6eda46519a 100644
--- a/ansible/roles/kolla-ansible/templates/overcloud-components.j2
+++ b/ansible/roles/kolla-ansible/templates/overcloud-components.j2
@@ -199,3 +199,6 @@ control
 
 [skydive:children]
 monitoring
+
+[zookeeper:children]
+monitoring
diff --git a/ansible/roles/kolla-ansible/tests/test-defaults.yml b/ansible/roles/kolla-ansible/tests/test-defaults.yml
index 11ad631c7e9e74ee1c8d870d5fb60549fcba8610..4137bc60e281c1710b2a291a84d3d5c74b4959ab 100644
--- a/ansible/roles/kolla-ansible/tests/test-defaults.yml
+++ b/ansible/roles/kolla-ansible/tests/test-defaults.yml
@@ -118,6 +118,7 @@
               - enable_ironic
               - enable_neutron
               - enable_nova
+              - enable_zookeeper
               - grafana_admin_username
 
         - name: Check whether inventory files exist
diff --git a/ansible/roles/kolla-ansible/tests/test-extras.yml b/ansible/roles/kolla-ansible/tests/test-extras.yml
index e1f378ae82431aa446bfd84072c4da123c1b640a..712481cd54a755420e89e3ce050e18a3a3e44ba5 100644
--- a/ansible/roles/kolla-ansible/tests/test-extras.yml
+++ b/ansible/roles/kolla-ansible/tests/test-extras.yml
@@ -121,6 +121,7 @@
             kolla_enable_tempest: True
             kolla_enable_trove: True
             kolla_enable_watcher: True
+            kolla_enable_zookeeper: True
             kolla_enable_zun: True
             kolla_extra_globals:
               extra-global-1: "extra-val-1"
@@ -253,6 +254,7 @@
               #enable_tempest: True
               #enable_trove: True
               #enable_watcher: True
+              #enable_zookeeper: True
               #enable_zun: True
               extra-global-1: "extra-val-1"
               extra-global-2: "extra-val-2"
diff --git a/ansible/roles/kolla-ansible/vars/main.yml b/ansible/roles/kolla-ansible/vars/main.yml
index 0fcf327f7c27dfe51bd86163df8414c9130487e2..cddaa4449270b8ede846e5cf2ede20e9771472d8 100644
--- a/ansible/roles/kolla-ansible/vars/main.yml
+++ b/ansible/roles/kolla-ansible/vars/main.yml
@@ -118,4 +118,5 @@ kolla_feature_flags:
   - tempest
   - trove
   - watcher
+  - zookeeper
   - zun
diff --git a/ansible/roles/kolla-openstack/defaults/main.yml b/ansible/roles/kolla-openstack/defaults/main.yml
index fc0575b98bd55c1386650f5ee13bc923954fba4f..003b14c608207a339af25c613456338806b7def2 100644
--- a/ansible/roles/kolla-openstack/defaults/main.yml
+++ b/ansible/roles/kolla-openstack/defaults/main.yml
@@ -348,3 +348,12 @@ kolla_extra_sahara:
 
 # Whether to enable swift.
 kolla_enable_swift:
+
+###############################################################################
+# Zookeeper configuration.
+
+# Whether to enable Zookeeper.
+kolla_enable_zookeeper:
+
+# Free form extra configuration to append to zookeeper.cfg.
+kolla_extra_zookeeper:
diff --git a/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py b/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py
index dafca645d352901c1aab2caa2c1383aa67132604..c3ea79ef659b671c38d7962c3804d5911c0877a7 100644
--- a/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py
+++ b/ansible/roles/kolla-openstack/molecule/default/tests/test_default.py
@@ -51,7 +51,8 @@ def test_service_config_directory(host, path):
      'neutron',
      'nova',
      'sahara',
-     'swift'])
+     'swift',
+     'zookeeper'])
 def test_service_config_directory_absent(host, path):
     path = os.path.join('/etc/kolla/config', path)
     utils.test_path_absent(host, path)
diff --git a/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml b/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml
index f020def9b302c1fce9f5ecf2131f983c08fe56f0..50db855d3870b2f02c4b6794045e7006e5843bb1 100644
--- a/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml
+++ b/ansible/roles/kolla-openstack/molecule/enable-everything/molecule.yml
@@ -78,6 +78,10 @@ provisioner:
           [extra-sahara.conf]
           foo=bar
         kolla_enable_swift: True
+        kolla_enable_zookeeper: True
+        kolla_extra_zookeeper: |
+          [extra-zookeeper.cfg]
+          foo=bar
   lint:
     name: ansible-lint
 scenario:
diff --git a/ansible/roles/kolla-openstack/molecule/enable-everything/tests/test_default.py b/ansible/roles/kolla-openstack/molecule/enable-everything/tests/test_default.py
index 7217b7b6c9eac165da427d921472f03fc95f6d1e..262e3d3617b2ece920f685597700e08d7956fb05 100644
--- a/ansible/roles/kolla-openstack/molecule/enable-everything/tests/test_default.py
+++ b/ansible/roles/kolla-openstack/molecule/enable-everything/tests/test_default.py
@@ -44,7 +44,8 @@ testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
      'neutron',
      'nova',
      'sahara',
-     'swift'])
+     'swift',
+     'zookeeper'])
 def test_service_config_directory(host, path):
     path = os.path.join('/etc/kolla/config', path)
     utils.test_directory(host, path)
@@ -65,7 +66,8 @@ def test_service_config_directory(host, path):
      'murano.conf',
      'neutron.conf',
      'nova.conf',
-     'sahara.conf'])
+     'sahara.conf',
+     'zookeeper.cfg'])
 def test_service_ini_file(host, path):
     # TODO(mgoddard): Check more of config file contents.
     path = os.path.join('/etc/kolla/config', path)
diff --git a/ansible/roles/kolla-openstack/tasks/config.yml b/ansible/roles/kolla-openstack/tasks/config.yml
index 484ef4d45fb804b9f7a18b3720d2d377331fca5b..341f26e73796f2d0cc72d74bae21703a668f2189 100644
--- a/ansible/roles/kolla-openstack/tasks/config.yml
+++ b/ansible/roles/kolla-openstack/tasks/config.yml
@@ -29,6 +29,7 @@
     - { src: nova.conf.j2, dest: nova.conf, enabled: "{{ kolla_enable_nova }}" }
     - { src: pxelinux.default.j2, dest: ironic/pxelinux.default, enabled: "{{ kolla_enable_ironic }}" }
     - { src: sahara.conf.j2, dest: sahara.conf, enabled: "{{ kolla_enable_sahara }}" }
+    - { src: zookeeper.cfg.j2, dest: zookeeper.cfg, enabled: "{{ kolla_enable_zookeeper }}" }
   when: item.enabled | bool
 
 - name: Ensure the ironic inspector kernel and ramdisk are downloaded
diff --git a/ansible/roles/kolla-openstack/templates/zookeeper.cfg.j2 b/ansible/roles/kolla-openstack/templates/zookeeper.cfg.j2
new file mode 100644
index 0000000000000000000000000000000000000000..08bdc8aa23986b195074fe22ef98e4aeb73e2003
--- /dev/null
+++ b/ansible/roles/kolla-openstack/templates/zookeeper.cfg.j2
@@ -0,0 +1,9 @@
+# {{ ansible_managed }}
+
+{% if kolla_extra_zookeeper %}
+#######################
+# Extra configuration
+#######################
+
+{{ kolla_extra_zookeeper }}
+{% endif %}
diff --git a/ansible/roles/kolla-openstack/vars/main.yml b/ansible/roles/kolla-openstack/vars/main.yml
index bbe4aca8848261e718bbe5c52036b90a9062d6c3..cfd4f43bee657a001ce62dd3b74afc4d7801e95c 100644
--- a/ansible/roles/kolla-openstack/vars/main.yml
+++ b/ansible/roles/kolla-openstack/vars/main.yml
@@ -108,3 +108,8 @@ kolla_openstack_custom_config:
     dest: "{{ kolla_node_custom_config_path }}/swift"
     patterns: "*"
     enabled: "{{ kolla_enable_swift }}"
+  # Zookeeper.
+  - src: "{{ kolla_extra_config_path }}/zookeeper"
+    dest: "{{ kolla_node_custom_config_path }}/zookeeper"
+    patterns: "*"
+    enabled: "{{ kolla_enable_zookeeper }}"