diff --git a/doc/source/administration/overcloud.rst b/doc/source/administration/overcloud.rst
index 535100378..f1ca0d229 100644
--- a/doc/source/administration/overcloud.rst
+++ b/doc/source/administration/overcloud.rst
@@ -10,9 +10,10 @@ It is possible to update packages on the overcloud hosts.
 Package Repositories
 --------------------
 
-If using custom package repositories, it may be necessary to update these prior
-to running a package update. To do this, update the configuration in
-``${KAYOBE_CONFIG_PATH}/dnf.yml`` and run the following command::
+If using custom DNF package repositories on CentOS, it may be necessary to
+update these prior to running a package update. To do this, update the
+configuration in ``${KAYOBE_CONFIG_PATH}/dnf.yml`` and run the following
+command::
 
     (kayobe) $ kayobe overcloud host configure --tags dnf --kolla-tags none
 
diff --git a/doc/source/administration/seed.rst b/doc/source/administration/seed.rst
index 8ac64ae4a..c23428abd 100644
--- a/doc/source/administration/seed.rst
+++ b/doc/source/administration/seed.rst
@@ -21,9 +21,10 @@ It is possible to update packages on the seed host.
 Package Repositories
 --------------------
 
-If using custom package repositories, it may be necessary to update these prior
-to running a package update. To do this, update the configuration in
-``${KAYOBE_CONFIG_PATH}/dnf.yml`` and run the following command::
+If using custom DNF package repositories on CentOS, it may be necessary to
+update these prior to running a package update. To do this, update the
+configuration in ``${KAYOBE_CONFIG_PATH}/dnf.yml`` and run the following
+command::
 
     (kayobe) $ kayobe seed host configure --tags dnf --kolla-tags none
 
diff --git a/doc/source/configuration/reference/bifrost.rst b/doc/source/configuration/reference/bifrost.rst
index aafa55911..a8d1d7ccc 100644
--- a/doc/source/configuration/reference/bifrost.rst
+++ b/doc/source/configuration/reference/bifrost.rst
@@ -52,16 +52,18 @@ configuration drive built by Bifrost, rather than the Bifrost default of
 :diskimage-builder-doc:`simple-init <elements/simple-init/README>`.
 
 ``kolla_bifrost_dib_os_element``
-    DIB base OS element. Default is ``centos``.
+    DIB base OS element. Default is ``{{ os_distribution }}``.
 ``kolla_bifrost_dib_os_release``
-    DIB image OS release. Default is ``8``.
+    DIB image OS release. Default is ``{{ os_release }}``.
 ``kolla_bifrost_dib_elements_default``
     *Added in the Train release. Use kolla_bifrost_dib_elements in earlier
     releases.*
 
     List of default DIB elements. Default is ``["disable-selinux",
-    "enable-serial-console", "vm"]``. The ``vm`` element is poorly named, and
-    causes DIB to build a whole disk image rather than a single partition.
+    "enable-serial-console", "vm"]`` when ``os_distribution`` is ``centos``, or
+    ``["enable-serial-console", "vm"]`` otherwise. The ``vm`` element is
+    poorly named, and causes DIB to build a whole disk image rather than a
+    single partition.
 ``kolla_bifrost_dib_elements_extra``
     *Added in the Train release. Use kolla_bifrost_dib_elements in earlier
     releases.*
diff --git a/doc/source/configuration/reference/hosts.rst b/doc/source/configuration/reference/hosts.rst
index 1bcf98c44..1625a9f4c 100644
--- a/doc/source/configuration/reference/hosts.rst
+++ b/doc/source/configuration/reference/hosts.rst
@@ -77,8 +77,8 @@ is ``stack``.
 Typically, the image used to provision these hosts will not include this user
 account, so Kayobe performs a bootstrapping step to create it, as a different
 user. In cloud images, there is often a user named after the OS distro, e.g.
-``centos`` or ``ubuntu``. This user defaults to the name of the user running
-Kayobe, but may be set via the following variables:
+``centos`` or ``ubuntu``. This user defaults to the ``os_distribution``
+variable, but may be set via the following variables:
 
 * ``seed_hypervisor_bootstrap_user``
 * ``seed_bootstrap_user``
