Stricter kubeadm validation (config and runtime checks) (#11710)

* kubeadm: do not ignore preflight errors blindly

The "ignoring all errors" seems to date back to the inception of the
kubeadm support (it was --skip-preflight-check before).

This can mask real errors and prevent users from seeing them.

Do not ignore any errors by default and make the set of ignored errors
configurable.

* download/kubeadm: remove redundant task

The mode is already set by the previous `copy` task.

* Validate kubeadm configs

This should help to fail early when we have invalid kubeadm configs (from
a kubespray bug or a misconfiguration).

* kubeadm-upgrade: remove unnecessary bool cast

* Convert kubeadm join discovery timeout to v1beta4 config

* CI: Ignore kubeadm:Mem errors on some setup.
pull/11714/head
Max Gautier 2024-11-15 07:34:52 +01:00 committed by GitHub
parent 05e2b47db6
commit 68718dcb6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 49 additions and 53 deletions

View File

@ -7,14 +7,6 @@
- not skip_downloads | default(false) - not skip_downloads | default(false)
- downloads.kubeadm.enabled - downloads.kubeadm.enabled
- name: Prep_kubeadm_images | Create kubeadm config
template:
src: "kubeadm-images.yaml.j2"
dest: "{{ kube_config_dir }}/kubeadm-images.yaml"
mode: "0644"
when:
- not skip_kubeadm_images | default(false)
- name: Prep_kubeadm_images | Copy kubeadm binary from download dir to system path - name: Prep_kubeadm_images | Copy kubeadm binary from download dir to system path
copy: copy:
src: "{{ downloads.kubeadm.dest }}" src: "{{ downloads.kubeadm.dest }}"
@ -22,11 +14,14 @@
mode: "0755" mode: "0755"
remote_src: true remote_src: true
- name: Prep_kubeadm_images | Set kubeadm binary permissions - name: Prep_kubeadm_images | Create kubeadm config
file: template:
path: "{{ bin_dir }}/kubeadm" src: "kubeadm-images.yaml.j2"
mode: "0755" dest: "{{ kube_config_dir }}/kubeadm-images.yaml"
state: file mode: "0644"
validate: "{{ bin_dir }}/kubeadm config validate --config %s"
when:
- not skip_kubeadm_images | default(false)
- name: Prep_kubeadm_images | Generate list of required images - name: Prep_kubeadm_images | Generate list of required images
shell: "set -o pipefail && {{ bin_dir }}/kubeadm config images list --config={{ kube_config_dir }}/kubeadm-images.yaml | grep -Ev 'coredns|pause'" shell: "set -o pipefail && {{ bin_dir }}/kubeadm config images list --config={{ kube_config_dir }}/kubeadm-images.yaml | grep -Ev 'coredns|pause'"

View File

@ -36,6 +36,7 @@
dest: "{{ kube_config_dir }}/kubeadm-controlplane.yaml" dest: "{{ kube_config_dir }}/kubeadm-controlplane.yaml"
mode: "0640" mode: "0640"
backup: true backup: true
validate: "{{ bin_dir }}/kubeadm config validate --config %s"
when: when:
- inventory_hostname != first_kube_control_plane - inventory_hostname != first_kube_control_plane
- not kubeadm_already_run.stat.exists - not kubeadm_already_run.stat.exists
@ -87,7 +88,7 @@
command: >- command: >-
{{ bin_dir }}/kubeadm join {{ bin_dir }}/kubeadm join
--config {{ kube_config_dir }}/kubeadm-controlplane.yaml --config {{ kube_config_dir }}/kubeadm-controlplane.yaml
--ignore-preflight-errors=all --ignore-preflight-errors={{ kubeadm_ignore_preflight_errors | join(',') }}
--skip-phases={{ kubeadm_join_phases_skip | join(',') }} --skip-phases={{ kubeadm_join_phases_skip | join(',') }}
environment: environment:
PATH: "{{ bin_dir }}:{{ ansible_env.PATH }}" PATH: "{{ bin_dir }}:{{ ansible_env.PATH }}"

View File

@ -93,6 +93,7 @@
src: "kubeadm-config.{{ kubeadm_config_api_version }}.yaml.j2" src: "kubeadm-config.{{ kubeadm_config_api_version }}.yaml.j2"
dest: "{{ kube_config_dir }}/kubeadm-config.yaml" dest: "{{ kube_config_dir }}/kubeadm-config.yaml"
mode: "0640" mode: "0640"
validate: "{{ bin_dir }}/kubeadm config validate --config %s"
- name: Kubeadm | Create directory to store admission control configurations - name: Kubeadm | Create directory to store admission control configurations
file: file:
@ -168,7 +169,7 @@
timeout -k {{ kubeadm_init_timeout }} {{ kubeadm_init_timeout }} timeout -k {{ kubeadm_init_timeout }} {{ kubeadm_init_timeout }}
{{ bin_dir }}/kubeadm init {{ bin_dir }}/kubeadm init
--config={{ kube_config_dir }}/kubeadm-config.yaml --config={{ kube_config_dir }}/kubeadm-config.yaml
--ignore-preflight-errors=all --ignore-preflight-errors={{ kubeadm_ignore_preflight_errors | join(',') }}
--skip-phases={{ kubeadm_init_phases_skip | join(',') }} --skip-phases={{ kubeadm_init_phases_skip | join(',') }}
{{ kube_external_ca_mode | ternary('', '--upload-certs') }} {{ kube_external_ca_mode | ternary('', '--upload-certs') }}
register: kubeadm_init register: kubeadm_init

View File

@ -15,9 +15,9 @@
{{ bin_dir }}/kubeadm {{ bin_dir }}/kubeadm
upgrade apply -y {{ kube_version }} upgrade apply -y {{ kube_version }}
--certificate-renewal={{ kubeadm_upgrade_auto_cert_renewal }} --certificate-renewal={{ kubeadm_upgrade_auto_cert_renewal }}
--ignore-preflight-errors=all --ignore-preflight-errors={{ kubeadm_ignore_preflight_errors | join(',') }}
--allow-experimental-upgrades --allow-experimental-upgrades
--etcd-upgrade={{ (etcd_deployment_type == "kubeadm") | bool | lower }} --etcd-upgrade={{ (etcd_deployment_type == "kubeadm") | lower }}
{% if kubeadm_patches | length > 0 %}--patches={{ kubeadm_patches_dir }}{% endif %} {% if kubeadm_patches | length > 0 %}--patches={{ kubeadm_patches_dir }}{% endif %}
--force --force
register: kubeadm_upgrade register: kubeadm_upgrade
@ -36,9 +36,9 @@
{{ bin_dir }}/kubeadm {{ bin_dir }}/kubeadm
upgrade apply -y {{ kube_version }} upgrade apply -y {{ kube_version }}
--certificate-renewal={{ kubeadm_upgrade_auto_cert_renewal }} --certificate-renewal={{ kubeadm_upgrade_auto_cert_renewal }}
--ignore-preflight-errors=all --ignore-preflight-errors={{ kubeadm_ignore_preflight_errors | join(',') }}
--allow-experimental-upgrades --allow-experimental-upgrades
--etcd-upgrade={{ (etcd_deployment_type == "kubeadm") | bool | lower }} --etcd-upgrade={{ (etcd_deployment_type == "kubeadm") | lower }}
{% if kubeadm_patches | length > 0 %}--patches={{ kubeadm_patches_dir }}{% endif %} {% if kubeadm_patches | length > 0 %}--patches={{ kubeadm_patches_dir }}{% endif %}
--force --force
register: kubeadm_upgrade register: kubeadm_upgrade

View File

@ -14,8 +14,14 @@ discovery:
token: {{ kubeadm_token }} token: {{ kubeadm_token }}
unsafeSkipCAVerification: true unsafeSkipCAVerification: true
{% endif %} {% endif %}
timeout: {{ discovery_timeout }}
tlsBootstrapToken: {{ kubeadm_token }} tlsBootstrapToken: {{ kubeadm_token }}
{# TODO: drop the if when we drop support for k8s<1.31 #}
{% if kubeadm_config_api_version == 'v1beta3' %}
timeout: {{ discovery_timeout }}
{% else %}
timeouts:
discovery: {{ discovery_timeout }}
{% endif %}
controlPlane: controlPlane:
localAPIEndpoint: localAPIEndpoint:
advertiseAddress: {{ kube_apiserver_address }} advertiseAddress: {{ kube_apiserver_address }}

View File

@ -9,6 +9,7 @@
src: "kubeadm-client.conf.j2" src: "kubeadm-client.conf.j2"
dest: "{{ kube_config_dir }}/kubeadm-cert-controlplane.conf" dest: "{{ kube_config_dir }}/kubeadm-cert-controlplane.conf"
mode: "0640" mode: "0640"
validate: "{{ bin_dir }}/kubeadm config validate --config %s"
vars: vars:
kubeadm_cert_controlplane: true kubeadm_cert_controlplane: true

View File

@ -77,6 +77,7 @@
dest: "{{ kube_config_dir }}/kubeadm-client.conf" dest: "{{ kube_config_dir }}/kubeadm-client.conf"
backup: true backup: true
mode: "0640" mode: "0640"
validate: "{{ bin_dir }}/kubeadm config validate --config %s"
when: ('kube_control_plane' not in group_names) when: ('kube_control_plane' not in group_names)
- name: Join to cluster if needed - name: Join to cluster if needed
@ -85,38 +86,16 @@
when: when:
- ('kube_control_plane' not in group_names) - ('kube_control_plane' not in group_names)
- not kubelet_conf.stat.exists - not kubelet_conf.stat.exists
block: vars:
ignored:
- name: Join to cluster - DirAvailable--etc-kubernetes-manifests
- "{{ kubeadm_ignore_preflight_errors }}"
command: >- command: >-
timeout -k {{ kubeadm_join_timeout }} {{ kubeadm_join_timeout }} timeout -k {{ kubeadm_join_timeout }} {{ kubeadm_join_timeout }}
{{ bin_dir }}/kubeadm join {{ bin_dir }}/kubeadm join
--config {{ kube_config_dir }}/kubeadm-client.conf --config {{ kube_config_dir }}/kubeadm-client.conf
--ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests --ignore-preflight-errors={{ ignored | flatten | join(',') }}
--skip-phases={{ kubeadm_join_phases_skip | join(',') }} --skip-phases={{ kubeadm_join_phases_skip | join(',') }}
register: kubeadm_join
changed_when: kubeadm_join is success
rescue:
- name: Join to cluster with ignores
command: >-
timeout -k {{ kubeadm_join_timeout }} {{ kubeadm_join_timeout }}
{{ bin_dir }}/kubeadm join
--config {{ kube_config_dir }}/kubeadm-client.conf
--ignore-preflight-errors=all
--skip-phases={{ kubeadm_join_phases_skip | join(',') }}
register: kubeadm_join
changed_when: kubeadm_join is success
always:
- name: Display kubeadm join stderr if any
when: kubeadm_join is failed
debug:
msg: |
Joined with warnings
{{ kubeadm_join.stderr_lines }}
- name: Update server field in kubelet kubeconfig - name: Update server field in kubelet kubeconfig
lineinfile: lineinfile:

View File

@ -20,8 +20,14 @@ discovery:
unsafeSkipCAVerification: true unsafeSkipCAVerification: true
{% endif %} {% endif %}
{% endif %} {% endif %}
timeout: {{ discovery_timeout }}
tlsBootstrapToken: {{ kubeadm_token }} tlsBootstrapToken: {{ kubeadm_token }}
{# TODO: drop the if when we drop support for k8s<1.31 #}
{% if kubeadm_config_api_version == 'v1beta3' %}
timeout: {{ discovery_timeout }}
{% else %}
timeouts:
discovery: {{ discovery_timeout }}
{% endif %}
caCertPath: {{ kube_cert_dir }}/ca.crt caCertPath: {{ kube_cert_dir }}/ca.crt
{% if kubeadm_cert_controlplane is defined and kubeadm_cert_controlplane %} {% if kubeadm_cert_controlplane is defined and kubeadm_cert_controlplane %}
controlPlane: controlPlane:

View File

@ -18,3 +18,6 @@ kubeadm_patches: []
# example.com/prod_level: "{{ prod_level }}" # example.com/prod_level: "{{ prod_level }}"
# - ... # - ...
# Patches are applied in the order they are specified. # Patches are applied in the order they are specified.
# List of errors to ignore during kubeadm preflight checks
kubeadm_ignore_preflight_errors: []

View File

@ -6,6 +6,8 @@ vm_memory: 1600
# Kubespray settings # Kubespray settings
auto_renew_certificates: true auto_renew_certificates: true
kubeadm_ignore_preflight_errors:
- Mem
# Currently ipvs not available on KVM: https://packages.ubuntu.com/search?suite=focal&arch=amd64&mode=exactfilename&searchon=contents&keywords=ip_vs_sh.ko # Currently ipvs not available on KVM: https://packages.ubuntu.com/search?suite=focal&arch=amd64&mode=exactfilename&searchon=contents&keywords=ip_vs_sh.ko
kube_proxy_mode: iptables kube_proxy_mode: iptables

View File

@ -6,6 +6,8 @@ vm_memory: 1600
# Kubespray settings # Kubespray settings
auto_renew_certificates: true auto_renew_certificates: true
kubeadm_ignore_preflight_errors:
- Mem
# Currently ipvs not available on KVM: https://packages.ubuntu.com/search?suite=noble&arch=amd64&mode=exactfilename&searchon=contents&keywords=ip_vs_sh.ko # Currently ipvs not available on KVM: https://packages.ubuntu.com/search?suite=noble&arch=amd64&mode=exactfilename&searchon=contents&keywords=ip_vs_sh.ko
kube_proxy_mode: iptables kube_proxy_mode: iptables