diff --git a/inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml b/inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml
index ee26992b6e65d1d8b3884dd10f84ea32df79b51d..af17a2ccc1075c1f17f1cfb38ed6ea8b6bbcb5a3 100644
--- a/inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml
+++ b/inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml
@@ -339,3 +339,9 @@ event_ttl_duration: "1h0m0s"
 auto_renew_certificates: false
 # First Monday of each month
 # auto_renew_certificates_systemd_calendar: "Mon *-*-1,2,3,4,5,6,7 03:{{ groups['kube_control_plane'].index(inventory_hostname) }}0:00"
+
+# kubeadm patches path
+kubeadm_patches:
+  enabled: false
+  source_dir: "{{ inventory_dir }}/patches"
+  dest_dir: "{{ kube_config_dir }}/patches"
diff --git a/inventory/sample/patches/kube-controller-manager+merge.yaml b/inventory/sample/patches/kube-controller-manager+merge.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a8aa5a7856b710c10139ae9c3824c7c341e24e09
--- /dev/null
+++ b/inventory/sample/patches/kube-controller-manager+merge.yaml
@@ -0,0 +1,8 @@
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  name: kube-controller-manager
+  annotations:
+    prometheus.io/scrape: 'true'
+    prometheus.io/port: '10257'
\ No newline at end of file
diff --git a/inventory/sample/patches/kube-scheduler+merge.yaml b/inventory/sample/patches/kube-scheduler+merge.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0bb39509d51f4e50030ff032586ce614090f90ee
--- /dev/null
+++ b/inventory/sample/patches/kube-scheduler+merge.yaml
@@ -0,0 +1,8 @@
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  name: kube-scheduler
+  annotations:
+    prometheus.io/scrape: 'true'
+    prometheus.io/port: '10259'
\ No newline at end of file
diff --git a/roles/kubernetes/control-plane/defaults/main/main.yml b/roles/kubernetes/control-plane/defaults/main/main.yml
index 32cabb91e976f337a3b74e1daad9f4ae14533c37..c26d1d639664c17dc27cfc7dfe9b11ab60e77739 100644
--- a/roles/kubernetes/control-plane/defaults/main/main.yml
+++ b/roles/kubernetes/control-plane/defaults/main/main.yml
@@ -228,3 +228,9 @@ auto_renew_certificates_systemd_calendar: "{{ 'Mon *-*-1,2,3,4,5,6,7 03:' ~
 # If we have requirement like without renewing certs upgrade the cluster,
 # we can opt out from the default behavior by setting kubeadm_upgrade_auto_cert_renewal to false
 kubeadm_upgrade_auto_cert_renewal: true
+
+# kubeadm patches path
+kubeadm_patches:
+  enabled: true
+  source_dir: "{{ inventory_dir }}/patches"
+  dest_dir: "{{ kube_config_dir }}/patches"
\ No newline at end of file
diff --git a/roles/kubernetes/control-plane/tasks/kubeadm-setup.yml b/roles/kubernetes/control-plane/tasks/kubeadm-setup.yml
index dc13520606d461ccabb4c0b44d418de1fd23619d..5f8c784453047cb741b3d7d5a458f708f1c2e3fb 100644
--- a/roles/kubernetes/control-plane/tasks/kubeadm-setup.yml
+++ b/roles/kubernetes/control-plane/tasks/kubeadm-setup.yml
@@ -150,6 +150,21 @@
     - apiserver_sans_check.changed
     - not kube_external_ca_mode
 
+- name: kubeadm | Create directory to store kubeadm patches
+  file:
+    path: "{{ kubeadm_patches.dest_dir }}"
+    state: directory
+    mode: 0640
+  when: kubeadm_patches is defined and kubeadm_patches.enabled
+
+- name: kubeadm | Copy kubeadm patches from inventory files
+  copy:
+    src: "{{ kubeadm_patches.source_dir }}/"
+    dest: "{{ kubeadm_patches.dest_dir }}"
+    owner: "root"
+    mode: 0644
+  when: kubeadm_patches is defined and kubeadm_patches.enabled
+
 - name: kubeadm | Initialize first master
   command: >-
     timeout -k 300s 300s
diff --git a/roles/kubernetes/control-plane/templates/kubeadm-config.v1beta3.yaml.j2 b/roles/kubernetes/control-plane/templates/kubeadm-config.v1beta3.yaml.j2
index d44a248494d0f45a7a0dbdf243c30085aeb1d7c7..9f4168cf64b00bc410971b424ccded15e794d16b 100644
--- a/roles/kubernetes/control-plane/templates/kubeadm-config.v1beta3.yaml.j2
+++ b/roles/kubernetes/control-plane/templates/kubeadm-config.v1beta3.yaml.j2
@@ -28,6 +28,10 @@ nodeRegistration:
   kubeletExtraArgs:
     cloud-provider: external
 {% endif %}
