TT Lab
开始
学习 学习路径 课程

用 Kubespray 与 Terraform 搭建集群

安装之前,这台服务器能承载吗

在 TT Lab 中继续学习

目标

在把 Kubernetes 装到前任管理员使用过的服务器之前,检查并修复 swap、内核模块、sysctl 和端口。 并通过阅读 role 的代码,分辨其中哪些是 kubespray 会自己完成的,哪些是必须由人先清理的。

为什么重要

在新拿到的 VM 上,似乎 kubespray 什么都会自动完成。实际上,关闭 swap、加载 br_netfilter、 打开 ip_forward,这些都是 preinstall 和 node role 做的。然而现场的服务器并不是新的。如果监控 agent 占用了 10250, kubespray 依然会把安装一直推进到底,而 kubelet 占不到端口,节点就起不来。如果安全检查留下的 sysctl 文件按文件名顺序排在后面, 安装当天没有问题,但首次重启时 Pod 通信就会中断。两者都属于漫长的安装全部跑完之后才会暴露的类型,所以在安装之前看一遍这些值,是最便宜的。

步骤

  1. 在修复任何东西之前,在 /root/ks/preflight/before.json 中写入 swap_total_kb(/proc/meminfo 的 SwapTotal,数字)、ip_forward(当前内核值,数字)、br_netfilter(模块是否已加载,布尔值)、busy_ports(控制平面端口 2379、2380、6443、10250、10257、10259 中,当前有东西在 LISTEN 的端口,升序的数字数组)。
  2. 关闭所有已开启的 swap,并把 /etc/fstab 中的 swap 行删除或用注释屏蔽,使重启后也不会再次开启。swap 文件本身可以删除,也可以保留。
  3. 现在就加载 overlay 和 br_netfilter,并在 /etc/modules-load.d/k8s.conf 中每行写一个这两个名称,使其在开机时也会加载。
  4. 在 /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。
  5. 找出控制平面端口中被某个东西占用的端口,停止启动它的 systemd 单元,并使其不会在开机时再次启动(disable)。在 /root/ks/preflight/ports.json 中写入 port(被占用的端口,数字)、unit(启动该进程的单元名称,包含 .service)、pid(停止前该进程的 PID,数字)。结束后,2379、2380、6443、10250、10257、10259 都不能处于 LISTEN 状态。
  6. 在 /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 写入。
  7. 阅读 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 值的文件路径,默认值)。

参考

在修复之前先写下现状

在修复任何东西之前,在 /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 所写文件之后的文件,重启时值就会被改回去。