Creating a Three Node OpenShift cluster with only one Control Plane node.

Posted by Mark DeNeve on Thursday, January 30, 2025

Is it possible to create an OpenShift cluster that contains one Control Plane node and multiple worker nodes? This is something that came up in a recent project, and as it turns out the answer is YES. Since OpenShift 4.11, it has been possible to add worker nodes to SNO OpenShift cluster. When you follow this process, you end up with a cluster that contains one or more worker nodes, along with the original SNO cluster.

$ oc get nodes
NAME                  STATUS   ROLES                         AGE   VERSION
ocp-worker-1          Ready    worker                        38h   v1.27.16+03a907c
ocp-worker-2          Ready    worker                        38h   v1.27.16+03a907c
ocp-control-plane-1   Ready    control-plane,master,worker   42h   v1.27.16+03a907c

But what if we don’t want the ocp-control-plane-1 node to be schedulable as a worker? Can we set it up so that it is ONLY a control-plane/master node? The answer is yes. In a non-OpenShift cluster we would simply remove the label node-role.kubernetes.io/worker from the node using the command oc adm label ocp-control-plane-1 node-role.kubernetes.io/worker- and the role would be removed. However if you try this with an OpenShift node, you will find that the change does not take effect. This is because the cluster scheduler operator is overriding your change based on the default configuration. So how do we make the change permanent, read on.

NOTE: Remember that building an OpenShift cluster with only one control-plane node means that when the control-plane node is down (be it due to failure, or maintenance), you will be unable to make any changes to the workloads running on the cluster, and any applications that leverage the “OpenShift Router” for exposing the application will not work, as all traffic must go through the control-plane node.

Prerequisites

The rest of this blog post will assume that you already have a

Cluster Configuration Changes Required

There are two changes that need to be made to your cluster to make your control-plane node not schedulable. The first is to edit the cluster scheduler, and the second is to update the ingress operator to run on the master node. We will take each of these changes one at a time.

Updating the Cluster Scheduler

We will start be editing the default Cluster Scheduler and changing the “mastersSchedulable” option from true to false. Log into the cluster using the oc login command, and then use the command oc edit schedulers.config.openshift.io cluster and change the spec.mastersSchedulable option to false as shown below.

apiVersion: config.openshift.io/v1
kind: Scheduler
metadata:
  name: cluster
spec:
  mastersSchedulable: false
  policy:
    name: ""
status: {}

Save your changes, and then we can check the state of the nodes:

$ oc get nodes
NAME                  STATUS   ROLES                 AGE   VERSION
ocp-worker-1          Ready    worker                38h   v1.27.16+03a907c
ocp-worker-2          Ready    worker                38h   v1.27.16+03a907c
ocp-control-plane-1   Ready    control-plane,master  42h   v1.27.16+03a907c

SUCCESS, but don’t celebrate just yet. If you reboot the ocp-control-plane-1 node, you will find that when the node starts back up, the OpenShift Ingress does not start. Lets check the pod status:

$ oc get po -n openshift-ingress
NAME                              READY   STATUS        RESTARTS       AGE
router-default-7f9ddc5fcc-xkcl7   0/1     Pending       0              39s

You will note that the pod shows as pending, lets take a look and see why.

$ oc describe po router-default-7f9ddc5fcc-xkcl7 -n openshift-ingress
<many lines omitted>
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  40m                default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/master: }, 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling..

From the output we can see that there is a taint on the master node, that is keeping it from being scheduled, so we will need to resolve this for the ingress controller to properly start. In order to do this, we will need to update the Ingress Controller and add a toleration so that the Ingress pod can run on the control-plane node.

Updating the Ingress Controller

The ingress controller needs to be updated so that it can run on the control-plane where the shared Ingress IP and API IP exist from deploying the SNO cluster. In order to do this we will need to edit the default IngressController oc edit ingresscontroller -n openshift-ingress-operator, update the section highlighted below:

apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
  name: default
  namespace: openshift-ingress-operator
spec:
 clientTLS:
    clientCA:
      name: ""
    clientCertificatePolicy: ""
  httpCompression: {}
  httpEmptyRequestsPolicy: Respond
  httpErrorCodePages:
    name: ""
  nodePlacement:
    nodeSelector:
      matchLabels:
        node-role.kubernetes.io/master: ""
    tolerations:
    - effect: NoSchedule
      key: node-role.kubernetes.io/master
      operator: Exists

Save your changes, and then we can check the state of the ingress pod:

$ oc get po -n openshift-ingress
NAME                             READY   STATUS    RESTARTS   AGE
router-default-6bbd55d79-nfbnw   1/1     Running   0          3s

Success! The router pod is now running on our control-plane node. You should now be able to access your cluster console at console-openshift-console.apps.<clustername>.<domainname>.

Checking the results

With these changes made we can go ahead and take a look at our cluster and make sure that it is up and running, and that the ocp-control-plane-1 node no longer has the “worker” role.

$ oc get nodes
NAME                  STATUS   ROLES                  AGE   VERSION
ocp-worker-1          Ready    worker                 38h   v1.27.16+03a907c
ocp-worker-2          Ready    worker                 38h   v1.27.16+03a907c
ocp-control-plane-1   Ready    control-plane,master   42h   v1.27.16+03a907c

Congratulations, you now have an OpenShift cluster with one control-plane node and two master nodes.

References

Configuring control plane nodes as schedulable