ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kubernetes节点为何需要不可变操作系统:极简、安全、无SSH的节点管理

Kubernetes节点为何需要不可变操作系统:极简、安全、无SSH的节点管理 很多年前我刚接触 Kubernetes 时一直有个疑问Kubernetes 明明已经把服务封装成了不可变的容器为什么承载它的 Linux 主机还是一台可以登录、可以随便改系统的“活机器”后来在维护几十台节点的集群时这个疑问变成了切肤之痛。今天要聊的就是专门为 Kubernetes 打造的一类 Linux 操作系统——开源、极简、不可变把安全当成第一优先级。它不再是一个可以随便操作的通用系统而是一个被规格化、产线化的一次性基础设施。先理解它为什么出现再动手用它很多运维习惯都会发生改变。这篇文章适合正在为节点一致性发愁的 SRE、平台工程师还有被安全审计追着跑的运维朋友。1. Kubernetes 节点为什么不应该再跑通用 Linux1.1 通用发行版把 kubelet 装进了一个充满变量的环境很多团队从 Ubuntu 或 CentOS 起步依赖包管理器把 kubelet、容器运行时和一堆工具装进节点。这个方式在单机、两三台节点时完全可行规模上去之后问题才开始显现。通用发行版出于兼容大众场景的目的预装了一大堆 Kubernetes 根本用不到的东西计划任务、邮件组件、编辑器、开发工具链、各种驱动。这些东西不参与容器调度却要和 kubelet 一起抢占内存和磁盘更要命的是它们同样要打补丁、要维护。如果你的安全团队要求每月修复漏洞那么面对几十台节点你可能每个周期都要在“不重启影响运行”和“补丁必须生效”之间反复摇摆。真正让通用发行版难以为继的是“可变”。包管理器给了任何一个有 root 权限的人修改系统的能力今天 A 管理员装个 tcpdump明天 B 同事顺手把内核参数改了。这些改动大多没有沉淀成文档也不会被版本化于是集群里每一台节点都逐渐变成一件“孤品”。当你定位一个诡异问题往往发现它只在某几台节点上出现而这恰好就是那几台被改过某些东西的机器。kubelet 本身是设计成声明式的你期望每个节点行为一致但底下的操作系统却在不断漂移。一次普通的系统升级牵扯到依赖库变化就可能破坏 kubelet 的启动链路这种“例行维护搞挂节点”的案例我遇到过不止一次。1.2 不可变架构把操作系统当镜像而不是当宠物不可变基础设施这个词最早是从服务端配置管理社区传出来的。它把一个重要经验推到极致如果一台服务器是可以登录、可以修改、可以长期“生活”的那你永远无法保证它的真实状态和你的配置定义一致如果你根本不修改运行中的服务器每次变更都通过替换镜像和重建实例去完成那系统的行为就像打印出来的文件一样可预期。容器世界已经贯彻了这个理念一个镜像打上 digest谁拉下来运行都是同样的产物不可变 Linux 操作系统就是把这个理念从工作负载进一步下沉到宿主机。在这类系统上根文件系统默认只读没有我们习惯的包管理器也不允许你在上面持续安装软件。你要做的事情是定义一份“我所期望的节点最终状态”比如网络、存储、角色然后让节点照着这份定义自己组装自己。后续所有调整都通过生成新配置或者新镜像来触发而不是登录节点去就地修补。这样处理集群的好处很明显节点不会因为某次人工操作而变得跟旁边那台不一样也不会因为忘记某个补丁而留下后门。坏了一台节点最常见也最合理的操作不是修而是直接踢掉重新引导一台让它变成和模板完全一致的副本。因为操作对象从“这台活机器”变成了“这份配置和这套镜像”日常运维里最耗费心神的几类问题就会被消解配置漂移、漏更某个依赖、为了排查临时改动系统文件。集群的一致性第一次变得可以被版本化和自动化完整覆盖。这正是 Kubernetes 使用方在基础设施层缺失的最后一环。2. 从设计上看极简、API 驱动与安全默认2.1 极简到什么程度才算合适讲这类系统之前我建议你先看一眼自己的节点现状一个全新安装的通用发行版启动后有多少个处于运行状态的服务多半在 50 个以上。一个不可变 Kubernetes 专用系统的目标是把宿主机上的活跃项压缩到一只手数得过来内核、平台初始化服务、容器运行时、kubelet、网络插件。除此之外没有多余的用户态服务没有图形栈没有编译器甚至没有常规意义上的包管理工具。有人会在第一眼看到一个小体积镜像时犹豫“这么少的东西真的够用吗”恰恰是这种少保证了你不需要为不需要的功能付出安全代价。举个实际感受专用系统的内核在编译时就去掉了大量用不上的驱动和模块默认只放开容器运行必需的能力这意味着某天网络上爆出一个仅有少数发行版默认模块受影响的内核漏洞时你的集群可能从结构上就不被打到。少不只是为了省内存和磁盘更是在攻击面这个维度上做了减法。还有一点常被忽略这类系统把“该留的不该留的”考虑得很清楚。磁盘分区通常划分成系统分区和存储分区系统分区只读运行存储分区才交给 etcd、容器镜像层这类运行时数据。你不需要操心“这台机器上到底哪些文件被改过”因为系统分区根本没有可写权限。2.2 用声明式配置管理节点而不是 SSH我们把目光放到日常管理入口。传统 Linux 的管理入口是 SSH是不可或缺的。而这类 Kubernetes 原生系统的管理思想完全不同节点启动时读取一份机器配置这份配置被系统工具生成、校验、签名之后决定节点的最终状态。节点加入集群后管理员面对的是一个固定不变的 Kubernetes API而不是一台随时可登录的 Linux。作为示例我拿这类系统中很典型的一份控制平面节点配置来演示。生成配置的工具会先从命令参数里接收集群名称和控制面地址然后输出类似下面的 YAMLmachine: type: controlplane network: hostname: k8s-control-01 nameservers: - 10.0.0.2 interfaces: - interface: eno1 dhcp: true install: disk: /dev/sda cluster: controlPlane: endpoint: https://10.0.0.10:6443 network: dnsDomain: cluster.local podSubnets: - 10.244.0.0/16 serviceSubnets: - 10.96.0.0/12我把这些字段换成人话machine.type决定这台节点是控制平面还是普通工作节点cluster.controlPlane.endpoint是你在 kubectl 配置里填的访问地址可以是负载均衡器的地址也可以是第一个控制面节点的地址podSubnets和serviceSubnets是集群内部网段必须提前规划好不能和现有物理网络冲突。这份配置还能表达更细的内容比如静态 IP、磁盘分区方式、内核参数、证书轮换等。在 GitOps 团队里它们会被直接放进仓库走代码评审流程。节点的引导方式也很直接把配置通过网卡的 PXE 启动、云平台的 user-data 或本地启动介质交给节点节点首次通电后会自动应用配置并完成加入。整个过程不需要你像过去那样在机器旁边敲命令或者手工配置网络。2.3 高度安全是从系统设计长出来的不是靠事后加固很多安全措施是装到系统之后再加的装防火墙、关闭密码登录、加固 SSH、定期扫描漏洞。这套路没有错但它经不起一个自然追问既然一套通用系统需要这么多补偿动作为什么不把危险入口直接去掉这类系统给的标准答案很干脆默认没有 SSH也没有可登录的 shell 环境。我理解很多人听到这里心里发怵——没有 SSH 还怎么排查集群我的实际体验是操作入口被压缩成 kubectl 之后绝大多数宿主机操作反而变得更简单、更规范了。想确认某台节点的状态用kubectl get nodes -o wide和kubectl describe node想看到某一个 Pod 的错误日志直接kubectl logs这些操作全都走经过鉴权的 Kubernetes API连节点私钥都不再需要出现在运维同学的电脑里。“默认没有 SSH”带来的连锁收益非常可观没有可用的 shellroot 弱口令、密钥泄露、管理员误执行命令这些常见风险来源就没有附着点根文件系统只读即使某个容器被攻破并逃逸到宿主机攻击者也很难改写系统分区、植入持久化后门或篡改后续的启动过程。需要把安全落地情况落在纸面上时这份配置天然就可以提交给审计方讲起来比一串手工加固命令有力得多。证书方面也不需要人去登录刷新节点的 kubelet 证书会由系统组件在过期前自动轮换时间同步一旦配置好证书过期这种常见的集群断连事故基本可以从清单里划掉。3. 实操从裸金属到可交付集群的完整过程3.1 开工前的准备动作如果只看宣传语你会觉得这套东西很神秘但落地过程比传统方案还要线性。开工前我习惯先花半小时把准备工作列清楚。第一机器规划。控制平面至少一台正式环境建议三台组成高可用工作节点按业务量加。每台节点要有固定可达的地址最好在 DHCP 里为它们的物理地址预留固定 IP否则节点重启后地址漂移会给集群带来访问层面的麻烦。第二网络规划。集群内部两个网段要提前定好Pod 网段和 Service 网段。这两个网段只在集群内部可见但必须和公司的物理网络、云上的私有网络分隔开不然路由会产生冲突。DNS 地址建议至少给两个并且保证它们与节点实际能用的解析路径一致。第三时间同步。这里我要特意划重点。Kubernetes 内部大量使用双向 TLS 证书做身份认证证书验证依赖各节点的时间如果某台节点的时间偏差超过几分钟它和其他组件之间的握手就会失败。不可变系统出厂时时间同步服务基本是开着的但如果你所在的机房没有放行默认的 NTP 端口需要提前在机器配置里指向内网时间服务器。我在不少集群里排查过一种现象所有节点看起来正常但某一台上面的 Pod 偶尔连接异常如果节点时间偏了就大概率能复现出这种异常。第四命令行工具和镜像准备。在管理机上安装与目标系统配套的 CLI 工具把 ISO、云镜像或裸金属镜像下载到本地同时规划好镜像仓库的访问方式。三台节点都用同一个镜像文件配置差异交给机器配置去表达。3.2 配置生成、初始化与加入节点的全流程我以这类系统里一个比较有代表性的发行版为例命令行工具生成配置的过程非常直观。下面是初始化一个集群的两条核心动作。生成集群配置命令大致是k8sos gen config k8s-demo https://10.0.0.10:6443执行后会输出两个文件一个是控制平面配置一个是工作节点配置。控制平面配置用第一个控制面节点去引导工作节点配置则由剩下的机器共用。不同产品的命令名可能不同但思路一致把集群名称、控制面访问地址和网段参数交给工具工具替你生成带签名的机器配置。拿到配置后我把控制平面配置塞进第一台节点的启动介质例如云平台上的 user-data 字段或者裸金属环境下通过管理控制器挂载的虚拟介质。节点第一次通电后会自动去拉取镜像、按配置写盘然后重启进入正式系统。当第一个控制面节点初始化完成集群的 Kubernetes API 就已经对外提供服务了。这时候我会用集群配置文件验证一下状态kubectl get nodes此时应该能看到第一个控制面节点状态大概率是 NotReady这是一个预期现象因为网络插件还没有部署。你想让节点真正进入 Ready需要接着安装网络插件比如 Cilium、Calico 这一类组件。很多第一次接触不可变系统的人会被这一步吓到其实它和你在普通 Linux 机群上安装网络组件没有任何区别。工作节点加入就更省心了。我要做的就是把之前生成的工作节点配置同样塞进剩余的机器逐台上电。因为这些机器的用途一致配置完全一样我会把它们当成一批“商品”坏了任何一台直接拿同样配置重新引导不需要做任何手工初始化。节点加入后在控制面执行kubectl get nodes就能确认已有多少节点进入 Ready并看到每个节点上被分配的 Pod 网段。3.3 升级、回滚与日常维护的心得一句话总结不可变系统的升级它不是原地打补丁而是把整台节点的系统分区整体替换成新版本。和传统发行版相比它更像把服务器的启动盘从旧版本换成了新版本同时保留一部分运行时数据。我用这类系统的升级命令举例它一般长这样k8sos upgrade --nodes10.0.0.11 --target-imageregistry.example.com/k8sos:latest执行升级前我会做三件准备工作。第一确认当前集群整体是健康的比如所有节点状态正常、etcd 正常第二给 etcd 打一个快照备份到节点故障后可以恢复的位置第三看一遍官方升级路径确认当前版本之间不需要做额外迁移。升级过程会先拉取新镜像写入另一个分区然后重启节点并切到新分区。整个过程有一个特征值得你适应重启是正常操作不需要害怕。一旦新版本有问题回滚同样简单。系统保留了至少一个旧分区你只要让节点回退到上一个分区启动就能回到升级前的版本。这种 A/B 分区机制在传统包管理里几乎看不到但它天然适合容器集群你就是把宿主机也当成一份可以回滚的部署单元。日常维护中我不会再关心某台机器上装了哪些软件包我关心的是镜像仓库里保存的节点版本是否一致以及工作节点模板有没有跟上最新安全修补。所有这些信息都可以通过命令行批量核对而不再需要逐台登录去收集。4. 常见问题与排查实录4.1 高频问题速查表我把实际维护中容易碰到的问题整理成了速查表按现象分类。它未必覆盖所有场景但能解决一大半急症。现象可能原因处理思路控制面节点初始化后 NotReady网络插件未部署安装对应组件检查 Pod 网段是否冲突工作节点加入后反复重启引导配置与控制面地址不匹配检查 endpoint 地址与端口确认配置未被篡改节点状态正常但 Pod 调度异常节点标签或污点不符合预期用 kubectl describe node 查看标签、污点和可用资源证书相关握手失败节点时间同步失效校准时间服务器配置让节点证书自动轮换DNS 解析时好时坏机器配置中的 DNS 上游不一致统一配置 DNS 列表将解析路径收敛到内网 DNS升级后集群版本混用多台节点一起重启导致中间状态让所有节点版本对齐必要时从备份恢复表格里的问题其实可以归成两类一类是网络没有按预期打通一类是时间和证书问题。Kubernetes 的故障里证书相关的比例相当高而在不可变系统里解决证书问题的方式通常是检查时间同步和机器配置而不是登录节点去手动生成证书。4.2 调试方式的转变没有 SSH 之后我调试习惯的变化值得单独聊一段。以前遇到 CPU 被打满我的第一反应是登录上去开个监控工具现在我会先看这个节点上跑了哪些 Pod再通过 Kubernetes 的指标接口在控制面统一观察。过去登录节点随意执行命令其实常常把现场破坏了等查完问题这台机器已经不是出事时的样子现在所有排查入口都经过 Kubernetes API至少我能保证“看”和“改”是分离的且每一步都有审计记录。需要看节点上的容器运行时状态时系统通常也会提供对应的命令行工具比如标准接口crictl你完全可以用它列出容器、拉取日志。因为默认没有登录 shell你反倒更愿意把日志集中到外部系统比如把节点日志和业务日志统一推送到日志平台。我有一条实操建议部署这类集群之前先把日志、指标和告警通道搭好别等出事再考虑。线上出问题时你会发现控制面能拿到的事件、状态、指标比你在某台机器上敲命令拿到的信息可靠得多。4.3 我踩过的三个坑第一个坑是时间同步。某次我图省事机器配置里的 DNS 写了但时间服务器没有改成内网地址节点用的是默认公共时间源而机房防火墙把它拦了。结果控制面一切正常某个工作节点的 kubelet 和 API Server 之间的证书验证隔三差五失败很长一段时间里我都在怀疑网络插件有问题。后来打开节点事件才发现时间差已经跑到了几分钟。这事之后我把时间同步检查放进了生成配置前的强制清单。第二个坑是升级操作太激进。以为是传统包升级顺手把三个控制面节点一起提版结果 etcd 成员之间出现短暂的不一致差点把控制面带挂。后来我学会克制控制面节点逐个升级每升完一个就观察几分钟确认集群具备仲裁能力再动下一台。工作节点倒是可以分批来但分批的颗粒度也不要太大一次一批观察完再继续。第三个坑是安全感带来的松懈。不可变系统把节点层弄得非常干净容易让人误以为整个集群从此高枕无忧。实际上工作负载还是可能因为镜像漏洞、凭据泄露被打穿服务账号权限过大也是常见问题。安全运维的重心从“别登录节点”变成了“管好供应链和工作负载”前者由架构解决后者仍然要靠人持续跟进。5. 什么场景适合切换以及同类方案怎么选5.1 适合切换的典型场景动不动就几十台节点的集群是最适合这套方案的。节点数量一旦上来人工逐台维护的成本会快速上涨而不可变系统把节点变成了同构的“耗材”一致性由模板保证。追求 GitOps 的团队也会发现它和现有流程非常契合从集群配置到机器配置都可以放进仓库变更走评审与自动发布不再依赖某个人的运维手感。安全要求比较严格的行业同样适合少了 SSH 入口基础设施审计自查的环节也会少很多。资源受限的边缘场景也是它的主场。一个小体积的系统镜像占用内存小、启动速度快可以在很旧或很小的设备上跑起来。如果你需要同时交付很多个集群比如给不同项目组各开一套环境这套系统的价值就更明显了节点模板一致、升级回滚统一、交付动作完全自动化不需要为每一套环境重新写初始化脚本。5.2 暂时别急着切换的情况这不是万能药。如果你的业务里还有必须跑在宿主机上的非容器化进程比如某个老旧的采集程序或专有数据库不可变系统那种“只读、无包管理”的环境会让你非常难受。依赖厂商闭源内核模块的场景也要慎重网卡驱动、GPU 驱动这类东西如果不能提前放进镜像运行起来会很麻烦。团队如果严重依赖 SSH 长期远程维护节点又缺乏把操作升级为配置的能力切换成本会比其他团队高不少。还有一类场景是合规层面指定特定发行版的。在这种情况下不需要进行理念上的争论把兼容性放在首位。我认为比较务实的做法是先在边缘和测试环境跑这套方案积累信心之后再评估正式环境而不是一次性把历史包袱全部压上去。5.3 对照参考同类方案没有唯一标准答案标题里描述的“开源、极简、不可变、安全”并不是某一个项目的专属标签。我从实际项目里梳理出几个代表选项放在一条线上。方案与 K8s 集成深度管理接口适合谁Talos Linux极深面向 Kubernetes 原生设计无 SSH靠 CLI 与 Kubernetes API纯容器化、追求自动化与高安全的团队Flatcar Container Linux较深自带容器运行时可选 SSH常用 Ignition 配置需要保留一定宿主机控制力的运维团队Fedora CoreOS中等容器优先支持 SSHIgnition 配置习惯红帽生态、需要灵活操作的团队Talos Linux 是这类系统里比较有代表性的一个它把节点管理完全收编进 Kubernetes 的视野升级、重启都能通过命令行风格完成。Flatcar 保留了更多 Linux 痕迹适合那些仍希望在宿主机上保留一定操作空间的团队。Fedora CoreOS 则更接近一个“容器化优先但依旧可登录”的通用底座。选型时不用追求最强的不可变先问自己三个问题团队能接受没有 SSH 吗宿主机上还有没有必须存在的东西安全审计希望我们交出什么样的一页纸答案清楚了选择自然就清楚了。我自己的体会是这类系统真正的收益要过一段时间才会大量显现。切换到不可变系统的最初两周会觉得各种习惯被限制等集群运行几个月后回头再看你会发现已经很久没有因为“某台节点被人改过”而半夜起来排查了。把节点变成模板的一部分让安全成为默认值这是 Kubernetes 基础设施里很值得做的一次调整。如果你正计划新集群不妨拿一台测试节点先跑起来把机器配置放进版本库感受一下“不用登录也能维护集群”的工作方式。我的最终建议是先在非生产环境里跑通完整的升级与回滚演练再决定要不要把这套模式推广到所有集群。
返回列表