diff --git a/.gitlab-ci/kubevirt.yml b/.gitlab-ci/kubevirt.yml index f04b9e198..a7ccd9bdb 100644 --- a/.gitlab-ci/kubevirt.yml +++ b/.gitlab-ci/kubevirt.yml @@ -45,6 +45,7 @@ pr: - fedora43-kube-router - opensuse-leap16-calico - rockylinux10-cilium + - rockylinux8-calico - rockylinux9-cilium - ubuntu22-calico-all-in-one - ubuntu22-calico-all-in-one-upgrade @@ -114,13 +115,14 @@ pr_full: - ubuntu24-flannel-ha - ubuntu24-flannel-ha-once -# Need an update of the container image to use schema v2 -# update: quay.io/kubespray/vm-amazon-linux-2:latest +# Experimental OS coverage and images needing maintenance. manual: extends: pr_full parallel: matrix: - TESTCASE: + - almalinux8-calico + # Needs a schema v2 update to quay.io/kubespray/vm-amazon-linux-2:latest. - amazon-linux-2-all-in-one rules: - when: manual diff --git a/docs/ansible/ansible.md b/docs/ansible/ansible.md index 46ba7748c..416f72fb2 100644 --- a/docs/ansible/ansible.md +++ b/docs/ansible/ansible.md @@ -34,6 +34,10 @@ Based on the table below and the available python version for your ansible host |----------------------|-----------------------------|----------------------------| | >=2.21.0, <2.22.0 | 3.12-3.14 | 3.9-3.14 | +### Target Python Bootstrap + +`bootstrap_os_install_python` defaults to `true` and controls Python installation for Debian/Ubuntu, Fedora, Fedora CoreOS, Flatcar, and distributions using the shared `centos.yml` bootstrap. Set it to `false` when a compatible interpreter is already provisioned, selecting it with `ansible_python_interpreter` if needed. This also skips Fedora CoreOS bootstrap preparation and reboot, but not general system package management. The shared CentOS bootstrap installs Python 3.12 using `yum` when the selected interpreter is missing or older than 3.9; configured repositories must provide that package. Other bootstrap paths retain their existing checks and package choices. + ## Customize Ansible vars Kubespray expects users to use one of the following variables sources for settings and customization: diff --git a/docs/developers/ci.md b/docs/developers/ci.md index c60997299..a5ca66ba9 100644 --- a/docs/developers/ci.md +++ b/docs/developers/ci.md @@ -6,6 +6,7 @@ To generate this Matrix run `./tests/scripts/md-table/main.py` | OS / CNI | calico | cilium | custom_cni | flannel | kube-ovn | kube-router | |---| --- | --- | --- | --- | --- | --- | +almalinux8 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | almalinux9 | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :x: | amazon | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | debian12 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | @@ -17,6 +18,7 @@ openeuler24 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | opensuse | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | opensusemicroos | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | rockylinux10 | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | +rockylinux8 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | rockylinux9 | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | ubuntu22 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | ubuntu24 | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | @@ -26,6 +28,7 @@ ubuntu26 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | | OS / CNI | calico | cilium | custom_cni | flannel | kube-ovn | kube-router | |---| --- | --- | --- | --- | --- | --- | +almalinux8 | :x: | :x: | :x: | :x: | :x: | :x: | almalinux9 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | amazon | :x: | :x: | :x: | :x: | :x: | :x: | debian12 | :x: | :x: | :x: | :x: | :x: | :x: | @@ -37,6 +40,7 @@ openeuler24 | :x: | :x: | :x: | :x: | :x: | :x: | opensuse | :x: | :x: | :x: | :x: | :x: | :x: | opensusemicroos | :x: | :x: | :x: | :x: | :x: | :x: | rockylinux10 | :x: | :x: | :x: | :x: | :x: | :x: | +rockylinux8 | :x: | :x: | :x: | :x: | :x: | :x: | rockylinux9 | :x: | :x: | :x: | :x: | :x: | :x: | ubuntu22 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | ubuntu24 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | @@ -46,6 +50,7 @@ ubuntu26 | :x: | :x: | :x: | :x: | :x: | :x: | | OS / CNI | calico | cilium | custom_cni | flannel | kube-ovn | kube-router | |---| --- | --- | --- | --- | --- | --- | +almalinux8 | :x: | :x: | :x: | :x: | :x: | :x: | almalinux9 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | amazon | :x: | :x: | :x: | :x: | :x: | :x: | debian12 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | @@ -57,6 +62,7 @@ openeuler24 | :x: | :x: | :x: | :x: | :x: | :x: | opensuse | :x: | :x: | :x: | :x: | :x: | :x: | opensusemicroos | :x: | :x: | :x: | :x: | :x: | :x: | rockylinux10 | :x: | :x: | :x: | :x: | :x: | :x: | +rockylinux8 | :x: | :x: | :x: | :x: | :x: | :x: | rockylinux9 | :x: | :x: | :x: | :x: | :x: | :x: | ubuntu22 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | ubuntu24 | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | diff --git a/docs/operating_systems/rhel.md b/docs/operating_systems/rhel.md index 64154639a..1d3716426 100644 --- a/docs/operating_systems/rhel.md +++ b/docs/operating_systems/rhel.md @@ -31,6 +31,26 @@ rh_subscription_sla: "Self-Support" If the RHEL hosts are already registered to a valid Red Hat support subscription via an alternative configuration management approach prior to the deployment of Kubespray, the successful RHEL `subscription-manager` status check will simply result in the RHEL subscription registration tasks being skipped. +## RHEL 8 Family + +RHEL 8, AlmaLinux 8, and Rocky Linux 8 are not end-of-life, but they are no longer in full or active support. RHEL 8 remains in maintenance support, while AlmaLinux 8 and Rocky Linux 8 receive security maintenance, through May 31, 2029. Prefer a newer major release for new deployments; this guidance is intended primarily for existing RHEL 8 family environments. See the lifecycle documentation for [RHEL](https://access.redhat.com/support/policy/updates/errata), [AlmaLinux](https://wiki.almalinux.org/release-notes/), and [Rocky Linux](https://wiki.rockylinux.org/rocky/version/). + +With `bootstrap_os_install_python: true` (the default), the shared `centos.yml` bootstrap checks the selected interpreter before gathering facts, without restricting the distribution or OS version. If Python is missing or older than 3.9, it installs Python 3.12 using `yum`, preserving system Python for DNF. This requires repositories providing `python3.12`, available in AlmaLinux 8.10 and Rocky Linux 8.10. RHEL uses a separate bootstrap path and is unchanged. + +If the inventory pins an older interpreter, set: + +```yaml +ansible_python_interpreter: /usr/bin/python3.12 +``` + +The default containerd binaries require a newer glibc than EL8 provides. Use the static binaries on these systems: + +```yaml +containerd_static_binary: true +``` + +Run bootstrap before `--check` on fresh hosts. Experimental CI includes `rockylinux8-calico` in the regular PR matrix and `almalinux8-calico` as a manual job. Both use static containerd binaries. SELinux, runtime, and kernel/cgroup compatibility still need validation; the kernel check and cgroup v1 exceptions are not production recommendations. + ## Rocky Linux 10 (Experimental in Kubespray CI) diff --git a/roles/bootstrap_os/defaults/main.yml b/roles/bootstrap_os/defaults/main.yml index 18a7fa4c0..338a9c0e8 100644 --- a/roles/bootstrap_os/defaults/main.yml +++ b/roles/bootstrap_os/defaults/main.yml @@ -43,6 +43,9 @@ fedora_coreos_packages: - containernetworking-plugins # required by crio ## General +# Install Python through the distribution-specific bootstrap tasks +bootstrap_os_install_python: true + # Set the hostname to inventory_hostname override_system_hostname: true diff --git a/roles/bootstrap_os/tasks/centos.yml b/roles/bootstrap_os/tasks/centos.yml index 41c260a35..66c7db3c2 100644 --- a/roles/bootstrap_os/tasks/centos.yml +++ b/roles/bootstrap_os/tasks/centos.yml @@ -1,4 +1,42 @@ --- +- name: Bootstrap Python + when: bootstrap_os_install_python + block: + - name: Check if Python bootstrap is needed + vars: + python_interpreter: "{{ lookup('config', 'INTERPRETER_PYTHON') | trim }}" + python_candidates: >- + {{ lookup('config', 'INTERPRETER_PYTHON_FALLBACK') + if python_interpreter in ['', 'auto', 'auto_silent'] else [python_interpreter] }} + raw: | + for python in {{ python_candidates | map('quote') | join(' ') }}; do + if command -v "$python" >/dev/null 2>&1; then + "$python" -c 'import sys; sys.exit(sys.version_info[:2] < (3, 9))' + exit $? + fi + done + exit 1 + register: need_bootstrap + changed_when: false + failed_when: need_bootstrap.rc not in [0, 1] + check_mode: false + + # Keep platform-python for the ansible-core DNF helper. + - name: Install Python 3.12 + raw: >- + yum --assumeyes + {% if not skip_http_proxy_on_os_packages and http_proxy is defined %} + --setopt={{ ('proxy=' ~ http_proxy) | quote }} + {% endif %} + install python3.12 + become: true + register: bootstrap_python + until: bootstrap_python is succeeded + retries: "{{ pkg_install_retries }}" + delay: "{{ retry_stagger | random + 3 }}" + timeout: "{{ pkg_install_timeout }}" + when: need_bootstrap.rc != 0 + - name: Gather host facts to get ansible_distribution_version ansible_distribution_major_version setup: gather_subset: '!all' @@ -61,8 +99,6 @@ - (ansible_facts['distribution_version'] | float) >= 7.6 - (ansible_facts['distribution_version'] | float) < 9 -# CentOS ships with python installed - - name: Check presence of fastestmirror.conf stat: path: /etc/yum/pluginconf.d/fastestmirror.conf diff --git a/roles/bootstrap_os/tasks/debian.yml b/roles/bootstrap_os/tasks/debian.yml index acfc0483b..2ef3e1083 100644 --- a/roles/bootstrap_os/tasks/debian.yml +++ b/roles/bootstrap_os/tasks/debian.yml @@ -49,4 +49,5 @@ DEBIAN_FRONTEND=noninteractive apt-get install -y python3-minimal become: true when: + - bootstrap_os_install_python - need_bootstrap.rc != 0 diff --git a/roles/bootstrap_os/tasks/fedora-coreos.yml b/roles/bootstrap_os/tasks/fedora-coreos.yml index 3062a5a88..ae288bbee 100644 --- a/roles/bootstrap_os/tasks/fedora-coreos.yml +++ b/roles/bootstrap_os/tasks/fedora-coreos.yml @@ -12,24 +12,24 @@ raw: "podman network rm podman" become: true ignore_errors: true # noqa ignore-errors - when: need_bootstrap.rc != 0 + when: bootstrap_os_install_python and need_bootstrap.rc != 0 - name: Clean up possible pending packages on fedora coreos raw: "export http_proxy={{ http_proxy | default('') }};rpm-ostree cleanup -p }}" become: true - when: need_bootstrap.rc != 0 + when: bootstrap_os_install_python and need_bootstrap.rc != 0 - name: Install required packages on fedora coreos raw: "export http_proxy={{ http_proxy | default('') }};rpm-ostree install --allow-inactive {{ fedora_coreos_packages | join(' ') }}" become: true - when: need_bootstrap.rc != 0 + when: bootstrap_os_install_python and need_bootstrap.rc != 0 - name: Reboot immediately for updated ostree raw: "nohup bash -c 'sleep 5s && shutdown -r now'" become: true ignore_errors: true # noqa ignore-errors ignore_unreachable: true - when: need_bootstrap.rc != 0 + when: bootstrap_os_install_python and need_bootstrap.rc != 0 - name: Wait for the reboot to complete wait_for_connection: @@ -37,4 +37,4 @@ connect_timeout: 20 delay: 5 sleep: 5 - when: need_bootstrap.rc != 0 + when: bootstrap_os_install_python and need_bootstrap.rc != 0 diff --git a/roles/bootstrap_os/tasks/fedora.yml b/roles/bootstrap_os/tasks/fedora.yml index d4a43c314..428b49617 100644 --- a/roles/bootstrap_os/tasks/fedora.yml +++ b/roles/bootstrap_os/tasks/fedora.yml @@ -27,4 +27,5 @@ raw: "dnf install --assumeyes python3 python3-dnf libselinux-python3" become: true when: + - bootstrap_os_install_python - need_bootstrap.rc != 0 diff --git a/roles/bootstrap_os/tasks/flatcar.yml b/roles/bootstrap_os/tasks/flatcar.yml index d73e0fc0e..36e619322 100644 --- a/roles/bootstrap_os/tasks/flatcar.yml +++ b/roles/bootstrap_os/tasks/flatcar.yml @@ -14,6 +14,7 @@ become: true environment: "{{ proxy_env }}" when: + - bootstrap_os_install_python - need_bootstrap.rc != 0 # Workaround ansible https://github.com/ansible/ansible/pull/82821 diff --git a/roles/kubernetes/preinstall/tasks/0079-selinux.yml b/roles/kubernetes/preinstall/tasks/0079-selinux.yml new file mode 100644 index 000000000..529efdf77 --- /dev/null +++ b/roles/kubernetes/preinstall/tasks/0079-selinux.yml @@ -0,0 +1,60 @@ +--- +# The ansible.posix.selinux module needs the libselinux Python bindings, which +# some distributions only package for their system Python. When Kubespray runs +# with another interpreter (for example the Python 3.12 bootstrapped on EL8) +# the bindings are missing, so fall back to editing the configuration file. +- name: Check for the libselinux Python bindings + command: "{{ ansible_facts['python']['executable'] }} -c 'import selinux'" + register: selinux_bindings + changed_when: false + failed_when: false + check_mode: false + +- name: Set selinux policy + ansible.posix.selinux: + policy: targeted + state: "{{ selinux_state }}" + when: selinux_bindings.rc == 0 + +- name: Set selinux policy without the libselinux Python bindings + when: selinux_bindings.rc != 0 + block: + - name: Gather selinux facts + setup: + gather_subset: selinux + + - name: Set selinux policy type + lineinfile: + path: /etc/selinux/config + regexp: '^SELINUXTYPE=' + line: "SELINUXTYPE=targeted" + mode: "0644" + backup: "{{ leave_etc_backup_files }}" + when: selinux_state != 'disabled' + + - name: Set selinux state + lineinfile: + path: /etc/selinux/config + regexp: '^SELINUX=' + line: "SELINUX={{ selinux_state }}" + mode: "0644" + backup: "{{ leave_etc_backup_files }}" + + # Disabling SELinux requires a reboot; use permissive mode until then. + - name: Update selinux runtime state + vars: + selinux_runtime_state: "{{ (selinux_state == 'enforcing') | ternary('enforcing', 'permissive') }}" + when: + - ansible_facts['selinux']['status'] == 'enabled' + - ansible_facts['selinux']['mode'] != selinux_runtime_state + block: + - name: Apply selinux state at runtime + command: setenforce {{ (selinux_runtime_state == 'enforcing') | ternary('1', '0') }} + changed_when: true + when: not ansible_check_mode + + - name: Report selinux runtime change in check mode + debug: + msg: "SELinux runtime state would change to {{ selinux_runtime_state }}" + changed_when: true + when: ansible_check_mode diff --git a/roles/kubernetes/preinstall/tasks/0080-system-configurations.yml b/roles/kubernetes/preinstall/tasks/0080-system-configurations.yml index 9cb2c0456..d4687124f 100644 --- a/roles/kubernetes/preinstall/tasks/0080-system-configurations.yml +++ b/roles/kubernetes/preinstall/tasks/0080-system-configurations.yml @@ -12,9 +12,9 @@ register: slc - name: Set selinux policy - ansible.posix.selinux: - policy: targeted - state: "{{ preinstall_selinux_state }}" + include_tasks: 0079-selinux.yml + vars: + selinux_state: "{{ preinstall_selinux_state }}" when: - ansible_facts['os_family'] == "RedHat" - "'Amazon' not in ansible_facts['distribution']" diff --git a/roles/kubernetes/preinstall/tasks/0081-ntp-configurations.yml b/roles/kubernetes/preinstall/tasks/0081-ntp-configurations.yml index 2ef6558f0..ffdfb9706 100644 --- a/roles/kubernetes/preinstall/tasks/0081-ntp-configurations.yml +++ b/roles/kubernetes/preinstall/tasks/0081-ntp-configurations.yml @@ -83,9 +83,9 @@ - ansible_facts['os_family'] == "RedHat" - name: Put SELinux in permissive mode, logging actions that would be blocked. - ansible.posix.selinux: - policy: targeted - state: permissive + include_tasks: 0079-selinux.yml + vars: + selinux_state: permissive when: - ansible_facts['os_family'] == "RedHat" - ansible_facts.selinux.status == 'enabled' @@ -96,9 +96,9 @@ name: "{{ ntp_timezone }}" - name: Re-enable SELinux - ansible.posix.selinux: - policy: targeted - state: "{{ preinstall_selinux_state }}" + include_tasks: 0079-selinux.yml + vars: + selinux_state: "{{ preinstall_selinux_state }}" when: - ansible_facts['os_family'] == "RedHat" - ansible_facts.selinux.status == 'enabled' diff --git a/tests/files/almalinux8-calico.yml b/tests/files/almalinux8-calico.yml new file mode 100644 index 000000000..01fa024c6 --- /dev/null +++ b/tests/files/almalinux8-calico.yml @@ -0,0 +1,15 @@ +--- +# Instance settings +cloud_image: almalinux-8 +vm_memory: 3072 + +# Exercise Python installation before gathering facts. +bootstrap_os_install_python: true + +# EL8 glibc is older than required by the dynamically linked containerd binaries. +containerd_static_binary: true + +# Experimental EL8 coverage with kernel 4.18 and cgroup v1. +kubeadm_ignore_preflight_errors: + - SystemVerification +kubelet_fail_cgroup_v1: false diff --git a/tests/files/rockylinux8-calico.yml b/tests/files/rockylinux8-calico.yml new file mode 100644 index 000000000..4e616cd21 --- /dev/null +++ b/tests/files/rockylinux8-calico.yml @@ -0,0 +1,16 @@ +--- +# Instance settings +cloud_image: rockylinux-8 +vm_memory: 3072 + +# Kubespray settings +bootstrap_os_install_python: true +# EL8 glibc is older than required by the dynamically linked containerd binaries. +containerd_static_binary: true +metrics_server_enabled: true +loadbalancer_apiserver_type: haproxy + +# Experimental EL8 coverage with kernel 4.18 and cgroup v1. +kubeadm_ignore_preflight_errors: + - SystemVerification +kubelet_fail_cgroup_v1: false