@@ -87,12 +87,12 @@ Kayobe, but may be set via the following variables:
 * ``monitoring_bootstrap_user``
 * ``storage_bootstrap_user``
 
-For example, to set the bootstrap user for controllers to ``centos``:
+For example, to set the bootstrap user for controllers to ``example-user``:
 
 .. code-block:: yaml
    :caption: ``controllers.yml``
 
-   controller_bootstrap_user: centos
+   controller_bootstrap_user: example-user
 
 PyPI Mirror and proxy
 =====================
@@ -202,13 +202,13 @@ added to the Kayobe configuration.
       ssh_key:
         - "{{ lookup('file', kayobe_config_path ~ '/ssh-keys/id_rsa_bob.pub') }}"
 
-Package Repositories
-====================
+DNF Package Repositories
+========================
 *tags:*
   | ``dnf``
 
-Kayobe supports configuration of package repositories via DNF, via variables in
-``${KAYOBE_CONFIG_PATH}/dnf.yml``.
+On CentOS, Kayobe supports configuration of package repositories via DNF, via
+variables in ``${KAYOBE_CONFIG_PATH}/dnf.yml``.
 
 Configuration of dnf.conf
 -------------------------
@@ -295,11 +295,25 @@ installed by setting ``dnf_automatic_upgrade_type`` to ``default``. This may
 cause the system to be less predictable as packages are updated without
 oversight or testing.
 
+Apt
+===
+
+On Ubuntu, Apt is used to manage packages and package repositories. Currently
+Kayobe does not provide support for configuring custom Apt repositories.
+
+Apt cache
+---------
+
+The Apt cache timeout may be configured via ``apt_cache_valid_time`` (in
+seconds) in ``etc/kayobe/apt.yml``, and defaults to 3600.
+
 SELinux
 =======
 *tags:*
   | ``disable-selinux``
 
+.. note:: SELinux applies to CentOS systems only.
+
 SELinux is not supported by Kolla Ansible currently, so it is disabled by
 Kayobe. If necessary, Kayobe will reboot systems in order to apply a change to
 the SELinux configuration. The timeout for waiting for systems to reboot is
diff --git a/doc/source/configuration/reference/index.rst b/doc/source/configuration/reference/index.rst
index e4f6d99a0..380144bce 100644
--- a/doc/source/configuration/reference/index.rst
+++ b/doc/source/configuration/reference/index.rst
@@ -10,6 +10,7 @@ options.
 
    kayobe
    ansible
+   os-distribution
    physical-network
    network
    routed-control-plane-networks
diff --git a/doc/source/configuration/reference/ironic-python-agent.rst b/doc/source/configuration/reference/ironic-python-agent.rst
index ad3c92e54..e60c37261 100644
--- a/doc/source/configuration/reference/ironic-python-agent.rst
+++ b/doc/source/configuration/reference/ironic-python-agent.rst
@@ -58,8 +58,9 @@ image build``.
 ``ipa_build_dib_env_default``
     Dictionary of default environment variables to provide to Diskimage Builder
     (DIB) during IPA image build. Default is
-    ``{"DIB_REPOLOCATION_ironic_agent": "{{ ipa_build_source_url }}",
-    "DIB_REPOREF_ironic_agent": "{{ ipa_build_source_version }}"}``.
+    ``{"DIB_RELEASE": "8-stream", "DIB_REPOLOCATION_ironic_agent": "{{
+    ipa_build_source_url }}", "DIB_REPOREF_ironic_agent": "{{
+    ipa_build_source_version }}"}``.
 ``ipa_build_dib_env_extra``
     Dictionary of additional environment variables to provide to Diskimage
     Builder (DIB) during IPA image build. Default is empty.
diff --git a/doc/source/configuration/reference/kolla.rst b/doc/source/configuration/reference/kolla.rst
index de8a74848..fa3b20bb4 100644
--- a/doc/source/configuration/reference/kolla.rst
+++ b/doc/source/configuration/reference/kolla.rst
@@ -73,7 +73,8 @@ used to generate the Kolla configuration file, ``kolla-build.conf``, and also
 affect :ref:`Kolla Ansible configuration <configuration-kolla-ansible-global>`.
 
 ``kolla_base_distro``
