diff --git a/playbooks/kayobe-seed-vm-base/overrides.yml.j2 b/playbooks/kayobe-seed-vm-base/overrides.yml.j2
index 4cbd700f6c82e92afc6a746adea8ce74aca24d0f..3e036b99a26d39a01b74345cc5c4c33d3f505c3b 100644
--- a/playbooks/kayobe-seed-vm-base/overrides.yml.j2
+++ b/playbooks/kayobe-seed-vm-base/overrides.yml.j2
@@ -3,6 +3,12 @@
 # Ansible is run directly on the controller.
 disable_selinux_do_reboot: false
 
+{% if ansible_os_family == 'Debian' %}
+# On Ubuntu, use 5 seconds delay to allow for interfaces to come up after ifup
+# exits.
+interfaces_pause_time: 5
+{% endif %}
+
 # Use the OpenStack infra's Dockerhub mirror.
 docker_registry_mirrors:
   - "http://{{ zuul_site_mirror_fqdn }}:8082/"
diff --git a/playbooks/kayobe-seed-vm-base/pre.yml b/playbooks/kayobe-seed-vm-base/pre.yml
index 9b3c12fa89b88a7bd3a58102c5508336290814ea..8a369a6b7a0c56d2bdf9dae11ab40df3aa8fc92d 100644
--- a/playbooks/kayobe-seed-vm-base/pre.yml
+++ b/playbooks/kayobe-seed-vm-base/pre.yml
@@ -36,6 +36,7 @@
       selinux:
         state: disabled
       become: True
+      when: ansible_os_family == 'RedHat'
 
     # NOTE(mgoddard): Use the name zz-overrides.yml to ensure this takes
     # precedence over the standard config files.
@@ -53,3 +54,4 @@
       shell:
         cmd: dev/install.sh &> {{ logs_dir }}/ansible/install
         chdir: "{{ kayobe_src_dir }}"
+        executable: /bin/bash
diff --git a/playbooks/kayobe-seed-vm-base/run.yml b/playbooks/kayobe-seed-vm-base/run.yml
index bfda7dda6bf72812283ae768449a692ae4eab2a0..7bd57a154f6bbe69343fda238aae739579243870 100644
--- a/playbooks/kayobe-seed-vm-base/run.yml
+++ b/playbooks/kayobe-seed-vm-base/run.yml
@@ -9,7 +9,9 @@
     - name: Ensure seed hypervisor is deployed
       shell:
         cmd: "{{ kayobe_src_dir }}/dev/seed-hypervisor-deploy.sh > {{ logs_dir }}/ansible/seed-hypervisor-deploy"
+        executable: /bin/bash
 
     - name: Ensure seed is deployed
       shell:
         cmd: "{{ kayobe_src_dir }}/dev/seed-deploy.sh &> {{ logs_dir }}/ansible/seed-deploy"
+        executable: /bin/bash
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index 635859d1d2c8db8d70ef00fe249acfa0fe5cbc39..1b10afa36d01c9d3cb22d5c53c122918b2064376 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -198,3 +198,8 @@
     name: kayobe-seed-vm-centos8
     parent: kayobe-seed-vm-base
     nodeset: kayobe-centos8
+
+- job:
+    name: kayobe-seed-vm-ubuntu-focal
+    parent: kayobe-seed-vm-base
+    nodeset: kayobe-ubuntu-focal
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 0cf1e8e9196a5bb077cb51317c855cb2972dfd49..9d5fcbf7e72efec029c37c8b5cbe0a7740c0c8b8 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -19,6 +19,7 @@
         - kayobe-seed-centos8
         - kayobe-seed-upgrade-centos8
         - kayobe-seed-vm-centos8
+        - kayobe-seed-vm-ubuntu-focal
 
     gate:
       queue: kayobe
@@ -35,3 +36,4 @@
         - kayobe-seed-centos8
         - kayobe-seed-upgrade-centos8
         - kayobe-seed-vm-centos8
+        - kayobe-seed-vm-ubuntu-focal