Created
March 21, 2026 01:27
-
-
Save ran-dall/bb6581524da6b3e8fec1ce91acff9dce to your computer and use it in GitHub Desktop.
Simple Bash script to verify and fix required host networking settings for Kubernetes on Arch-based systems.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # check-k8s-netfilter-arch.sh | |
| # | |
| # Checks common Kubernetes networking prerequisites on Arch-based systems: | |
| # - br_netfilter module exists | |
| # - br_netfilter module is loaded | |
| # - net.bridge.bridge-nf-call-iptables = 1 | |
| # - net.bridge.bridge-nf-call-ip6tables = 1 | |
| # - net.ipv4.ip_forward = 1 | |
| # | |
| # Modes: | |
| # default Check only, print guidance if something is missing | |
| # --fix Apply runtime fixes, ask before persisting | |
| # --persist Apply runtime fixes and persist without prompting | |
| # --help Show help | |
| usage() { | |
| cat <<'EOF' | |
| Usage: | |
| check-k8s-netfilter-arch.sh [--fix | --persist | --help] | |
| Options: | |
| --fix Apply runtime fixes. Ask before persisting. | |
| --persist Apply runtime fixes and persist them without prompting. | |
| --help Show this help text. | |
| EOF | |
| } | |
| have_cmd() { | |
| command -v "$1" >/dev/null 2>&1 | |
| } | |
| get_sysctl_value() { | |
| local key="$1" | |
| sysctl -n "$key" 2>/dev/null || true | |
| } | |
| is_module_loaded() { | |
| lsmod | awk '{print $1}' | grep -qx 'br_netfilter' | |
| } | |
| print_status() { | |
| local status="$1" | |
| shift | |
| printf '%s: %s\n' "$status" "$*" | |
| } | |
| ask_yes_no() { | |
| local prompt="$1" | |
| local answer | |
| read -r -p "$prompt [y/N]: " answer | |
| [[ "$answer" =~ ^[Yy]$ ]] | |
| } | |
| apply_runtime_fixes() { | |
| local need_module_load="$1" | |
| local need_bridge_iptables="$2" | |
| local need_bridge_ip6tables="$3" | |
| local need_ip_forward="$4" | |
| if [[ "$need_module_load" == "true" ]]; then | |
| print_status "INFO" "Loading br_netfilter" | |
| sudo modprobe br_netfilter | |
| fi | |
| if [[ "$need_bridge_iptables" == "true" ]]; then | |
| print_status "INFO" "Setting net.bridge.bridge-nf-call-iptables=1" | |
| sudo sysctl -w net.bridge.bridge-nf-call-iptables=1 >/dev/null | |
| fi | |
| if [[ "$need_bridge_ip6tables" == "true" ]]; then | |
| print_status "INFO" "Setting net.bridge.bridge-nf-call-ip6tables=1" | |
| sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=1 >/dev/null | |
| fi | |
| if [[ "$need_ip_forward" == "true" ]]; then | |
| print_status "INFO" "Setting net.ipv4.ip_forward=1" | |
| sudo sysctl -w net.ipv4.ip_forward=1 >/dev/null | |
| fi | |
| } | |
| persist_fixes() { | |
| print_status "INFO" "Writing /etc/modules-load.d/br_netfilter.conf" | |
| echo br_netfilter | sudo tee /etc/modules-load.d/br_netfilter.conf >/dev/null | |
| print_status "INFO" "Writing /etc/sysctl.d/99-kubernetes.conf" | |
| sudo tee /etc/sysctl.d/99-kubernetes.conf >/dev/null <<'EOF' | |
| net.bridge.bridge-nf-call-iptables = 1 | |
| net.bridge.bridge-nf-call-ip6tables = 1 | |
| net.ipv4.ip_forward = 1 | |
| EOF | |
| print_status "INFO" "Reloading sysctl settings" | |
| sudo sysctl --system >/dev/null | |
| } | |
| mode="check" | |
| case "${1:-}" in | |
| "") | |
| ;; | |
| --fix) | |
| mode="fix" | |
| ;; | |
| --persist) | |
| mode="persist" | |
| ;; | |
| --help|-h) | |
| usage | |
| exit 0 | |
| ;; | |
| *) | |
| usage >&2 | |
| exit 2 | |
| ;; | |
| esac | |
| if ! have_cmd modinfo; then | |
| print_status "FAIL" "modinfo is not available" | |
| exit 1 | |
| fi | |
| if ! have_cmd lsmod; then | |
| print_status "FAIL" "lsmod is not available" | |
| exit 1 | |
| fi | |
| if ! have_cmd sysctl; then | |
| print_status "FAIL" "sysctl is not available" | |
| exit 1 | |
| fi | |
| need_fix=false | |
| need_module_load=false | |
| need_bridge_iptables=false | |
| need_bridge_ip6tables=false | |
| need_ip_forward=false | |
| if modinfo br_netfilter >/dev/null 2>&1; then | |
| print_status "OK" "br_netfilter module exists" | |
| else | |
| print_status "FAIL" "br_netfilter module was not found in the running kernel" | |
| cat <<'EOF' | |
| This kernel does not appear to provide br_netfilter. | |
| On Arch-based systems, use a kernel/modules package that includes it. | |
| EOF | |
| exit 1 | |
| fi | |
| if is_module_loaded; then | |
| print_status "OK" "br_netfilter module is loaded" | |
| else | |
| print_status "FAIL" "br_netfilter module is not loaded" | |
| need_fix=true | |
| need_module_load=true | |
| fi | |
| bridge_iptables="$(get_sysctl_value net.bridge.bridge-nf-call-iptables)" | |
| if [[ "$bridge_iptables" == "1" ]]; then | |
| print_status "OK" "net.bridge.bridge-nf-call-iptables = 1" | |
| else | |
| print_status "FAIL" "net.bridge.bridge-nf-call-iptables = ${bridge_iptables:-missing}" | |
| need_fix=true | |
| need_bridge_iptables=true | |
| fi | |
| bridge_ip6tables="$(get_sysctl_value net.bridge.bridge-nf-call-ip6tables)" | |
| if [[ "$bridge_ip6tables" == "1" ]]; then | |
| print_status "OK" "net.bridge.bridge-nf-call-ip6tables = 1" | |
| else | |
| print_status "FAIL" "net.bridge.bridge-nf-call-ip6tables = ${bridge_ip6tables:-missing}" | |
| need_fix=true | |
| need_bridge_ip6tables=true | |
| fi | |
| ip_forward="$(get_sysctl_value net.ipv4.ip_forward)" | |
| if [[ "$ip_forward" == "1" ]]; then | |
| print_status "OK" "net.ipv4.ip_forward = 1" | |
| else | |
| print_status "FAIL" "net.ipv4.ip_forward = ${ip_forward:-missing}" | |
| need_fix=true | |
| need_ip_forward=true | |
| fi | |
| if [[ "$need_fix" == false ]]; then | |
| printf '\n' | |
| print_status "OK" "All Kubernetes networking prerequisites are satisfied" | |
| exit 0 | |
| fi | |
| printf '\n' | |
| case "$mode" in | |
| check) | |
| print_status "INFO" "This host is missing one or more Kubernetes networking prerequisites" | |
| cat <<'EOF' | |
| To apply runtime fixes now: | |
| sudo modprobe br_netfilter | |
| sudo sysctl -w net.bridge.bridge-nf-call-iptables=1 | |
| sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=1 | |
| sudo sysctl -w net.ipv4.ip_forward=1 | |
| To persist these settings: | |
| echo br_netfilter | sudo tee /etc/modules-load.d/br_netfilter.conf | |
| sudo tee /etc/sysctl.d/99-kubernetes.conf >/dev/null <<'EOT' | |
| net.bridge.bridge-nf-call-iptables = 1 | |
| net.bridge.bridge-nf-call-ip6tables = 1 | |
| net.ipv4.ip_forward = 1 | |
| EOT | |
| sudo sysctl --system | |
| Or rerun this script with: | |
| --fix | |
| --persist | |
| EOF | |
| exit 1 | |
| ;; | |
| fix) | |
| apply_runtime_fixes \ | |
| "$need_module_load" \ | |
| "$need_bridge_iptables" \ | |
| "$need_bridge_ip6tables" \ | |
| "$need_ip_forward" | |
| printf '\n' | |
| print_status "OK" "Runtime fixes applied" | |
| if ask_yes_no "Persist these settings across reboot?"; then | |
| persist_fixes | |
| print_status "OK" "Persistent configuration written" | |
| else | |
| print_status "INFO" "Persistent configuration not written" | |
| fi | |
| ;; | |
| persist) | |
| apply_runtime_fixes \ | |
| "$need_module_load" \ | |
| "$need_bridge_iptables" \ | |
| "$need_bridge_ip6tables" \ | |
| "$need_ip_forward" | |
| persist_fixes | |
| printf '\n' | |
| print_status "OK" "Runtime and persistent fixes applied" | |
| ;; | |
| esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment