diff --git a/ci/environments/scenario009-multinode.yaml b/ci/environments/scenario009-multinode.yaml
index 26d1af9929..5231ff54e6 100644
--- a/ci/environments/scenario009-multinode.yaml
+++ b/ci/environments/scenario009-multinode.yaml
@@ -22,7 +22,6 @@ parameter_defaults:
     - OS::TripleO::Services::HAproxy
     - OS::TripleO::Services::Keepalived
     - OS::TripleO::Services::OpenShift::Master
-    - OS::TripleO::Services::OpenShift::Worker
   ComputeServices:
     - OS::TripleO::Services::DisableUnbound
     - OS::TripleO::Services::CACerts
diff --git a/extraconfig/services/openshift-master.yaml b/extraconfig/services/openshift-master.yaml
index ead5cf56f5..1dd4044cbe 100644
--- a/extraconfig/services/openshift-master.yaml
+++ b/extraconfig/services/openshift-master.yaml
@@ -115,8 +115,8 @@ outputs:
               set_fact:
                 openshift_global_vars:
                   map_merge:
-                  - openshift_release: '3.9'
-                    openshift_version: '3.9.0'
+                  - openshift_release: '3.10'
+                    openshift_version: '3.10'
                     openshift_image_tag:
                       yaql:
                         expression:
@@ -147,18 +147,8 @@ outputs:
                           image: {get_param: DockerOpenShiftBaseImage}
                     etcd_image: {get_param: DockerOpenShiftEtcdImage}
                     osm_etcd_image: {get_param: DockerOpenShiftEtcdImage}
-                    osm_image:
-                      yaql:
-                        expression:
-                          $.data.image.rightSplit(":", 1)[0]
-                        data:
-                          image: {get_param: DockerOpenShiftBaseImage}
-                    osn_image:
-                      yaql:
-                        expression:
-                          $.data.image.rightSplit(":", 1)[0]
-                        data:
-                          image: {get_param: DockerOpenShiftNodeImage}
+                    osm_image: {get_param: DockerOpenShiftBaseImage}
+                    osn_image: {get_param: DockerOpenShiftNodeImage}
                     openshift_cockpit_deployer_prefix:
                       yaql:
                         expression:
@@ -184,6 +174,8 @@ outputs:
                         data:
                           image: {get_param: DockerOpenShiftBaseImage}
                     openshift_docker_additional_registries: {get_param: DockerInsecureRegistryAddress}
+                    openshift_master_bootstrap_auto_approve: true
+                    osm_controller_args: {"experimental-cluster-signing-duration": ["20m"]}
                   - {get_param: OpenShiftGlobalVariables}
                 tripleo_role_name: {get_param: RoleName}
                 tripleo_stack_action: {get_param: StackAction}
@@ -223,6 +215,8 @@ outputs:
                     ansible_user: "{{ hostvars[item]['ansible_user'] | default(hostvars[item]['ansible_ssh_user']) | default('root') }}"
                     ansible_host: "{{ hostvars[item]['ansible_host'] | default(item) }}"
                     ansible_become: true
+                    containerized: true
+                    openshift_node_group_name: 'node-config-master-infra'
                     etcd_ip: "{{hostvars[item][openshift_master_network + '_ip']}}"
                     openshift_ip: "{{hostvars[item][openshift_master_network + '_ip']}}"
                     openshift_master_bind_addr: "{{hostvars[item][openshift_master_network + '_ip']}}"
@@ -253,6 +247,13 @@ outputs:
                     {{host.hostname}}:
                         {{host | combine(openshift_master_node_vars) | to_nice_yaml() | indent(6)}}
                     {% endfor %}
+
+                  nodes:
+                    hosts:
+                    {% for host in master_nodes %}
+                    {{host.hostname}}:
+                        {{host | combine(openshift_master_node_vars) | to_nice_yaml() | indent(6)}}
+                    {% endfor %}
                   {% endif %}
 
                   {% if new_masters | count > 0 %}
@@ -263,6 +264,13 @@ outputs:
                         {{host | combine(openshift_master_node_vars) | to_nice_yaml() | indent(6)}}
                     {% endfor %}
 
+                  new_nodes:
+                    hosts:
+                    {% for host in master_nodes %}
+                    {{host.hostname}}:
+                        {{host | combine(openshift_master_node_vars) | to_nice_yaml() | indent(6)}}
+                    {% endfor %}
+
                   new_etcd:
                     children:
                       new_masters: {}
@@ -345,6 +353,8 @@ outputs:
                           state: restarted
                           enabled: yes
 
+
+                  - include: "/usr/share/ansible/openshift-ansible/playbooks/prerequisites.yml"
                   {% if tripleo_stack_action == 'UPDATE' and new_masters | count > 0 %}
                   - include: "{{openshift_master_scaleup_playbook_path}}"
                   {% endif %}