-    Kolla base container image distribution. Default is ``centos``.
+    Kolla base container image distribution. Options are ``centos``,
+    ``debian``, or ``ubuntu``. Default is ``{{ os_distribution }}``.
 ``kolla_install_type``
     Kolla container image type: ``binary`` or ``source``. Default is
     ``binary``.
diff --git a/doc/source/configuration/reference/network.rst b/doc/source/configuration/reference/network.rst
index 3084d021d..dcfe6b3e6 100644
--- a/doc/source/configuration/reference/network.rst
+++ b/doc/source/configuration/reference/network.rst
@@ -71,6 +71,12 @@ supported:
 
     On CentOS, each item should be a string describing an ``iproute2`` IP
     routing rule.
+
+    On Ubuntu, each item should be a dict containing optional items ``from``,
+    ``to``, ``priority`` and ``table``. ``from`` is the source address prefix
+    to match with optional prefix. ``to`` is the destination address prefix to
+    match with optional prefix. ``priority`` is the priority of the rule.
+    ``table`` is the routing table ID.
 ``physical_network``
     Name of the physical network on which this network exists. This aligns with
     the physical network concept in neutron.
@@ -168,6 +174,8 @@ If necessary, custom options may be added to the route:
          - onlink
          - metric 400
 
+Note that custom options are not currently supported on Ubuntu.
+
 Configuring a VLAN
 ------------------
 
diff --git a/doc/source/configuration/reference/os-distribution.rst b/doc/source/configuration/reference/os-distribution.rst
new file mode 100644
index 000000000..4e86962b8
--- /dev/null
+++ b/doc/source/configuration/reference/os-distribution.rst
@@ -0,0 +1,34 @@
+===============
+OS Distribution
+===============
+
+As of the Wallaby 10.0.0 release, Kayobe supports multiple Operating System
+(OS) distributions. See the :ref:`support matrix <support-matrix-supported-os>`
+for a list of supported OS distributions. The same OS distribution should be
+used throughout the system.
+
+The ``os_distribution`` variable in ``etc/kayobe/globals.yml`` can be used to
+set the OS distribution to use.  It may be set to either ``centos`` or
+``ubuntu``, and defaults to ``centos``.
+
+The ``os_release`` variable in ``etc/kayobe/globals.yml`` can be used to set
+the release of the OS. When ``os_distribution`` is set to ``centos`` it may be
+set to ``8-stream``, and this is its default value. When ``os_distribution`` is
+set to ``ubuntu`` it may be set to ``focal``, and this is its default value.
+
+These variables are used to set various defaults, including:
+
+* Bootstrap users
+* Overcloud host root disk image build configuration
+* Seed VM root disk image
+* Kolla base container image
+
+Example: using Ubuntu
+=====================
+
+In the following example, we set the OS distribution to ``ubuntu``:
+
+.. code-block:: yaml
+   :caption: ``globals.yml``
+
+   os_distribution: "ubuntu"
diff --git a/doc/source/configuration/scenarios/all-in-one/index.rst b/doc/source/configuration/scenarios/all-in-one/index.rst
index 8c7c5a037..313534698 100644
--- a/doc/source/configuration/scenarios/all-in-one/index.rst
+++ b/doc/source/configuration/scenarios/all-in-one/index.rst
@@ -40,7 +40,8 @@ Prerequisites
 This scenario requires:
 
 * a basic understanding of Linux, networking and OpenStack
-* a single CentOS 8 host (VM or bare metal)
+* a single host running a :ref:`supported operating system
+  <support-matrix-supported-os>` (VM or bare metal)
 * at least one network interface that has Internet access
 * an IP subnet with a free IP address for the OpenStack API virtual IP, and a
   range of free IP addresses for external network access
diff --git a/doc/source/configuration/scenarios/all-in-one/overcloud.rst b/doc/source/configuration/scenarios/all-in-one/overcloud.rst
index fbb4dbc83..8028653e6 100644
--- a/doc/source/configuration/scenarios/all-in-one/overcloud.rst
+++ b/doc/source/configuration/scenarios/all-in-one/overcloud.rst
@@ -184,6 +184,15 @@ Use the correct hostname and IP address for your environment.
    aio_ips:
      controller0: 192.168.33.3
 