+{% if kubeadm_patches is defined and kubeadm_patches.enabled %}
+patches:
+  directory: {{ kubeadm_patches.dest_dir }}
+{% endif %}
 ---
 apiVersion: kubeadm.k8s.io/v1beta3
 kind: ClusterConfiguration
diff --git a/roles/kubernetes/control-plane/templates/kubeadm-controlplane.v1beta3.yaml.j2 b/roles/kubernetes/control-plane/templates/kubeadm-controlplane.v1beta3.yaml.j2
index 7bf876c527870c6b46ceb3e4538767382d54f038..b41b2dbc765035ebd833a6a0be146fd600a7021d 100644
--- a/roles/kubernetes/control-plane/templates/kubeadm-controlplane.v1beta3.yaml.j2
+++ b/roles/kubernetes/control-plane/templates/kubeadm-controlplane.v1beta3.yaml.j2
@@ -26,3 +26,7 @@ nodeRegistration:
 {% else %}
   taints: []
 {% endif %}
+{% if kubeadm_patches is defined and kubeadm_patches.enabled %}
+patches:
+  directory: {{ kubeadm_patches.dest_dir }}
+{% endif %}
\ No newline at end of file
diff --git a/roles/kubernetes/kubeadm/defaults/main.yml b/roles/kubernetes/kubeadm/defaults/main.yml
index 0449b8ae740de4d9f662b489e8154143fa9860fe..1277684aef336e48c18e18cd4c933687cb868249 100644
--- a/roles/kubernetes/kubeadm/defaults/main.yml
+++ b/roles/kubernetes/kubeadm/defaults/main.yml
@@ -10,3 +10,9 @@ kube_override_hostname: >-
   {%- else -%}
   {{ inventory_hostname }}
   {%- endif -%}
+
+# kubeadm patches path
+kubeadm_patches:
+  enabled: true
+  source_dir: "{{ inventory_dir }}/patches"
+  dest_dir: "{{ kube_config_dir }}/patches"
\ No newline at end of file
diff --git a/roles/kubernetes/kubeadm/tasks/main.yml b/roles/kubernetes/kubeadm/tasks/main.yml
index 13497ffbbd3f863d742b5b1d5094f412dedd614a..a3cc8620f6132de44826489a31e889fe4220b457 100644
--- a/roles/kubernetes/kubeadm/tasks/main.yml
+++ b/roles/kubernetes/kubeadm/tasks/main.yml
@@ -52,7 +52,7 @@
     kubeadm_token: "{{ temp_token.stdout }}"
   when: kubeadm_token is not defined
 
-- name: Set kubeadm api version to v1beta2
+- name: Set kubeadm api version to v1beta3
   set_fact:
     kubeadmConfig_api_version: v1beta3
 
@@ -64,6 +64,21 @@
     mode: 0640
   when: not is_kube_master
 
+- name: kubeadm | Create directory to store kubeadm patches
+  file:
+    path: "{{ kubeadm_patches.dest_dir }}"
+    state: directory
+    mode: 0640
+  when: kubeadm_patches is defined and kubeadm_patches.enabled
+
+- name: kubeadm | Copy kubeadm patches from inventory files
+  copy:
+    src: "{{ kubeadm_patches.source_dir }}/"
+    dest: "{{ kubeadm_patches.dest_dir }}"
+    owner: "root"
+    mode: 0644
+  when: kubeadm_patches is defined and kubeadm_patches.enabled
+
 - name: Join to cluster if needed
   environment:
     PATH: "{{ bin_dir }}:{{ ansible_env.PATH }}:/sbin"
diff --git a/roles/kubernetes/kubeadm/templates/kubeadm-client.conf.v1beta3.j2 b/roles/kubernetes/kubeadm/templates/kubeadm-client.conf.v1beta3.j2
index d35409b13ada0953e81eb801bea914a6ecaccdde..64c3db99addcca083e020f95b7debe8cb479b295 100644
--- a/roles/kubernetes/kubeadm/templates/kubeadm-client.conf.v1beta3.j2
+++ b/roles/kubernetes/kubeadm/templates/kubeadm-client.conf.v1beta3.j2
@@ -26,3 +26,7 @@ nodeRegistration:
   - effect: NoSchedule
     key: node-role.kubernetes.io/calico-rr
 {% endif %}
+{% if kubeadm_patches is defined and kubeadm_patches.enabled %}
+patches:
+  directory: {{ kubeadm_patches.dest_dir }}
+{% endif %}