先抛个反直觉的结论:一台连 SSH 都登不上去的服务器,比你能随便登的那台安全得多,也好维护得多。
我知道这话听着别扭。咱搞运维的,手里没个 ssh 通道,半夜出事怎么办?我一开始也是这反应。直到我们组那套自建 k8s 集群被人薅了——某个节点上有人手动装过一个调试工具,留了后门,我们排查了整整两天才定位到。问题不在那个工具,问题在于:那台机器上「能被人手动改」这件事本身。

Talos 把这条路直接堵死了
Talos Linux 的思路特别极端,它整个操作系统就是为跑 Kubernetes 而生的,除此之外几乎啥都没有。没有 SSH、没有 shell、没有包管理器、没有 systemd(它用自己写的 init),连个 bash 都摸不到。系统盘是只读的,跑起来之后你想往里写文件?写不进去。
那它怎么管?全靠 API。你不是登进去敲命令,而是用一个叫 talosctl 的客户端,通过 gRPC 跟节点上的 apid 通信。整个机器的状态,由一份 YAML 配置完全决定。这就是「不可变基础设施」落到操作系统这一层的样子——节点不是宠物,是牲口,坏了不修,直接拿配置重新拍一台一模一样的出来。
我当时最大的顾虑是排障。没 shell 我怎么看日志、抓进程?后来发现常见操作 talosctl 全包了:
# 看某个节点的内核日志,等价于你以前 ssh 上去 dmesg
talosctl -n 10.0.0.5 dmesg
# 看服务日志,比如 kubelet 起不来
talosctl -n 10.0.0.5 logs kubelet
# 看当前进程,等价于 ps
talosctl -n 10.0.0.5 processes
# 抓个网络包,连 tcpdump 都不用装
talosctl -n 10.0.0.5 pcap -i eth0
你发现没,这些命令背后都是只读地「读取状态」,没有一个是「我登进去手动改了点啥」。想改,只能改那份配置,然后让节点应用。这就从机制上保证了:集群里每台机器,长什么样、跑什么版本,全写在 Git 里,没有任何「某台机器上有人偷偷动过」的灰色地带。
一份配置决定一切
节点的全部身份和配置,就是一份机器配置文件。简化一下大概长这样:
version: v1alpha1
machine:
type:controlplane# 这台是控制面节点
token:xxxx.yyyyyyyyyy# 加入集群的凭证
kubelet:
extraArgs:
rotate-server-certificates:"true"
install:
disk:/dev/sda
image:ghcr.io/siderolabs/installer:v1.9.1# 系统镜像,版本钉死
wipe:false
#没有 users,没有 sshd 配置,因为压根没这玩意
cluster:
controlPlane:
endpoint:https://10.0.0.1:6443
network:
cni:
name:flannel
升级 k8s 版本怎么搞?不是 apt upgrade,是换上面那个 installer 镜像的 tag,然后一条命令滚动升级:
talosctl -n 10.0.0.5 upgrade --image ghcr.io/siderolabs/installer:v1.9.2
它会把节点优雅地 drain 掉、换新镜像、重启、重新加入集群。整个过程你不用登任何机器。我们上次从 1.28 跨到 1.29,全程在 CI 里跑的脚本,人没碰过键盘。
那真出了 SSH 才能解决的事呢
讲真,用了大半年,我们还没遇到过「非 SSH 不可」的场景。早期我担心的那些——看日志、改配置、抓包、重启服务——talosctl 全有对应命令。真要说有什么不一样:
●思维得换。你不能再「先上去看看再说」,得先想清楚要查什么状态,再用对应的子命令去拿。
●装 DaemonSet 跑特权容器这条路还在,真需要往节点里塞点东西,规规矩矩走 Kubernetes 的资源,留痕、可审计、可回滚。
●调试某些底层问题时,确实比有 shell 的系统多绕一道。但这点不便,换来的是「这台机器永远跟配置一致」的确定性。
我现在的体会是这样:以前能 SSH,给的是一种「我随时能补救」的安全感,但这份安全感的代价,是每台机器都可能藏着没人记得的手动改动,时间一长,集群就变成一堆谁也不敢动的雪花服务器。Talos 把这条退路堵死,逼着你把所有变更都走配置、进 Git,短期憋屈,长期是真省心。
被后门坑过那两天的我,现在看着登不上去的节点,心里反而踏实。