项目地址:https://github.com/kelseyhightower/kubernetes-the-hard-way 定位:不用 minikube/kubeadm/托管云,从证书签发到节点组网手工部署一个五脏俱全的 Kubernetes 集群。作者 Kelsey Hightower(前 Google 布道师)。
| 元信息 | 说明 |
|---|---|
| 形态 | 教程(本地 VM/物理机),全程 shell 命令 |
| 时长 | 6-10 小时(完整走一遍) |
| 前置 | 熟悉 Linux、TLS 基础、读过第 5 篇的架构 |
| 产出 | 手工搭出的可用集群(etcd + 控制面组件 + 2 个 worker) + 满满的"原来如此" |
1、值得"浪费"一天的理由
- kubeadm 一键装完后,你学到的可能只是"kubeadm 能装 K8s":组件怎么通信、证书谁签给谁、kubelet 凭什么信任 API Server——黑盒依旧;
- hard way 把每个黑盒拆开:你亲手生成每一张证书、写每一段 systemd unit、配每一条路由。此后 K8s 的任何故障(证书过期、节点 NotReady、apiserver 起不来)你都有"结构化想象力";
- 面试官问"说说 K8s 控制面组件如何互相认证",做过 hard way 的人能画出证书链,没做过的人只能背组件名。
2、路线图:10 个阶段的依赖关系
① 环境准备(VM/云主机、网段规划)
▼
② CA 与证书体系(ca.pem 签发 admin/kubelet/kube-proxy/
kube-scheduler/kube-controller-manager/kube-apiserver/etcd/
service-account 八类证书) ←─ 全集群信任的根
▼
③ etcd 集群(peer/client 证书) ←─ 见第 10 篇
▼
④ kube-apiserver(含 encryption-config、审计策略可选)
▼
⑤ RBAC:为 kubelet/bootstrap 与 scheduler/controller-manager
授权(Kubeconfig 文件 = 证书+API 地址+上下文)
▼
⑥ 控制面其余组件(scheduler/controller-manager 以
"非容器化 systemd 服务"运行;多 master 时前置负载均衡/VIP)
▼
⑦ worker 节点:containerd + kubelet + kube-proxy(kubeconfig 引导)
▼
⑧ 网络插件(CNI:CNIConfig + pod 网段路由/overlay)
▼
⑨ 验收:DNS(CoreDNS)、smoke test(部署 nginx、NodePort)
▼
⑩ 清理资源
每一步都建立在上一步的产物(证书/配置/负载均衡地址)之上——这个依赖图本身就是 K8s 的"信任拓扑"。
3、最有价值的五个"卡点"
3.1、证书:K8s 的信任体系
# 每张证书 = CN(身份)+ SAN(域名/IP)+ 签发链
# 例:kube-apiserver 的 SAN 必须包含
# kubernetes.default(Service 域名)、10.32.0.1(Service CIDR 首地址)、
# controller 节点各 IP、127.0.0.1(多 master 时另加各节点 IP 与 VIP)…
- 卡点:漏一个 SAN → 某些客户端(kube-proxy、kubectl 内部域名)握手报
x509: certificate is valid for … not for …; - 收获:K8s 所有组件互为 TLS 客户端与服务端,RBAC 授权的"身份"就是证书 CN/O 映射的 User/Group。看懂这张证书表,
kubectl auth can-i与各类 401/403 不再神秘。
3.2、kubeconfig:认证的统一容器
kubectl config set-cluster hardway --server=https://VIP:6443 \
--certificate-authority=ca.pem --embed-certs=true
kubectl config set-credentials admin --client-certificate=admin.pem --client-key=admin-key.pem
kubectl config set-context ctx --cluster=hardway --user=admin
一次配置,处处复用——kubelet、scheduler、controller-manager 全用同一格式的 kubeconfig 指向 apiserver。理解 kubeconfig,就理解了 K8s 的身份模型。
3.3、etcd 与 apiserver 的连接
--etcd-servers=https://10.0.1.11:2379,...
--etcd-cafile=/etc/etcd/ca.pem
--etcd-certfile=/etc/etcd/kubernetes.pem
--etcd-keyfile=/etc/etcd/kubernetes-key.pem
apiserver 是 etcd 的唯一写入者(其他组件只能通过 apiserver),证书双向校验。结合第 10 篇:这里就是"watch 机制"的源头,所有控制器的视野都从这里出发。
3.4、kubelet:唯一"反向"注册的组件
- kubelet 以 systemd 服务跑在 worker 上,拿着证书阶段预签的 kubelet 证书与 kubeconfig 向 apiserver 注册 Node 对象——KHW 全程手工签发证书,不走 bootstrap token(生产里的 TLS bootstrapping 是把这一步自动化);
- 卡点:kubelet 起了但节点 NotReady → 十有八九 CNI 没就绪或
node-status-update-frequency与 controller-manager 的容忍时间窗没对齐; - 收获:节点"上线"的本质是 kubelet 成功向 apiserver 注册 Node 对象并开始心跳,与容器运行时无关。
3.5、Pod 网络:路由表即 overlay
# 本地变体(无云网络)用路由打通 Pod CIDR:
ip route add 10.200.1.0/24 via <worker1内网IP> dev eth0
ip route add 10.200.2.0/24 via <worker2内网IP> dev eth0
不用 VXLAN、不用 Calico,纯静态路由让跨节点 Pod 互通。CNI 插件做的本质事情就是自动化这件事(加上策略与封装)。亲手配完路由再装 Calico,你会对 ip route/iptables/conntrack 心存敬畏。
4、快速上手:三种姿势
| 玩法 | 方式 | 适合 |
|---|---|---|
| 官方原版 | 官方教程(jumpbox + 1 controller + 2 worker,本地 VM/物理机) | 跟原味 |
| 本地 VirtualBox/Vagrant 版 | 社区 fork(如 mmumshad/kubernetes-the-hard-way) | 自动拉起本地环境 |
| 自己来 | 不看教程,只看架构图盲搭,卡住再查 | 二刷进阶 |
一刷建议:完全照做、逐条理解参数含义(每条 flag 查官方文档一行);二刷建议:盲搭 + 故意制造故障(删证书、停 etcd、错配 SAN)练习排障。
5、与"简单方式"的对照收获
做完 hard way,回头看 kubeadm 的输出,每一步都能对上:
kubeadm init
= ②证书生成(/etc/kubernetes/pki)
+ ③本机 etcd(或外部)
+ ④⑤apiserver+RBAC 静态 Pod 清单
+ ⑥其余组件静态 Pod
+ bootstrap token(你手工写 kubeconfig 的自动化)
托管云(GKE/EKS/ACK)= 以上全部 + 节点池管理 + 升级编排。"简单"只是把复杂度转移给了平台,理解成本并没有消失——它变成你的排障盲区。hard way 做的就是把这些盲区点亮。
6、生产实践视角
- 证书轮换:手工集群一年后集体过期(apiserver 日志
certificate has expired)——生产务必配自动轮换(cert-manager + 自建 CA,或 kubelet 的 rotate 机制);hard way 让你理解为什么到期的是"那几张"; - 组件参数不要抄旧版:教程版本的 flag 与你生产版本可能差异巨大(如
--container-runtime=remote已废弃);以目标版本kube-apiserver --help为准; - 控制面 LB:手工搭的 VIP(haproxy/keepalived)就是生产高可用的雏形;云上换成内网 SLB 即可,健康检查路径
/healthz不变; - 别在生产手搓:hard way 是教学。生产用 kubeadm/托管——但手搓过的运维,用 kubeadm 时知道每一步在验证什么。
7、面试高频问答
- Q:apiserver 的证书 SAN 为什么要包含 Service IP? A:集群内组件(kube-proxy、CoreDNS、普通 Pod)通过
kubernetes.default.svc(解析为 Service CIDR 首地址)访问 apiserver,TLS 握手时校验的就是这个 IP 的 SAN——漏了它,所有集群内客户端都会证书校验失败。 - Q:scheduler 和 controller-manager 为什么不用静态 Pod 也行? A:它们是纯客户端(只连 apiserver,不对外提供服务),以 systemd 进程跑是最简形态;K8s 发行版用静态 Pod 是为了自管理(升级/重启自动化),不是功能必需。
- Q:kubelet TLS bootstrap 流程? A:首次启动用低权限 bootstrap token 的 kubeconfig → apiserver 认证并自动批准 CSR → kubelet 拿到专属节点证书 → 后续以节点身份通信。生产可配自动批准 controller 或手动
kubectl certificate approve。 - Q:手工集群上
kubectl get nodesNotReady 第一查什么? A:CNI 是否就绪(kubelet 日志 "network plugin not ready");再看 kube-proxy 与 Pod CIDR 分配(/run/flannel/subnet.env或 controller-manager 的--allocate-node-cidrs+--cluster-cidr配置)。
8、总结
kubernetes-the-hard-way 的价值不是"学会装集群",而是把 K8s 从魔法还原为工程:一堆证书、几个 systemd 服务、一台 etcd、一个负载均衡。此后你再遇到任何组件异常,都有心理模型去定位。建议与第 5 篇(架构原理)、第 10 篇(etcd)、第 24 篇(minikube 日常实验)连读,形成"原理—手工—日常"的完整闭环。
9、参考资料
- 官方教程:https://github.com/kelseyhightower/kubernetes-the-hard-way
- 本地变体:https://github.com/mmumshad/kubernetes-the-hard-way
- K8s 证书体系:https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/cluster-management/
- 本系列第 5 篇(声明式架构)、第 10 篇(etcd)


