From 4dc16a20a1cf52637817ead2ffc05b65536bf2b8 Mon Sep 17 00:00:00 2001 From: Wolfgang Kulhanek Date: Thu, 26 Feb 2026 15:24:37 +0100 Subject: [PATCH 1/3] scale_ocp_workers: remove worker label from control-plane --- roles/scale_ocp_workers/README.md | 16 ++++ roles/scale_ocp_workers/defaults/main.yml | 8 ++ .../tasks/configure_worker_only.yml | 90 +++++++++++++++++++ roles/scale_ocp_workers/tasks/main.yml | 4 + 4 files changed, 118 insertions(+) create mode 100644 roles/scale_ocp_workers/tasks/configure_worker_only.yml diff --git a/roles/scale_ocp_workers/README.md b/roles/scale_ocp_workers/README.md index 8907d31..cb5b27f 100644 --- a/roles/scale_ocp_workers/README.md +++ b/roles/scale_ocp_workers/README.md @@ -26,6 +26,22 @@ Scale to 5 workers with a different instance type: worker_machineset_suffix: compute ``` +Scale to 3 workers and enable worker-only mode (compact/SNO clusters): + +```yaml +- name: Scale OCP workers with worker-only mode + ansible.builtin.include_role: + name: agnosticd.cloud_provider_aws.scale_ocp_workers + vars: + worker_instance_count: 3 + worker_only: true +``` + +When `worker_only: true`, the role will: +1. Remove the `node-role.kubernetes.io/worker` label from control-plane nodes +2. Set `mastersSchedulable: false` on the Scheduler object (adds `NoSchedule` taint automatically) +3. Drain control-plane nodes to move existing workloads to the new workers (set `worker_drain_control_plane: false` to skip) + ## Variables See [defaults/main.yml](defaults/main.yml) for all variables and their defaults. diff --git a/roles/scale_ocp_workers/defaults/main.yml b/roles/scale_ocp_workers/defaults/main.yml index f7e873f..aa53926 100644 --- a/roles/scale_ocp_workers/defaults/main.yml +++ b/roles/scale_ocp_workers/defaults/main.yml @@ -30,3 +30,11 @@ worker_scale_approve_csrs: true worker_scale_csr_wait_seconds: 180 worker_scale_csr_retries: 30 worker_scale_csr_delay: 10 + +# Worker-only mode: removes worker label from control-plane nodes +# and sets mastersSchedulable: false on the Scheduler object +worker_only: false + +# Drain control-plane nodes to move existing workloads to dedicated workers +# Only applies when worker_only is true +worker_drain_control_plane: true diff --git a/roles/scale_ocp_workers/tasks/configure_worker_only.yml b/roles/scale_ocp_workers/tasks/configure_worker_only.yml new file mode 100644 index 0000000..60c39aa --- /dev/null +++ b/roles/scale_ocp_workers/tasks/configure_worker_only.yml @@ -0,0 +1,90 @@ +--- +# configure_worker_only.yml +# Removes worker role from control-plane nodes, disables master scheduling, +# and optionally drains control-plane nodes to move workloads to dedicated workers. + +- name: Get control-plane nodes + kubernetes.core.k8s_info: + api_version: v1 + kind: Node + label_selectors: + - "node-role.kubernetes.io/control-plane" + register: r_control_plane_nodes + +- name: Get master-labeled nodes + kubernetes.core.k8s_info: + api_version: v1 + kind: Node + label_selectors: + - "node-role.kubernetes.io/master" + register: r_master_nodes + +- name: Build list of control-plane nodes with worker label + ansible.builtin.set_fact: + control_plane_worker_nodes: >- + {%- set nodes = [] -%} + {%- set seen = [] -%} + {%- for node in (r_control_plane_nodes.resources + r_master_nodes.resources) -%} + {%- if node.metadata.name not in seen + and node.metadata.labels.get('node-role.kubernetes.io/worker') is defined -%} + {%- set _ = nodes.append(node.metadata.name) -%} + {%- set _ = seen.append(node.metadata.name) -%} + {%- endif -%} + {%- endfor -%} + {{ nodes }} + +- name: Display control-plane nodes with worker label + ansible.builtin.debug: + msg: "Control-plane nodes with worker label: {{ control_plane_worker_nodes }}" + +- name: Remove worker label from control-plane nodes + kubernetes.core.k8s: + api_version: v1 + kind: Node + name: "{{ item }}" + state: present + definition: + metadata: + labels: + node-role.kubernetes.io/worker: null + loop: "{{ control_plane_worker_nodes }}" + when: control_plane_worker_nodes | length > 0 + +- name: Set mastersSchedulable to false + kubernetes.core.k8s: + api_version: config.openshift.io/v1 + kind: Scheduler + name: cluster + state: present + definition: + spec: + mastersSchedulable: false + +- name: Drain and uncordon control-plane nodes + when: + - worker_drain_control_plane | default(true) | bool + - control_plane_worker_nodes | length > 0 + block: + - name: Drain control-plane node + kubernetes.core.k8s_drain: + name: "{{ item }}" + state: drain + delete_options: + ignore_daemonsets: true + delete_emptydir_data: true + force: true + loop: "{{ control_plane_worker_nodes }}" + + - name: Uncordon control-plane node + kubernetes.core.k8s_drain: + name: "{{ item }}" + state: uncordon + loop: "{{ control_plane_worker_nodes }}" + +- name: Display worker-only mode configuration results + ansible.builtin.debug: + msg: + - "Worker-only mode configured successfully" + - "Control-plane nodes with worker label removed: {{ control_plane_worker_nodes }}" + - "mastersSchedulable: false" + - "Control-plane nodes drained: {{ worker_drain_control_plane | default(true) | bool }}" diff --git a/roles/scale_ocp_workers/tasks/main.yml b/roles/scale_ocp_workers/tasks/main.yml index ebcd955..30ce3ec 100644 --- a/roles/scale_ocp_workers/tasks/main.yml +++ b/roles/scale_ocp_workers/tasks/main.yml @@ -78,3 +78,7 @@ - name: Wait for worker nodes to be Ready when: worker_instance_count | int > 0 ansible.builtin.include_tasks: wait_for_nodes.yml + + - name: Configure worker-only mode + when: worker_only | default(false) | bool + ansible.builtin.include_tasks: configure_worker_only.yml From 34b53862cac926653472eb105adcc9ea10626b75 Mon Sep 17 00:00:00 2001 From: Wolfgang Kulhanek Date: Thu, 26 Feb 2026 15:58:17 +0100 Subject: [PATCH 2/3] Ignore errors on drain --- .../tasks/configure_worker_only.yml | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/roles/scale_ocp_workers/tasks/configure_worker_only.yml b/roles/scale_ocp_workers/tasks/configure_worker_only.yml index 60c39aa..1723d2a 100644 --- a/roles/scale_ocp_workers/tasks/configure_worker_only.yml +++ b/roles/scale_ocp_workers/tasks/configure_worker_only.yml @@ -62,29 +62,31 @@ - name: Drain and uncordon control-plane nodes when: - - worker_drain_control_plane | default(true) | bool - - control_plane_worker_nodes | length > 0 + - worker_drain_control_plane | default(true) | bool + - control_plane_worker_nodes | length > 0 block: - - name: Drain control-plane node - kubernetes.core.k8s_drain: - name: "{{ item }}" - state: drain - delete_options: - ignore_daemonsets: true - delete_emptydir_data: true - force: true - loop: "{{ control_plane_worker_nodes }}" + - name: Drain control-plane node + kubernetes.core.k8s_drain: + name: "{{ item }}" + state: drain + delete_options: + ignore_daemonsets: true + delete_emptydir_data: true + force: true + loop: "{{ control_plane_worker_nodes }}" + # Ignore errors (e.g. apiserver PDB violation) + ignore_errors: true - - name: Uncordon control-plane node - kubernetes.core.k8s_drain: - name: "{{ item }}" - state: uncordon - loop: "{{ control_plane_worker_nodes }}" + - name: Uncordon control-plane node + kubernetes.core.k8s_drain: + name: "{{ item }}" + state: uncordon + loop: "{{ control_plane_worker_nodes }}" - name: Display worker-only mode configuration results ansible.builtin.debug: msg: - - "Worker-only mode configured successfully" - - "Control-plane nodes with worker label removed: {{ control_plane_worker_nodes }}" - - "mastersSchedulable: false" - - "Control-plane nodes drained: {{ worker_drain_control_plane | default(true) | bool }}" + - "Worker-only mode configured successfully" + - "Control-plane nodes with worker label removed: {{ control_plane_worker_nodes }}" + - "mastersSchedulable: false" + - "Control-plane nodes drained: {{ worker_drain_control_plane | default(true) | bool }}" From cbc596ff975e9b52b35c13c738526df5479ef112 Mon Sep 17 00:00:00 2001 From: Wolfgang Kulhanek Date: Thu, 26 Feb 2026 16:34:20 +0100 Subject: [PATCH 3/3] Fix indentation --- roles/scale_ocp_workers/tasks/configure_worker_only.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/scale_ocp_workers/tasks/configure_worker_only.yml b/roles/scale_ocp_workers/tasks/configure_worker_only.yml index 1723d2a..5904b76 100644 --- a/roles/scale_ocp_workers/tasks/configure_worker_only.yml +++ b/roles/scale_ocp_workers/tasks/configure_worker_only.yml @@ -8,7 +8,7 @@ api_version: v1 kind: Node label_selectors: - - "node-role.kubernetes.io/control-plane" + - "node-role.kubernetes.io/control-plane" register: r_control_plane_nodes - name: Get master-labeled nodes @@ -16,7 +16,7 @@ api_version: v1 kind: Node label_selectors: - - "node-role.kubernetes.io/master" + - "node-role.kubernetes.io/master" register: r_master_nodes - name: Build list of control-plane nodes with worker label