常见疑问
# 疑问一
我们在安装k8s的过程中,会出现以下的操作:
systemctl stop firewalld
systemctl disable firewalld# 2. 禁用 SELinux(临时+永久)
setenforce 0
sed -i 's/enforcing/disabled/g' /etc/selinux/config# 3. 关闭 Swap 分区(面试常考点,保证容器性能可控)
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
在生产环境中,K8s 作为一个分布式集群操作系统,它需要拥有对底层网络、进程和物理内存的绝对控制权。而 Linux 原生自带的这三个组件(防火墙、SELinux、Swap)会和 K8s 的控制策略发生严重冲突。
以下我用最通俗的语言,结合面试考点为你拆解为什么必须关掉它们:
# 1. 关闭防火墙 (firewalld)
- 命令:
systemctl stop firewalld && systemctl disable firewalld - 大白话原因: K8s 集群里的 Pod(容器)跨机器通信、或是暴露端口时,底层都是靠 K8s 的
kube-proxy组件去动态修改 Linux 的 iptables 规则 来引流的。如果系统自带的firewalld防火墙服务一直开着,它会经常和 K8s 争夺 iptables 的控制权,把你刚建好的容器通道一脚踢断,导致你的多个飞书网关之间无法互相通信。 - 面试加分点: 真正的生产环境并不是“裸奔”,我们通常会关闭操作系统的
firewalld服务,转而使用云厂商的安全组(Security Group)或者 K8s 原生的 NetworkPolicy(网络策略) 来做更细粒度的容器间隔离。
# 2. 禁用 SELinux
- 命令:
setenforce 0加上修改配置文件 - 大白话原因: SELinux 是美国国家安全局(NSA)给 Linux 开发的一个极其严格的权限控制安全系统。它有一个原则:“除了我知道的,其他默认都是禁止的”。而 K8s 的容器在宿主机上运行时,需要频繁地读写挂载目录(比如你存放配置文件和记忆的
./bot_hr_data)、接管底层网络设备。一旦开启 SELinux,它就会误认为这些容器是“木马病毒在越权作乱”,直接强行拦截,导致容器无法启动(频繁报Permission Denied错误)。 - 面试加分点: 彻底禁用它是为了保证云原生生态的 CRI 容器运行时(如 Containerd)能顺利地为容器进行文件系统挂载和权限重映射。
# 3. 关闭 Swap 交换分区(🔥 面试重灾区,必考!)
- 命令:
swapoff -a - 什么是 Swap: 当你的服务器物理内存(RAM)不够用时,Linux 会在硬盘上划出一块空间当成临时内存来用,这个硬盘“假内存”就叫 Swap。
- 大白话原因: 1. 性能不可控(致命损耗): 硬盘的读写速度比物理内存慢上万倍!如果你的 K8s 容器不小心跑进了 Swap 区,原本响应只需几毫秒的飞书机器人,可能会因为硬盘卡顿变成十几秒才回答,这在生产环境是不可接受的。 2. 调度器会“变瞎”: K8s 脑子里的调度器(kube-scheduler)是非常精准的。它在给节点分配 Pod 时,计算的是:“Node 1 还剩 2G 物理内存,正好可以塞进一个 2G 的 Hermes 容器”。如果开启了 Swap,宿主机内存表面上被假内存撑大了,调度器就无法准确感知节点真实的资源极限,从而做出错误的调度决策,导致集群雪崩。
- 面试硬核回答: > “K8s 的资源隔离与限额是基于 Linux 内核的 cgroups(控制组) 机制实现的。K8s 默认的设计理念是让容器完全在纯物理内存中运行,从而保证应用性能的确定性与可控性。因此,为了防止 cgroups 资源限额计算失效以及硬盘 I/O 导致集群响应雪崩,K8s 团队在代码中硬编码了检测:一旦发现系统开启了 Swap,kubelet 就会默认直接拒绝启动。”
# 💡 总结
做这三个操作,本质上就是“一山不容二虎”。把操作系统的这三个原生管家关掉,K8s 才能真正成为这台服务器上的“绝对独裁者”,从而由它来全权负责安全、网络和内存的调度。
理解了这三个底层逻辑后,在后续的 K8s 面试中,只要聊到集群初始化,你就能非常专业地从“组件冲突”和“cgroups 调度原理”这两个高阶维度来解释它们了。
# 疑问2
# 生成默认配置并修改
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml# 修改 SystemdCgroup 为 true,并将默认沙箱镜像(Pause 容器)切到国内阿里云源
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
sed -i 's|registry.k8s.io/pause:3.8|registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9|g' /etc/containerd/config.toml# 启动并开机自启
systemctl daemon-reload
systemctl restart containerd
systemctl enable containerd
# 1. 为什么要将 SystemdCgroup 改为 true?(🔥 面试超高频)
大白话原因: 为了避免宿主机上出现“两个管家,互相打架”的混乱局面。
底层逻辑: Linux 内核通过 cgroups(控制组) 来限制容器能用多少 CPU 和内存。但在 CentOS 8 等较新的 Linux 系统中,系统默认启动时是由 Systemd 来作为初始化和资源管理的总管(cgroup 驱动)。
当你安装 Containerd 时,它默认的 cgroup 驱动是
cgroupfs(这是它自带的一个独立管理器)。这就出问题了:如果保持默认配置(
false),系统里就会同时存在 Systemd 和 cgroupfs 两个驱动在抢着管资源。当服务器内存紧张时,cgroupfs 认为这个容器还能跑,但 Systemd 觉得它超标了、直接强行把容器进程杀掉(OOM)。这种“双驱动”模式会导致 K8s 极不稳定,容器经常莫名其妙崩溃。我们将它改为
true,就是强行命令 Containerd:放弃你自带的驱动,完全服从宿主机的 Systemd 管辖。这样 K8s(kubelet)和 Containerd 都用 Systemd,天下太平。面试硬核话术:
“在现代化 Linux 发行版中,系统默认使用 Systemd 作为初始化系统并全权管理 cgroup 树。为了避免在单机上同时存在
systemd和cgroupfs两种 cgroup 驱动导致资源配额计算冲突、甚至引发不确定性的 OOM Kills,Kubernetes 官方极力推荐驱动一致性原则。因此,我们在 Containerd 的config.toml中显式开启SystemdCgroup = true,使整个容器栈统一使用 Systemd 驱动,从而保证生产环境的拓扑稳定性。”
# 2. 为什么要将 registry.k8s.io/pause 切换到阿里云源?
大白话原因: 原生的基础镜像在国内下载不到(被墙了),不改的话你的 K8s 里的所有 Pod 永远无法启动,全部卡在
ContainerCreating状态。什么是 Pause 容器?(核心考点): 在 K8s 的设计里,Pod 是最小调度单位,一个 Pod 里面可以跑多个业务容器(比如你的 Hermes Agent 加上一个旁路日志容器)。
那么,同一个 Pod 里的多个容器,是如何做到无缝共享同一个 IP 地址和网络空间的呢?
K8s 的天才设计就在这里:每当你创建一个 Pod,K8s 并不是先启动你的业务容器,而是先偷偷启动一个极其微小的、不干任何脏活累活的容器,这个容器就叫
Pause 容器(又叫基础设施/沙箱容器)。Pause 容器启动后,会向 Linux 内核申请一个独立的网络 Namespace。接着,你真正的业务容器(如 Hermes Agent)启动时,会通过 Linux 的
netns技术,直接强行加入到这个 Pause 容器的网络里。这样,业务容器之间就可以直接通过localhost互相通信,并共享同一个 Pod IP。面试硬核话术:
“Pause 容器是 Kubernetes 实现 Pod 概念的基石。在 CRI(如 Containerd)中,它是最先启动的沙箱容器(Sandbox Container),负责接管整个 Pod 的网络和 IPC Namespace。随后启动的业务容器通过
Container-Network模式共享该网络命名空间。由于官方默认的registry.k8s.io镜像源在国内无法访问,会导致沙箱容器创建失败、Pod 持续卡在ContainerCreating。因此需要将其重定向到阿里云等国内镜像源,以保证 K8s 基础底座能够顺利初始化。”
# 💡 总结最后三句命令:
systemctl daemon-reload # 重新加载操作系统的服务配置文件
systemctl restart containerd # 重启 Containerd 顺便应用你刚才改的 SystemdCgroup 和 阿里云源
systemctl enable containerd # 设置开机自启,保证服务器重启后容器运行时自动活着
# 疑问3
# 原则一:三网绝对互斥(不能重叠)
在设计 K8s 集群时,以下三个网段绝对不能有任何交集,否则会导致严重的路由冲突,流量直接在内核里“鬼打墙”:
- Node 物理网段(你虚拟机的真实 IP 段,比如
192.168.1.0/24) - Pod 虚拟网段(
--pod-network-cidr) - Service 虚拟网段(
--service-cidr)
# 原则二:根据业务体量算好掩码(CIDR)
- 为什么 Service 默认给的是
/12,而 Pod 给的是/16? - 面试加分回答: “
/16意味着可以容纳 $2^{16}-2 = 65534$ 个 IP 地址。在 Flannel 网络模型中,它会为每个加入集群的 Worker 节点默认切分一个/24的子网(即每个子节点最多能跑 254 个 Pod)。我们在规划生产环境时,会根据预期加入的最大节点数和单节点 Pod 密度,来倒推并自定义--pod-network-cidr的掩码大小,防止未来业务扩容时 IP 地址枯竭。”
# 原则三:禁止与公司现有内网冲突
如果你把 K8s 的 Pod 网段自定义成了 192.168.0.0/16,而你们公司办公区的 Wi-Fi 刚好也是 192.168.x.x,那就会导致你的 K8s 容器在试图访问公司内部系统时,误以为是访问集群内部的 Pod,导致网络彻底断开。所以生产环境一般会选一个公司绝对没人用的冷门私有网段。
现在你对这两个参数的含义和底层的网络结构完全吃透了吧?如果你的 Master 节点 IP 已经准备好,就可以把这行 kubeadm init 替换并砸进终端,开始唤醒你的 K8s 大脑了!