diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 16efa3d5cc1314b3b48f3c57bac833957845ea06..34985a0594dbd056312ad795377ecb9c086ac446 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -96,6 +96,10 @@ swift_object_server_port: "6000"
 swift_account_server_port: "6001"
 swift_container_server_port: "6002"
 
+heat_api_port: "8004"
+heat_api_cfn_port: "8000"
+
+
 ####################
 # Openstack options
 ####################
@@ -133,9 +137,11 @@ enable_rabbitmq: "yes"
 
 # Additional optional OpenStack services are specified here
 enable_cinder: "no"
+enable_heat: "yes"
 enable_horizon: "yes"
 enable_swift: "no"
 
+
 ####################
 # RabbitMQ options
 ####################
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index b0cbdb457a75bb601c7b2418940c09bca866301f..e762078b1bebfa396801fbd90ab19fbab9a6d038 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -48,6 +48,9 @@ control
 [swift:children]
 control
 
+[heat:children]
+control
+
 
 # Additional control implemented here. These groups allow you to control which
 # services run on which hosts at a per-service level.
@@ -111,3 +114,13 @@ storage
 
 [swift-object-server:children]
 storage
+
+# Heat
+[heat-api:children]
+heat
+
+[heat-api-cfn:children]
+heat
+
+[heat-engine:children]
+heat
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index 7db8c12a5fdfe70f0dd03a7e473e3ea18cf644dd..1d4e1fb7fda546f214e81f549a7d0a4f38f9f07b 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -9,6 +9,8 @@ control03       ansible_ssh_user=sam
 # The above can also be specified as follows:
 #control[01:03]     ansible_ssh_user=sam
 
+# The network nodes are where your l3-agent and loadbalancers will run
+# This can be the same as a a host in the control group
 [network]
 network01
 
@@ -54,6 +56,9 @@ control
 [swift:children]
 control
 
+[heat:children]
+control
+
 
 # Additional control implemented here. These groups allow you to control which
 # services run on which hosts at a per-service level.
@@ -117,3 +122,13 @@ storage
 
 [swift-object-server:children]
 storage
+
+# Heat
+[heat-api:children]
+heat
+
+[heat-api-cfn:children]
+heat
+
+[heat-engine:children]
+heat
diff --git a/ansible/roles/haproxy/templates/haproxy.cfg.j2 b/ansible/roles/haproxy/templates/haproxy.cfg.j2
index 128e1ff9612becd419af714fec3b096481af0d12..745d9b0f58d18267158f414ab8976e13dae2aaf6 100644
--- a/ansible/roles/haproxy/templates/haproxy.cfg.j2
+++ b/ansible/roles/haproxy/templates/haproxy.cfg.j2
@@ -97,3 +97,15 @@ listen cinder_api
 {% for host in groups['cinder-api'] %}
   server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + api_interface]['ipv4']['address'] }}:{{ cinder_api_port }} check inter 2000 rise 2 fall 5
 {% endfor %}
