安装之前,这台服务器能承载吗
目标
在把 Kubernetes 装到前任管理员使用过的服务器之前,检查并修复 swap、内核模块、sysctl 和端口。 并通过阅读 role 的代码,分辨其中哪些是 kubespray 会自己完成的,哪些是必须由人先清理的。
为什么重要
在新拿到的 VM 上,似乎 kubespray 什么都会自动完成。实际上,关闭 swap、加载 br_netfilter、 打开 ip_forward,这些都是 preinstall 和 node role 做的。然而现场的服务器并不是新的。如果监控 agent 占用了 10250, kubespray 依然会把安装一直推进到底,而 kubelet 占不到端口,节点就起不来。如果安全检查留下的 sysctl 文件按文件名顺序排在后面, 安装当天没有问题,但首次重启时 Pod 通信就会中断。两者都属于漫长的安装全部跑完之后才会暴露的类型,所以在安装之前看一遍这些值,是最便宜的。
步骤
- 在修复任何东西之前,在
/root/ks/preflight/before.json中写入swap_total_kb(/proc/meminfo 的 SwapTotal,数字)、ip_forward(当前内核值,数字)、br_netfilter(模块是否已加载,布尔值)、busy_ports(控制平面端口 2379、2380、6443、10250、10257、10259 中,当前有东西在 LISTEN 的端口,升序的数字数组)。 - 关闭所有已开启的 swap,并把
/etc/fstab中的 swap 行删除或用注释屏蔽,使重启后也不会再次开启。swap 文件本身可以删除,也可以保留。 - 现在就加载
overlay和br_netfilter,并在/etc/modules-load.d/k8s.conf中每行写一个这两个名称,使其在开机时也会加载。 - 在
/etc/sysctl.d/k8s.conf中写入net.ipv4.ip_forward = 1、net.bridge.bridge-nf-call-iptables = 1、net.bridge.bridge-nf-call-ip6tables = 1并应用。当前内核值必须三个都是 1,并且在重启时按文件名顺序重新读取 sysctl.d 之后,三个也必须都是 1。 - 找出控制平面端口中被某个东西占用的端口,停止启动它的 systemd 单元,并使其不会在开机时再次启动(disable)。在
/root/ks/preflight/ports.json中写入port(被占用的端口,数字)、unit(启动该进程的单元名称,包含 .service)、pid(停止前该进程的 PID,数字)。结束后,2379、2380、6443、10250、10257、10259 都不能处于 LISTEN 状态。 - 在
/opt/ks/kubespray中用ansible -i /root/ks/inventory/lab/inventory.ini node1 -m setup收集这台节点的事实(facts),并在/root/ks/preflight/facts.json中写入memtotal_mb、processor_vcpus、distribution、distribution_version、kernel、default_ipv4(默认路径的 IPv4 地址)。然后从 kubespray 的roles/kubernetes/preinstall/defaults/main.yml中找到控制平面的最低内存,一并以minimal_master_memory_mb写入。 - 阅读 kubespray v2.32.0 的
roles/kubernetes/preinstall和roles/kubernetes/node,在/root/ks/preflight/who-fixes.json中,对四个问题各写入:如果 kubespray 会自己修复,就写"kubespray",如果必须由人先清理,就写"operator"。键是swap、br_netfilter、ip_forward、port_10250。并且一并写入sysctl_file(kubespray 写入 sysctl 值的文件路径,默认值)。
参考
- VM 上已准备好 kubespray v2.32.0 和 inventory
/root/ks/inventory/lab/inventory.ini(一台节点,local 连接)。本实验不进行安装。 - 常见错误:只执行
swapoff -a而保持 fstab 不变。下次开机时会再次开启。 - 常见错误:只杀掉进程。
Restart=always的单元会立即重新启动它。 - 常见错误:只看自己的 sysctl 文件就结束。请确认
sysctl --system的读取顺序。 - 文档:Kubernetes — Ports and Protocols · Kubernetes — Container Runtimes(前提条件) · Kubespray — Port requirements
在修复之前先写下现状
在修复任何东西之前,在 /root/ks/preflight/before.json 中写入 swap_total_kb(/proc/meminfo 的 SwapTotal,数字)、ip_forward(当前内核值,数字)、br_netfilter(模块是否已加载,布尔值)、busy_ports(控制平面端口 2379、2380、6443、10250、10257、10259 中,当前有东西在 LISTEN 的端口,升序的数字数组)。
正在 LISTEN 的套接字用 ss -ltnp 查看。模块是否已加载,可以用 lsmod 或 /sys/module/<이름>(占位符为模块名称)确认。评分器会与 VM 准备好时另外测得的值核对,所以如果是修复之后才写,就对不上。
关闭 swap,并让它不再重新开启
关闭所有已开启的 swap,并把 /etc/fstab 中的 swap 行删除或用注释屏蔽,使重启后也不会再次开启。swap 文件本身可以删除,也可以保留。
swapoff 只在当前关闭。开机时开启 swap 的,是 fstab 中 type 为 swap 的那一行。哪个文件是 swap,可以在 swapon --show 或 /proc/swaps 中看到。
内核模块,现在要加载,开机时也要加载
现在就加载 overlay 和 br_netfilter,并在 /etc/modules-load.d/k8s.conf 中每行写一个这两个名称,使其在开机时也会加载。
containerd 的默认快照器使用 overlay,而 br_netfilter 的作用是让经过桥接的 Pod 流量经过 iptables。modprobe 只在当前生效,modules-load.d 则从下次开机起生效。
sysctl 以最后读取的文件为准
在 /etc/sysctl.d/k8s.conf 中写入 net.ipv4.ip_forward = 1、net.bridge.bridge-nf-call-iptables = 1、net.bridge.bridge-nf-call-ip6tables = 1 并应用。当前内核值必须三个都是 1,并且在重启时按文件名顺序重新读取 sysctl.d 之后,三个也必须都是 1。
运行 sysctl --system 之后,请重新读取 ip_forward。sysctl.d 中的文件按文件名顺序读取,相同的键以后面的为准。sysctl --system 的输出会显示读取了哪些文件、按什么顺序。是删除前任管理员的文件、改名,还是把自己的文件往后排,取决于你的判断。
占用了 kubelet 位置的东西
找出控制平面端口中被某个东西占用的端口,停止启动它的 systemd 单元,并使其不会在开机时再次启动(disable)。在 /root/ks/preflight/ports.json 中写入 port(被占用的端口,数字)、unit(启动该进程的单元名称,包含 .service)、pid(停止前该进程的 PID,数字)。结束后,2379、2380、6443、10250、10257、10259 都不能处于 LISTEN 状态。
ss -ltnp 会显示 PID,启动该 PID 的单元可以在 systemctl status <PID> 或 /proc/<PID>/cgroup 中看到。如果只杀掉进程,Restart=always 的单元会立即把它重新启动。kubespray 不会替你腾出这个端口。第一次 kubeadm init 会被 preflight 的 Port-10250 错误拦住,而 kubespray 的重试会把这个错误放进忽略列表后再次运行,所以原因只留在日志上方的第一次尝试中(control-plane/tasks/kubeadm-setup.yml)。
kubespray 所看到的这台主机
在 /opt/ks/kubespray 中用 ansible -i /root/ks/inventory/lab/inventory.ini node1 -m setup 收集这台节点的事实(facts),并在 /root/ks/preflight/facts.json 中写入 memtotal_mb、processor_vcpus、distribution、distribution_version、kernel、default_ipv4(默认路径的 IPv4 地址)。然后从 kubespray 的 roles/kubernetes/preinstall/defaults/main.yml 中找到控制平面的最低内存,一并以 minimal_master_memory_mb 写入。
kubespray 的预检(0040-verify-settings.yml)根据这些事实来判定。如果内存小于最小值,安装在开始几分钟后就会停住。setup 模块的输出位于 ansible_facts 之下,默认路径地址是 default_ipv4.address。如果不另外给出 ip 变量,kubespray 会把 API 服务器和 etcd 连接到这个地址上。
哪些交给工具,哪些由人来看
阅读 kubespray v2.32.0 的 roles/kubernetes/preinstall 和 roles/kubernetes/node,在 /root/ks/preflight/who-fixes.json 中,对四个问题各写入:如果 kubespray 会自己修复,就写 "kubespray",如果必须由人先清理,就写 "operator"。键是 swap、br_netfilter、ip_forward、port_10250。并且一并写入 sysctl_file(kubespray 写入 sysctl 值的文件路径,默认值)。
preinstall 的 0010-swapoff.yml 会删除 fstab 中的 swap 行、屏蔽 swap.target 并调用 swapoff。模块和 sysctl 可以在 node 和 preinstall role 中找到,sysctl 文件路径是 kubespray_defaults 的 sysctl_file_path。腾出端口的任务哪里都没有。请同时想一想,正如你在第 4 步经历过的,如果有按文件名顺序排在 kubespray 所写文件之后的文件,重启时值就会被改回去。