+The default OS distribution in Kayobe is CentOS. If using an Ubuntu host, set
+the ``os_distribution`` variable in ``etc/kayobe/globals.yml`` to ``ubuntu``.
+
+.. code-block:: yaml
+   :caption: ``etc/kayobe/globals.yml``
+
+   ---
+   os_distribution: "ubuntu"
+
 In a development environment, we may wish to tune some Kolla Ansible variables.
 Using QEMU as the virtualisation type will be necessary if KVM is not
 available. Reducing the number of OpenStack service workers helps to avoid
diff --git a/doc/source/contributor/automated.rst b/doc/source/contributor/automated.rst
index e3cd2153e..e26d3adc3 100644
--- a/doc/source/contributor/automated.rst
+++ b/doc/source/contributor/automated.rst
@@ -56,10 +56,9 @@ Clone the ``kayobe-config-dev`` repository to ``config/src/kayobe-config``::
 Inspect the Kayobe configuration and make any changes necessary for your
 environment.
 
-If using Ubuntu, configure Kolla Ansible to use the Ubuntu source images::
+If using Ubuntu, configure the OS distribution::
 
-    sed -i -e 's/#kolla_base_distro:/kolla_base_distro: ubuntu/' config/src/kayobe-config/etc/kayobe/kolla.yml
-    sed -i -e 's/#kolla_install_type:/kolla_install_type: source/' config/src/kayobe-config/etc/kayobe/kolla.yml
+    sed -i -e 's/#os_distribution:/os_distribution: ubuntu/' config/src/kayobe-config/etc/kayobe/globals.yml
 
 If using Vagrant, follow the steps in :ref:`contributor-vagrant` to prepare
 your environment for use with Vagrant and bring up a Vagrant VM.
@@ -71,7 +70,7 @@ port ``eth1``, and an IP address of ``192.168.33.3/24``.  This can be modified
 by editing
 ``config/src/kayobe-config/etc/kayobe/inventory/group_vars/controllers/network-interfaces``.
 
-On CentOS, this can be added using the following commands::
+This can be added using the following commands::
 
     sudo ip l add breth1 type bridge
     sudo ip l set breth1 up
@@ -80,30 +79,6 @@ On CentOS, this can be added using the following commands::
     sudo ip l set eth1 up
     sudo ip l set eth1 master breth1
 
-On Ubuntu, the interface configuration must be persistent::
-
-    sudo apt update
-    sudo apt -y install ifupdown
-
-    sudo ip l add breth1 type bridge
-    sudo ip l add eth1 type dummy
-
-    cat << EOF | sudo tee /etc/network/interfaces.d/ifcfg-eth1
-    auto eth1
-    iface eth1 inet manual
-    EOF
-
-    cat << EOF | sudo tee /etc/network/interfaces.d/ifcfg-breth1
-    auto breth1
-    iface breth1 inet static
-    address 192.168.33.3
-    netmask 255.255.255.0
-    bridge_ports eth1
-    EOF
-
-    sudo ifup eth1
-    sudo ifup breth1
-
 Usage
 -----
 
@@ -231,6 +206,10 @@ Clone the ``kayobe-config-dev`` repository to ``config/src/kayobe-config``::
 Inspect the Kayobe configuration and make any changes necessary for your
 environment.
 
+If using Ubuntu, configure the OS distribution::
+
+    sed -i -e 's/#os_distribution:/os_distribution: ubuntu/' config/src/kayobe-config/etc/kayobe/globals.yml
+
 The default development configuration expects the presence of a bridge
 interface on the seed host to carry provisioning traffic.  The bridge should be
 named ``breth1`` with a single port ``eth1``, and an IP address of
@@ -374,6 +353,10 @@ Clone the ``add-seed-and-hv`` branch of the ``kayobe-config-dev`` repository to
 Inspect the Kayobe configuration and make any changes necessary for your
 environment.
 
+If using Ubuntu, configure the OS distribution::
+
+    sed -i -e 's/#os_distribution:/os_distribution: ubuntu/' config/src/kayobe-config/etc/kayobe/globals.yml
+
 Usage
 -----
 