+
+listen heat_api
+  bind {{ kolla_internal_address }}:{{ heat_api_port }}
+{% for host in groups['heat-api'] %}
+  server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + api_interface]['ipv4']['address'] }}:{{ heat_api_port }} check inter 2000 rise 2 fall 5
+{% endfor %}
+
+listen heat_api_cfn
+  bind {{ kolla_internal_address }}:{{ heat_api_cfn_port }}
+{% for host in groups['heat-api-cfn'] %}
+  server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + api_interface]['ipv4']['address'] }}:{{ heat_api_cfn_port }} check inter 2000 rise 2 fall 5
+{% endfor %}
diff --git a/ansible/roles/heat/defaults/main.yml b/ansible/roles/heat/defaults/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1e126a7b24306c7565904a7c223f915a0560a444
--- /dev/null
+++ b/ansible/roles/heat/defaults/main.yml
@@ -0,0 +1,43 @@
+---
+project_name: "heat"
+
+####################
+# Database
+####################
+heat_database_name: "heat"
+heat_database_user: "heat"
+heat_database_address: "{{ kolla_internal_address }}"
+
+
+####################
+# Docker
+####################
+heat_registry_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-heat-registry"
+heat_registry_tag: "{{ openstack_release }}"
+heat_registry_image_full: "{{ heat_registry_image }}:{{ heat_registry_tag }}"
+
+heat_api_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-heat-api"
+heat_api_tag: "{{ openstack_release }}"
+heat_api_image_full: "{{ heat_api_image }}:{{ heat_api_tag }}"
+
+heat_api_cfn_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-heat-api-cfn"
+heat_api_cfn_tag: "{{ openstack_release }}"
+heat_api_cfn_image_full: "{{ heat_api_cfn_image }}:{{ heat_api_cfn_tag }}"
+
+heat_engine_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-heat-engine"
+heat_engine_tag: "{{ openstack_release }}"
+heat_engine_image_full: "{{ heat_engine_image }}:{{ heat_engine_tag }}"
+
+####################
+# Openstack
+####################
+heat_public_address: "{{ kolla_external_address }}"
+heat_admin_address: "{{ kolla_internal_address }}"
+heat_internal_address: "{{ kolla_internal_address }}"
+
+heat_logging_verbose: "{{ openstack_logging_verbose }}"
+heat_logging_debug: "{{ openstack_logging_debug }}"
+
+heat_keystone_user: "heat"
+
+openstack_heat_auth: "{'auth_url':'{{ openstack_auth_v2.auth_url }}','username':'{{ openstack_auth_v2.username }}','password':'{{ openstack_auth_v2.password }}','project_name':'{{ openstack_auth_v2.project_name }}'}"
diff --git a/ansible/roles/heat/tasks/bootstrap.yml b/ansible/roles/heat/tasks/bootstrap.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b43b4dccb4c8cbbf61b483f819ef35b841369493
--- /dev/null
+++ b/ansible/roles/heat/tasks/bootstrap.yml
@@ -0,0 +1,68 @@
+---
+- name: Creating Heat database
+  command: docker exec -t kolla_ansible /usr/bin/ansible localhost
+    -m mysql_db
+    -a "login_host='{{ database_address }}'
+        login_user='{{ database_user }}'
+        login_password='{{ database_password }}'
+        name='{{ heat_database_name }}'"
+  register: database
+  changed_when: "{{ database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}"
+  failed_when: database.stdout.split()[2] != 'SUCCESS'
+  run_once: True
+
+- name: Creating Heat database user and setting permissions
+  command: docker exec -t kolla_ansible /usr/bin/ansible localhost
+    -m mysql_user
+    -a "login_host='{{ database_address }}'
+        login_user='{{ database_user }}'
+        login_password='{{ database_password }}'
+        name='{{ heat_database_name }}'
+        password='{{ heat_database_password }}'
+        host='%'
+        priv='{{ heat_database_name }}.*:ALL'
+        append_privs='yes'"
+  register: database_user
+  changed_when: "{{ database.stdout.find('localhost | SUCCESS => ') != -1 and (database_user.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}"
+  failed_when: database_user.stdout.split()[2] != 'SUCCESS'
+  run_once: True
+
+- name: Starting Heat bootstrap container
+  docker:
+    detach: False
+    docker_api_version: "{{ docker_api_version }}"
+    net: host
+    pull: "{{ docker_pull_policy }}"
+    restart_policy: "no"
+    state: reloaded
+    registry: "{{ docker_registry }}"
+    username: "{{ docker_registry_username }}"
+    password: "{{ docker_registry_password }}"
+    insecure_registry: "{{ docker_insecure_registry }}"
+    name: bootstrap_heat
+    image: "{{ heat_api_image_full }}"
+    volumes: "{{ node_config_directory }}/heat-api/:/opt/kolla/heat-api/:ro"
+    env:
+      KOLLA_BOOTSTRAP:
+      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
+      OS_AUTH_URL: "{{ openstack_auth.auth_url }}"
+      OS_IDENTITY_API_VERSION: "3"
+      OS_USERNAME: "{{ openstack_auth.username }}"
+      OS_PASSWORD: "{{ openstack_auth.password }}"
+      OS_PROJECT_NAME: "{{ openstack_auth.project_name }}"
+      HEAT_DOMAIN_ADMIN_PASSWORD: "{{ heat_domain_admin_password }}"
+  run_once: True
+  when: database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed
+
+# https://github.com/ansible/ansible-modules-core/pull/1031
+- name: Waiting for bootstrap container to exit
+  command: docker wait bootstrap_heat
+  run_once: True
+  when: database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed
+
+- name: Cleaning up Heat boostrap container
+  docker:
+    name: bootstrap_heat
+    image: "{{ heat_api_image_full }}"
+    state: absent
+  when: database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed
diff --git a/ansible/roles/heat/tasks/config.yml b/ansible/roles/heat/tasks/config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..bf1364a010ffbb26fa1b54d19956835b0eca0bfd
--- /dev/null
+++ b/ansible/roles/heat/tasks/config.yml
@@ -0,0 +1,55 @@
+---
+- include: ../../config.yml
+  vars:
+    service_name: "heat-engine"
+    config_source:
+      - "roles/heat/templates/heat.conf.j2"
+      - "/etc/kolla/config/global.conf"
+      - "/etc/kolla/config/database.conf"
+      - "/etc/kolla/config/heat.conf"
+      - "/etc/kolla/config/heat/heat-engine.conf"
+    config_template_dest:
+      - "{{ node_templates_directory }}/heat-engine/heat.conf_minimal"
+      - "{{ node_templates_directory }}/heat-engine/heat.conf_global"
+      - "{{ node_templates_directory }}/heat-engine/heat.conf_database"
+      - "{{ node_templates_directory }}/heat-engine/heat.conf_augment"
+      - "{{ node_templates_directory }}/heat-engine/heat-engine.conf_augment"
+    config_dest: "{{ node_config_directory }}/heat-engine/heat.conf"
+
+- include: ../../config.yml
+  vars:
+    service_name: "heat-api"
+    config_source:
+      - "roles/heat/templates/heat.conf.j2"
+      - "/etc/kolla/config/global.conf"
+      - "/etc/kolla/config/database.conf"
+      - "/etc/kolla/config/messaging.conf"
+      - "/etc/kolla/config/heat.conf"
+      - "/etc/kolla/config/heat/heat-api.conf"
+    config_template_dest:
+      - "{{ node_templates_directory }}/heat-api/heat.conf_minimal"
+      - "{{ node_templates_directory }}/heat-api/heat.conf_global"
+      - "{{ node_templates_directory }}/heat-api/heat.conf_database"
+      - "{{ node_templates_directory }}/heat-api/heat.conf_messaging"
+      - "{{ node_templates_directory }}/heat-api/heat.conf_augment"
+      - "{{ node_templates_directory }}/heat-api/heat-api.conf_augment"
+    config_dest: "{{ node_config_directory }}/heat-api/heat.conf"
+
+- include: ../../config.yml
+  vars:
+    service_name: "heat-api-cfn"
+    config_source:
+      - "roles/heat/templates/heat.conf.j2"
+      - "/etc/kolla/config/global.conf"
+      - "/etc/kolla/config/database.conf"
+      - "/etc/kolla/config/messaging.conf"
+      - "/etc/kolla/config/heat.conf"
+      - "/etc/kolla/config/heat/heat-api-cfn.conf"
+    config_template_dest:
+      - "{{ node_templates_directory }}/heat-api-cfn/heat.conf_minimal"
+      - "{{ node_templates_directory }}/heat-api-cfn/heat.conf_global"
+      - "{{ node_templates_directory }}/heat-api-cfn/heat.conf_database"
+      - "{{ node_templates_directory }}/heat-api-cfn/heat.conf_messaging"
+      - "{{ node_templates_directory }}/heat-api-cfn/heat.conf_augment"
+      - "{{ node_templates_directory }}/heat-api-cfn/heat-api-cfn.conf_augment"
+    config_dest: "{{ node_config_directory }}/heat-api-cfn/heat.conf"
diff --git a/ansible/roles/heat/tasks/main.yml b/ansible/roles/heat/tasks/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5c48120b7c9e6ee00027462c3f23aa25c6b05dd7
--- /dev/null
+++ b/ansible/roles/heat/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+- include: register.yml
+
+- include: config.yml
+
+- include: bootstrap.yml
+
+- include: start.yml
diff --git a/ansible/roles/heat/tasks/register.yml b/ansible/roles/heat/tasks/register.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3cd89b94bbadfaf5d0bc81783f8ba628b2c9edfb
--- /dev/null
+++ b/ansible/roles/heat/tasks/register.yml
@@ -0,0 +1,57 @@
+---
+- name: Creating the Heat service and endpoint
+  command: docker exec -t kolla_ansible /usr/bin/ansible localhost
+    -m kolla_keystone_service
+    -a "service_name=heat
+        service_type=orchestration
+        description='Openstack Orchestration'
+        endpoint_region={{ openstack_region_name }}
+        admin_url='http://{{ kolla_internal_address }}:{{ heat_api_port }}/v1/%(tenant_id)s'
+        internal_url='http://{{ kolla_internal_address }}:{{ heat_api_port }}/v1/%(tenant_id)s'
+        public_url='http://{{ kolla_external_address }}:{{ heat_api_port }}/v1/%(tenant_id)s'
+        region_name={{ openstack_region_name }}
+        auth={{ '{{ openstack_heat_auth }}' }}"
+    -e "{'openstack_heat_auth':{{ openstack_heat_auth }}}"
+  register: heat_endpoint
+  changed_when: "{{ heat_endpoint.stdout.find('localhost | SUCCESS => ') != -1 and (heat_endpoint.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}"
+  until: heat_endpoint.stdout.split()[2] == 'SUCCESS'
+  retries: 10
+  delay: 5
+  run_once: True
+
+- name: Creating the Heat-cfn service and endpoint
+  command: docker exec -t kolla_ansible /usr/bin/ansible localhost
+    -m kolla_keystone_service
+    -a "service_name=heat-cfn
+        service_type=orchestration
+        description='Openstack Orchestration'
+        endpoint_region={{ openstack_region_name }}
+        admin_url='http://{{ kolla_internal_address }}:{{ heat_api_port }}/v1'
+        internal_url='http://{{ kolla_internal_address }}:{{ heat_api_cfn_port }}/v1'
+        public_url='http://{{ kolla_external_address }}:{{ heat_api_cfn_port }}/v1'
+        region_name={{ openstack_region_name }}
+        auth={{ '{{ openstack_heat_auth }}' }}"
+    -e "{'openstack_heat_auth':{{ openstack_heat_auth }}}"
+  register: heat_endpoint
+  changed_when: "{{ heat_endpoint.stdout.find('localhost | SUCCESS => ') != -1 and (heat_endpoint.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}"
+  until: heat_endpoint.stdout.split()[2] == 'SUCCESS'
+  retries: 10
+  delay: 5
+  run_once: True
+
+- name: Creating the Heat project, user, and role
+  command: docker exec -t kolla_ansible /usr/bin/ansible localhost
+    -m kolla_keystone_user
+    -a "project=service
+        user=heat
+        password={{ heat_keystone_password }}
+        role=admin
+        region_name={{ openstack_region_name }}
+        auth={{ '{{ openstack_heat_auth }}' }}"
+    -e "{'openstack_heat_auth':{{ openstack_heat_auth }}}"
+  register: heat_user
+  changed_when: "{{ heat_user.stdout.find('localhost | SUCCESS => ') != -1 and (heat_user.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}"
+  until: heat_user.stdout.split()[2] == 'SUCCESS'
+  retries: 10
+  delay: 5
+  run_once: True
diff --git a/ansible/roles/heat/tasks/start.yml b/ansible/roles/heat/tasks/start.yml
new file mode 100644
index 0000000000000000000000000000000000000000..62f8ba1e0c56c5891c4176d25de3b3c1eae79333
--- /dev/null
+++ b/ansible/roles/heat/tasks/start.yml
@@ -0,0 +1,57 @@
+---
+- name: Starting heat-api container
+  docker:
+    docker_api_version: "{{ docker_api_version }}"
+    net: host
+    pull: "{{ docker_pull_policy }}"
+    restart_policy: "{{ docker_restart_policy }}"
+    restart_policy_retry: "{{ docker_restart_policy_retry }}"
+    state: reloaded
+    registry: "{{ docker_registry }}"
+    username: "{{ docker_registry_username }}"
+    password: "{{ docker_registry_password }}"
+    insecure_registry: "{{ docker_insecure_registry }}"
+    name: heat_api
+    image: "{{ heat_api_image_full }}"
+    volumes: "{{ node_config_directory }}/heat-api/:/opt/kolla/heat-api/:ro"
+    env:
+      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
+  when: inventory_hostname in groups['heat-api']
+
+- name: Starting heat-api-cfn container
+  docker:
+    docker_api_version: "{{ docker_api_version }}"
+    net: host
+    pull: "{{ docker_pull_policy }}"
+    restart_policy: "{{ docker_restart_policy }}"
+    restart_policy_retry: "{{ docker_restart_policy_retry }}"
+    state: reloaded
+    registry: "{{ docker_registry }}"
+    username: "{{ docker_registry_username }}"
+    password: "{{ docker_registry_password }}"
+    insecure_registry: "{{ docker_insecure_registry }}"
+    name: heat_api_cfn
+    image: "{{ heat_api_cfn_image_full }}"
+    volumes: "{{ node_config_directory }}/heat-api-cfn/:/opt/kolla/heat-api-cfn/:ro"
+    env:
+      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
+  when: inventory_hostname in groups['heat-api-cfn']
+
+- name: Starting heat-engine container
+  docker:
+    docker_api_version: "{{ docker_api_version }}"
+    net: host
+    pull: "{{ docker_pull_policy }}"
+    restart_policy: "{{ docker_restart_policy }}"
+    restart_policy_retry: "{{ docker_restart_policy_retry }}"
+    state: reloaded
+    registry: "{{ docker_registry }}"
+    username: "{{ docker_registry_username }}"
+    password: "{{ docker_registry_password }}"
+    insecure_registry: "{{ docker_insecure_registry }}"
+    name: heat_engine
+    image: "{{ heat_engine_image_full }}"
+    volumes: "{{ node_config_directory }}/heat-engine/:/opt/kolla/heat-engine/:ro"
+    env:
+      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
+  when: inventory_hostname in groups['heat-engine']
diff --git a/ansible/roles/heat/templates/heat.conf.j2 b/ansible/roles/heat/templates/heat.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..9d891758e5b6d0fb93fa46e8814393fdec25bff9
--- /dev/null
+++ b/ansible/roles/heat/templates/heat.conf.j2
@@ -0,0 +1,45 @@
+[DEFAULT]
+heat_watch_server_url = http://{{ kolla_external_address }}:{{ heat_api_cfn_port }}
+heat_metadata_server_url = http://{{ kolla_external_address }}:{{ heat_api_cfn_port }}
+heat_waitcondition_server_url = http://{{ kolla_external_address }}:{{ heat_api_cfn_port }}/v1/waitcondition
+
+stack_domain_admin = heat_domain_admin
+stack_domain_admin_password = {{ heat_domain_admin_password }}
+stack_user_domain_name = heat_user_domain
+
+rpc_backend = rabbit
+notification_driver = noop
+
+[oslo_messaging_rabbit]
+rabbit_host = {{ kolla_internal_address }}
+rabbit_userid = {{ rabbitmq_user }}
+rabbit_password = {{ rabbitmq_password }}
+rabbit_ha_queues = true
+
+{% if service_name == 'heat-api' %}
+[heat_api]
+bind_host = {{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}
+bind_port = {{ heat_api_port }}
+{% endif %}
+
+{% if service_name == 'heat-api-cfn' %}
+[heat_api_cfn]
+bind_host = {{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}
+bind_port = {{ heat_api_cfn_port }}
+{% endif %}
+
+[database]
+connection = mysql://{{ heat_database_user }}:{{ heat_database_password }}@{{ heat_database_address }}/{{ heat_database_name }}
+
+[keystone_authtoken]
+auth_uri = http://{{ kolla_internal_address }}:{{ keystone_public_port }}
+auth_url = http://{{ kolla_internal_address }}:{{ keystone_admin_port }}
+auth_plugin = password
+project_domain_id = default
+user_domain_id = default
+project_name = service
+username = heat
+password = {{ heat_keystone_password }}
+
+[ec2authtoken]
+auth_uri = http://{{ kolla_internal_address }}:{{ keystone_public_port }}
diff --git a/ansible/site.yml b/ansible/site.yml
index b395249023567025e24559f7e26cdc3fbb503bdb..6eeafed366f42c33fb50c5823d524ef72e785a4a 100755
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -35,6 +35,10 @@
   roles:
     - { role: cinder, tags: cinder, when: enable_cinder | bool }
 
+- hosts: [heat-api, heat-api-cfn, heat-engine]
+  roles:
+    - { role: heat, tags: heat, when: enable_heat | bool }
+
 - hosts: horizon
   roles:
     - { role: horizon, tags: horizon, when: enable_horizon | bool }
diff --git a/docker/base/Dockerfile.j2 b/docker/base/Dockerfile.j2
index 3e8d6abdf190c76deec6101edf6f8ab7f6d9f22f..6213f2c70e0f1d60d9e4fcae2fcaff9b0b6ac426 100755
--- a/docker/base/Dockerfile.j2
+++ b/docker/base/Dockerfile.j2
@@ -61,6 +61,7 @@ RUN yum install -y \
         git \
         iproute \
         mariadb-libs \
+        MySQL-python \
         openssl \
         openstack-utils \
         pyparsing \
@@ -104,6 +105,7 @@ RUN yum install -y \
         python-netifaces \
         python-networkx \
         python-oauthlib \
+        python-openstackclient \
         python-oslo-config \
         python-oslo-messaging \
         python-oslo-rootwrap \
@@ -155,7 +157,6 @@ RUN yum update -y \
         libxslt-devel \
         mariadb-devel \
         mysql-devel \
-        MySQL-python \
         openldap-devel \
         openssl \
         openssl-devel \
@@ -193,7 +194,6 @@ RUN apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com 199369E5404BD
         build-essential \
         python-dev \
         libssl-dev \
-        python-mysqldb \
         libmariadbclient-dev \
         libxslt1-dev \
         libffi-dev \
@@ -211,7 +211,11 @@ RUN apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com 199369E5404BD
 
 RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py \
     && python get-pip.py \
-    && rm get-pip.py
+    && rm get-pip.py \
+    && pip --no-cache-dir install \
+        python-openstackclient \
+        MySQL-python \
+        numpy
 
 # Endif for install_type source
 {% endif %}
diff --git a/docker/designate/designate-base/Dockerfile.j2 b/docker/designate/designate-base/Dockerfile.j2
index 2df82c29740524f5298089b22b74b8c0bec389ad..8f6afa925c30d130f88d12bc9e07bc69432e8aa2 100644
--- a/docker/designate/designate-base/Dockerfile.j2
+++ b/docker/designate/designate-base/Dockerfile.j2
@@ -9,10 +9,9 @@ MAINTAINER Kolla Project (https://launchpad.net.kolla)
 # need the complete policy file because of some of the containers'
 # requiring it. Remove the package when the file is moved though.
 RUN yum install -y \
-    MySQL-python \
-    openstack-designate-api \
-    openstack-designate-common \
-    python-tooz \
+        openstack-designate-api \
+        openstack-designate-common \
+        python-tooz \
     && yum clean all \
     && cp /etc/designate/policy.json /tmp/ \
     && rpm -e openstack-designate-api \
diff --git a/docker/heat/heat-api-cfn/Dockerfile.j2 b/docker/heat/heat-api-cfn/Dockerfile.j2
index f199c16cfde588a865a3dcf2cd6a8f14eb227520..0e0b099078ca8fec8de82040de0119b438e965de 100644
--- a/docker/heat/heat-api-cfn/Dockerfile.j2
+++ b/docker/heat/heat-api-cfn/Dockerfile.j2
@@ -4,9 +4,7 @@ MAINTAINER Kolla Project (https://launchpad.net/kolla)
 {% if install_type == 'binary' %}
     {% if base_distro in ['fedora', 'centos', 'oraclelinux'] %}
 
-RUN yum -y install \
-    openstack-heat-api-cfn \
-    python-openstackclient \
+RUN yum -y install openstack-heat-api-cfn \
     && yum clean all
 
     {% elif base_distro in ['ubuntu', 'debian'] %}
diff --git a/docker/heat/heat-api/Dockerfile.j2 b/docker/heat/heat-api/Dockerfile.j2
index 8a782d8d3b504bdfce3ad9264d63c4feddc2d85b..25cbcf9f58075811c6a5e38353c6355976884d3a 100644
--- a/docker/heat/heat-api/Dockerfile.j2
+++ b/docker/heat/heat-api/Dockerfile.j2
@@ -4,9 +4,7 @@ MAINTAINER Kolla Project (https://launchpad.net/kolla)
 {% if install_type == 'binary' %}
     {% if base_distro in ['fedora', 'centos', 'oraclelinux'] %}
 
-RUN yum -y install \
-    openstack-heat-api \
-    python-openstackclient \
+RUN yum -y install openstack-heat-api \
     && yum clean all
 
     {% elif base_distro in ['ubuntu', 'debian'] %}
diff --git a/docker/heat/heat-api/config-external.sh b/docker/heat/heat-api/config-external.sh
index ca5d73e909bda0e7ee4d332639f9cd02844b4feb..2da92b2031527eaedcbd2086f4bfe7217065ef9f 100644
--- a/docker/heat/heat-api/config-external.sh
+++ b/docker/heat/heat-api/config-external.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
-SOURCE="/opt/kolla/heat-api/heat-api.conf"
-TARGET="/etc/heat/heat-api.conf"
+SOURCE="/opt/kolla/heat-api/heat.conf"
+TARGET="/etc/heat/heat.conf"
 OWNER="heat"
 
 if [[ -f "$SOURCE" ]]; then
diff --git a/docker/heat/heat-api/start.sh b/docker/heat/heat-api/start.sh
index a7b14b1d9afd34f371a5ed6cf4727c134e2795f7..25bfa2bff66219f6cc49b881ec62e2fd792db5ee 100755
--- a/docker/heat/heat-api/start.sh
+++ b/docker/heat/heat-api/start.sh
@@ -10,4 +10,14 @@ source /opt/kolla/kolla-common.sh
 # Execute config strategy
 set_configs
 
+# Bootstrap and exit if KOLLA_BOOTSTRAP variable is set. This catches all cases
+# of the KOLLA_BOOTSTRAP variable being set, including empty.
+if [[ "${!KOLLA_BOOTSTRAP[@]}" ]]; then
+    su -s /bin/sh -c "heat-manage db_sync" heat
+    openstack domain create heat_user_domain
+    openstack user create --domain heat_user_domain heat_domain_admin --password ${HEAT_DOMAIN_ADMIN_PASSWORD}
+    openstack role add --domain heat_user_domain --user heat_domain_admin admin
+    exit 0
+fi
+
 exec $CMD $ARGS
diff --git a/docker/ironic/ironic-base/Dockerfile.j2 b/docker/ironic/ironic-base/Dockerfile.j2
index 8af231f7ae9152af993b9725b73c3a612ba140fa..4de31d2b7d2f7e26a9a496fba78b81591582c8e5 100644
--- a/docker/ironic/ironic-base/Dockerfile.j2
+++ b/docker/ironic/ironic-base/Dockerfile.j2
@@ -6,12 +6,10 @@ MAINTAINER Kolla Project (https://launchpad.net/kolla)
 
 # until packaging is fixed, all of this is required
 # api: policy
-# conductor:MySQL-python
 RUN yum -y install \
         python-oslo-log \
         python-oslo-concurrency \
         python-oslo-policy \
-        MySQL-python \
     && yum clean all
 
     {% elif base_distro in ['ubuntu', 'debian'] %}
diff --git a/docker/keystone/Dockerfile.j2 b/docker/keystone/Dockerfile.j2
index db5292399b124665b9a3c9a1f7dd808f0efd2c50..e71d7dfb9f9328940f281f153beb70bbf54aa7d6 100644
--- a/docker/keystone/Dockerfile.j2
+++ b/docker/keystone/Dockerfile.j2
@@ -6,7 +6,6 @@ MAINTAINER Kolla Project (https://launchpad.net/kolla)
 
 RUN yum -y install openstack-keystone \
         python-keystoneclient \
-        python-openstackclient \
         httpd \
         mod_wsgi \
     && yum clean all
diff --git a/docker/kolla-ansible/Dockerfile.j2 b/docker/kolla-ansible/Dockerfile.j2
index 9975f587383f9c9dbb9ae4ab1f6f6ab0cab2f2c4..9b84c761e0cba8405019f3f492c3a045e492f218 100644
--- a/docker/kolla-ansible/Dockerfile.j2
+++ b/docker/kolla-ansible/Dockerfile.j2
@@ -9,7 +9,6 @@ RUN yum -y install \
         libffi-devel \
         libxml2-devel \
         libxslt-devel \
-        MySQL-python \
         openssl-devel \
         python-devel \
         openssh-clients \
@@ -19,16 +18,17 @@ RUN pip install -U pip wheel
 
 {% elif base_distro in ['ubuntu', 'debian'] %}
 
-RUN apt-get install -y --no-install-recommends git
+RUN apt-get install -y --no-install-recommends git \
+    && apt-get clean
 
 {% endif %}
 
-RUN pip install shade
+RUN pip --no-cache-dir install shade
 
 RUN git clone --depth 1 https://github.com/ansible/ansible.git \
     && cd ansible \
     && git submodule update --init --recursive \
-    && pip install --install-option="--install-scripts=/usr/bin" .
+    && pip --no-cache-dir install .
 
 RUN mkdir -p /etc/ansible /usr/share/ansible \
     && echo 'localhost ansible_connection=local' > /etc/ansible/hosts
diff --git a/etc/kolla/config/heat.conf b/etc/kolla/config/heat.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/etc/kolla/config/heat/heat-api-cfn.conf b/etc/kolla/config/heat/heat-api-cfn.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/etc/kolla/config/heat/heat-api.conf b/etc/kolla/config/heat/heat-api.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/etc/kolla/config/heat/heat-engine.conf b/etc/kolla/config/heat/heat-engine.conf
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/etc/kolla/passwords.yml b/etc/kolla/passwords.yml
index e73f573f72a21f62488cf463ca48167bb6a53b8d..dacfcd6ee3e169813209f9993892547c5dbbfe20 100644
--- a/etc/kolla/passwords.yml
+++ b/etc/kolla/passwords.yml
@@ -30,7 +30,6 @@ nova_keystone_password: "password"
 
 neutron_database_password: "password"
 neutron_keystone_password: "password"
-
 metadata_secret: "password"
 
 cinder_database_password: "password"
@@ -40,6 +39,10 @@ swift_keystone_password: "password"
 swift_hash_path_suffix: "kolla"
 swift_hash_path_prefix: "kolla"
 
+heat_database_password: "password"
+heat_keystone_password: "password"
+heat_domain_admin_password: "password"
+
 ####################
 # RabbitMQ options
 ####################