diff --git a/extraconfig/services/openshift-worker.yaml b/extraconfig/services/openshift-worker.yaml
index 6334676a64..03498be6f9 100644
--- a/extraconfig/services/openshift-worker.yaml
+++ b/extraconfig/services/openshift-worker.yaml
@@ -32,11 +32,30 @@ parameters:
     description: Mapping of service endpoint -> protocol. Typically set
                  via parameter_defaults in the resource registry.
     type: json
+  OpenShiftNodeGroupName:
+    default: node-config-compute
+    description: The group the nodes belong to.
+    type: string
+    tags:
+      - role_specific
   OpenShiftWorkerScaleupPlaybook:
     default: '/usr/share/ansible/openshift-ansible/playbooks/openshift-node/scaleup.yml'
     description: Path to OpenShift-Ansible playbook.
     type: string
 
+resources:
+  RoleParametersValue:
+    type: OS::Heat::Value
+    properties:
+      type: json
+      value:
+        map_replace:
+          - map_replace:
+            - OpenShiftNodeGroupName: OpenShiftNodeGroupName
+            - values: {get_param: [RoleParameters]}
+          - values:
+              OpenShiftNodeGroupName: {get_param: OpenShiftNodeGroupName}
+
 outputs:
   role_data:
     description: Role data for the Openshift Service
@@ -71,6 +90,7 @@ outputs:
             - name: set global vars facts
               set_fact:
                 tripleo_role_name: {get_param: RoleName}
+                tripleo_node_group_name: {get_attr: [RoleParametersValue, value, OpenShiftNodeGroupName]}
                 openshift_master_network: {get_param: [ServiceNetMap, OpenshiftMasterNetwork]}
                 openshift_worker_scaleup_playbook_path: {get_param: OpenShiftWorkerScaleupPlaybook}
 
@@ -82,7 +102,7 @@ outputs:
                 || echo "false"
               register: origin_nodes
               delegate_to: "{{item}}"
-              with_items: "{{ groups[tripleo_role_name] | default([])  }}"
+              with_items: "{{ groups[tripleo_role_name] | default([]) }}"
 
             - set_fact:
                 nodes:
@@ -91,16 +111,14 @@ outputs:
                     ansible_user: "{{ hostvars[item]['ansible_user'] | default(hostvars[item]['ansible_ssh_user']) | default('root') }}"
                     ansible_host: "{{ hostvars[item]['ansible_host'] | default(item) }}"
                     ansible_become: true
+                    containerized: true
+                    openshift_node_group_name: '{{tripleo_node_group_name }}'
                     etcd_ip: "{{hostvars[item][openshift_master_network + '_ip']}}"
                     openshift_ip: "{{hostvars[item][openshift_master_network + '_ip']}}"
                     openshift_public_ip: "{{hostvars[item][openshift_master_network + '_ip']}}"
                     openshift_hostname: "{{hostvars[item][openshift_master_network + '_ip']}}"
                     openshift_public_hostname: "{{hostvars[item][openshift_master_network + '_ip']}}"
-                    openshift_schedulable: true
-                    openshift_node_labels:
-                      region: 'infra'
-                      zone: 'default'
-                      node-role.kubernetes.io/compute: true
+                    openshift_schedulable: '{{tripleo_node_group_name != "node-config-infra"}}'
               register: all_worker_nodes
               with_items: "{{groups[tripleo_role_name] | default([]) }}"
 
diff --git a/roles/OpenShiftInfra.yaml b/roles/OpenShiftInfra.yaml
new file mode 100644
index 0000000000..d60c1df43a
--- /dev/null
+++ b/roles/OpenShiftInfra.yaml
@@ -0,0 +1,24 @@
+###############################################################################
+# Role: OpenShiftInfra                                                        #
+###############################################################################
+- name: OpenShiftInfra
+  description: |
+    OpenShiftInfra role, a specialized worker that only runs infra pods.
+  CountDefault: 1
+  tags:
+    - openshift
+  networks:
+    - InternalApi
+    - Storage
+    - StorageMgmt
+    - Tenant
+  RoleParametersDefault:
+    OpenShiftNodeGroupName: 'node-config-infra'
+  # For systems with both IPv4 and IPv6, you may specify a gateway network for
+  # each, such as ['ControlPlane', 'External']
+  default_route_networks: ['ControlPlane']
+  ServicesDefault:
+    - OS::TripleO::Services::Docker
+    - OS::TripleO::Services::Sshd
+    - OS::TripleO::Services::Ntp
+    - OS::TripleO::Services::OpenShift::Worker
diff --git a/roles/OpenShiftMaster.yaml b/roles/OpenShiftMaster.yaml
index ee42e85a5e..749aa47b9c 100644
--- a/roles/OpenShiftMaster.yaml
+++ b/roles/OpenShiftMaster.yaml
@@ -27,5 +27,3 @@
     - OS::TripleO::Services::HAproxy
     - OS::TripleO::Services::Keepalived
     - OS::TripleO::Services::OpenShift::Master
-    - OS::TripleO::Services::OpenShift::Worker
-    - OS::TripleO::Services::OpenShift::GlusterFS