diff --git a/doc/source/deployment.rst b/doc/source/deployment.rst
index 94afea952..b83324166 100644
--- a/doc/source/deployment.rst
+++ b/doc/source/deployment.rst
@@ -100,10 +100,10 @@ VM Provisioning
    bare metal host or a VM provisioned outside of Kayobe, this step may be
    skipped.  Ensure that the Ansible inventory contains a host for the seed.
 
-The seed hypervisor should have CentOS and ``libvirt`` installed.  It should
-have ``libvirt`` networks configured for all networks that the seed VM needs
-access to and a ``libvirt`` storage pool available for the seed VM's volumes.
-To provision the seed VM::
+The seed hypervisor should have CentOS or Ubuntu with ``libvirt`` installed.
+It should have ``libvirt`` networks configured for all networks that the seed
+VM needs access to and a ``libvirt`` storage pool available for the seed VM's
+volumes.  To provision the seed VM::
 
     (kayobe) $ kayobe seed vm provision
 
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
index ba92554c2..247cae68e 100644
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -15,8 +15,9 @@ Prerequisites
 Currently Kayobe supports the following Operating Systems on the Ansible
 control host:
 
-- CentOS 8
-- Ubuntu 16.04
+- CentOS Linux 8
+- CentOS Stream 8 (since Wallaby 10.0.0 release)
+- Ubuntu Focal 20.04 (since Wallaby 10.0.0 release)
 
 See the :doc:`support matrix <support-matrix>` for details of supported
 Operating Systems for other hosts.
diff --git a/doc/source/resources.rst b/doc/source/resources.rst
index d3a84fdb5..c3011b740 100644
--- a/doc/source/resources.rst
+++ b/doc/source/resources.rst
@@ -22,8 +22,8 @@ OpenStack using Kolla, Ansible and Kayobe. The guide makes use of
 baremetal environment running on a single hypervisor.
 
 To complete the walkthrough you will require a baremetal or VM hypervisor
-running CentOS 8 with at least 32GB RAM & 80GB disk space.
-Preparing the deployment can take some time - where possible it is
-beneficial to snapshot the hypervisor. We advise making a snapshot after
-creating the initial 'seed' VM as this will make additional deployments
-significantly faster.
+running CentOS 8 or Ubuntu Focal 20.04 (since Wallaby 10.0.0) with at least
+32GB RAM & 80GB disk space.  Preparing the deployment can take some time -
+where possible it is beneficial to snapshot the hypervisor. We advise making a
+snapshot after creating the initial 'seed' VM as this will make additional
+deployments significantly faster.
diff --git a/doc/source/support-matrix.rst b/doc/source/support-matrix.rst
index 9593933ab..8face4e44 100644
--- a/doc/source/support-matrix.rst
+++ b/doc/source/support-matrix.rst
@@ -2,12 +2,15 @@
 Support Matrix
 ==============
 
+.. _support-matrix-supported-os:
+
 Supported Operating Systems
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Kayobe supports the following host Operating Systems (OS):
 
-* CentOS 8
+* CentOS Stream 8 (since Wallaby 10.0.0 release)
+* Ubuntu Focal 20.04 (since Wallaby 10.0.0 release)
 
 .. note::
 
@@ -16,6 +19,12 @@ Kayobe supports the following host Operating Systems (OS):
    Train documentation <https://docs.openstack.org/kayobe/train/centos8.html>`_
    for information on migrating to CentOS 8.
 
+.. note::
+
+   CentOS Linux 8 (as opposed to CentOS Stream 8) is no longer supported as a
+   host OS. The Victoria release will in future support both CentOS Linux 8 and
+   CentOS Stream 8, and provides a route for migration.
+
 Supported container images
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/releasenotes/notes/ubuntu-e74f49ea72f69869.yaml b/releasenotes/notes/ubuntu-e74f49ea72f69869.yaml
new file mode 100644
index 000000000..d67bb27b7
--- /dev/null
+++ b/releasenotes/notes/ubuntu-e74f49ea72f69869.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Adds support for Ubuntu Focal 20.04 as a host and container Operating
+    System for seed, seed hypervisor and overcloud hosts.