不用 kubeadm:从零用二进制部署一套高可用 Kubernetes 集群
本文基于当前 kubernetes-the-hard-way 仓库整理。目标不是提供一键脚本,而是通过手工部署理解证书、kubeconfig、systemd、容器运行时和 Pod 网络如何组成 Kubernetes 集群。
1. 部署目标
本实验使用 1 台管理机、1 台控制平面和 2 台工作节点:
kubectl
|
v
server:6443
+---------------------------+
| kube-apiserver |
| kube-controller-manager |
| kube-scheduler |
| etcd |
+---------------------------+
|
+---------+---------+
| |
node-0 node-1
containerd/kubelet containerd/kubelet
kube-proxy/CNI kube-proxy/CNI
10.200.0.0/24 10.200.1.0/24这套拓扑只有一个控制平面节点和一个 etcd 成员,适合学习与实验,不具备生产环境所需的高可用能力。
2. 环境与版本
操作系统为 Debian 12(Bookworm),支持 AMD64 和 ARM64。最低资源如下:
| 主机 | 用途 | CPU | 内存 | 磁盘 |
|---|---|---|---|---|
| jumpbox | 管理、签发证书、分发文件 | 1 核 | 512 MB | 10 GB |
| server | etcd 与控制平面 | 1 核 | 2 GB | 20 GB |
| node-0 | 工作节点 | 1 核 | 2 GB | 20 GB |
| node-1 | 工作节点 | 1 核 | 2 GB | 20 GB |
仓库主要使用 Kubernetes v1.32.3、crictl v1.32.0、CNI Plugins v1.6.2、containerd v2.1.x 和 etcd v3.6.x。当前下载清单中的 containerd、etcd、runc 含 beta 或 RC 构建,只应视为实验版本;长期运行时应换成经过验证的稳定版本,并校验 SHA256 或签名。
地址规划如下:
Service CIDR:10.32.0.0/24
Pod CIDR: 10.200.0.0/16
node-0 Pod: 10.200.0.0/24
node-1 Pod: 10.200.1.0/24在 jumpbox 创建 machines.txt,将示例地址改成实际 IP:
192.168.10.10 server.kubernetes.local server
192.168.10.11 node-0.kubernetes.local node-0 10.200.0.0/24
192.168.10.12 node-1.kubernetes.local node-1 10.200.1.0/24三台集群机器必须互通,并可由 jumpbox 通过 SSH 访问。仓库使用 root 简化实验;真实环境应使用普通运维账号配合 sudo,并限制 SSH 来源。
3. 准备管理机和二进制文件
在 jumpbox 安装工具并进入仓库:
apt-get update
apt-get -y install wget curl vim openssl git
git clone --depth 1 \
https://github.com/kelseyhightower/kubernetes-the-hard-way.git
cd kubernetes-the-hard-way根据 Debian 架构下载二进制:
wget -q --show-progress \
--https-only \
--timestamping \
-P downloads \
-i downloads-$(dpkg --print-architecture).txt解压后将程序整理到四类目录:
downloads/client/ kubectl、etcdctl
downloads/controller/ etcd、kube-apiserver、controller-manager、scheduler
downloads/worker/ containerd、runc、crictl、kubelet、kube-proxy
downloads/cni-plugins/ bridge、loopback、host-local 等插件最后增加执行权限:
chmod +x downloads/{client,controller,worker}/*4. 建立集群信任链
二进制部署最重要的不是复制程序,而是建立组件间的身份认证。整个集群共享一个自签名 CA,再为各组件签发证书。仓库 ca.conf 定义了以下身份:
| 证书 | 关键身份 | 用途 |
|---|---|---|
| admin | O=system:masters | 集群管理员 |
| node-0、node-1 | CN=system:node:节点名,O=system:nodes | kubelet 节点认证 |
| kube-proxy | O=system:node-proxier | Service 转发规则 |
| controller-manager | 系统组件身份 | 控制器访问 API Server |
| scheduler | 系统组件身份 | 调度器访问 API Server |
| kube-api-server | 带服务端 SAN | API Server TLS 及访问 kubelet |
| service-accounts | 独立密钥对 | 签发 ServiceAccount Token |
创建 CA:
openssl genrsa -out ca.key 4096
openssl req -x509 -new -sha512 -noenc \
-key ca.key -days 3653 \
-config ca.conf -out ca.crt随后按照 docs/04-certificate-authority.md,为 admin、两个工作节点、kube-proxy、kube-controller-manager、kube-scheduler、kube-api-server 和 service-accounts 生成私钥、CSR 与证书。
这里有两个关键点:
- kubelet 用户名必须是 system:node:NodeName,组织必须是 system:nodes,否则 Node Authorizer 会拒绝请求。
- API Server 证书 SAN 必须覆盖实际访问入口,包括 server.kubernetes.local、服务器 IP、Kubernetes Service 名称和 Service ClusterIP。
证书应按最小权限分发:节点只获取自己的 kubelet 证书和 CA;server 保存控制平面需要的文件;ca.key 等私钥不能无差别复制。
5. 生成 kubeconfig 和 Secret 加密配置
本实验需要 admin、controller-manager、scheduler、kube-proxy、node-0 和 node-1 六类 kubeconfig。以 node-0 为例:
kubectl config set-cluster kubernetes-the-hard-way \
--certificate-authority=ca.crt \
--embed-certs=true \
--server=https://server.kubernetes.local:6443 \
--kubeconfig=node-0.kubeconfig
kubectl config set-credentials system:node:node-0 \
--client-certificate=node-0.crt \
--client-key=node-0.key \
--embed-certs=true \
--kubeconfig=node-0.kubeconfig
kubectl config set-context default \
--cluster=kubernetes-the-hard-way \
--user=system:node:node-0 \
--kubeconfig=node-0.kubeconfig
kubectl config use-context default --kubeconfig=node-0.kubeconfig其他组件同理,只需替换证书和用户。节点配置分别放到 /var/lib/kubelet/kubeconfig 和 /var/lib/kube-proxy/kubeconfig,controller-manager、scheduler 和 admin 配置下发到 server。
为避免 Secret 明文写入 etcd,再创建静态加密配置:
export ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
envsubst < configs/encryption-config.yaml > encryption-config.yaml
scp encryption-config.yaml root@server:~/仓库使用 AES-CBC 加密 Secret,并保留 identity 作为读取旧数据的回退提供者。加密密钥必须单独备份,否则已有加密数据将无法恢复。
6. 部署 etcd
将 etcd、etcdctl 和 etcd.service 复制到 server,随后安装:
mv etcd etcdctl /usr/local/bin/
mkdir -p /etc/etcd /var/lib/etcd
chmod 700 /var/lib/etcd
cp ca.crt kube-api-server.key kube-api-server.crt /etc/etcd/
mv etcd.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now etcd
etcdctl member list实验中的 etcd 仅监听 127.0.0.1:2379,因为它与 API Server 位于同一台机器。这样减少了暴露面,但 server 故障会让整个控制面不可用。生产环境应使用 3 或 5 个 etcd 成员,启用客户端和 Peer TLS,并定期做快照与恢复演练。
7. 部署控制平面
在 server 安装组件并建立目录:
mv kube-apiserver kube-controller-manager \
kube-scheduler kubectl /usr/local/bin/
mkdir -p /etc/kubernetes/config /var/lib/kubernetes将 CA、API Server 证书、ServiceAccount 密钥、加密配置和各组件 kubeconfig 放入 /var/lib/kubernetes,scheduler 配置放入 /etc/kubernetes/config,再安装三个 systemd unit。
API Server 的核心参数包括:
--authorization-mode=Node,RBAC
--etcd-servers=http://127.0.0.1:2379
--encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml
--service-node-port-range=30000-32767
--client-ca-file=/var/lib/kubernetes/ca.crt
--tls-cert-file=/var/lib/kubernetes/kube-api-server.crt
--tls-private-key-file=/var/lib/kubernetes/kube-api-server.keycontroller-manager 负责两个集群网段:
--cluster-cidr=10.200.0.0/16
--service-cluster-ip-range=10.32.0.0/24启动控制平面:
systemctl daemon-reload
systemctl enable --now kube-apiserver kube-controller-manager kube-scheduler
systemctl --no-pager --full status \
kube-apiserver kube-controller-manager kube-schedulerAPI Server 访问 kubelet 还需要 RBAC 授权:
kubectl apply \
--kubeconfig admin.kubeconfig \
-f kube-apiserver-to-kubelet.yaml验证版本和健康状态:
curl --cacert ca.crt https://server.kubernetes.local:6443/version
kubectl get componentstatuses --kubeconfig admin.kubeconfig如启动失败,优先查看日志:
journalctl -u kube-apiserver -u kube-controller-manager \
-u kube-scheduler --since "10 min ago" --no-pager8. 部署 Worker 节点
每个 Worker 都安装 runc、CNI Plugins、containerd、kubelet、kube-proxy 和 crictl。先安装依赖并关闭 Swap:
apt-get update
apt-get -y install socat conntrack ipset kmod
swapoff -a
mkdir -p /etc/cni/net.d /opt/cni/bin \
/var/lib/kubelet /var/lib/kube-proxy \
/var/lib/kubernetes /var/run/kubernetes安装二进制:
mv crictl kube-proxy kubelet runc /usr/local/bin/
mv containerd containerd-shim-runc-v2 containerd-stress /bin/
mv cni-plugins/* /opt/cni/bin/配置 CNI
jumpbox 会将 configs/10-bridge.conf 中的 SUBNET 替换为当前节点网段。node-0 使用 10.200.0.0/24,node-1 使用 10.200.1.0/24。节点上执行:
mv 10-bridge.conf 99-loopback.conf /etc/cni/net.d/
modprobe br-netfilter
echo br-netfilter >> /etc/modules-load.d/modules.conf
echo "net.bridge.bridge-nf-call-iptables = 1" \
>> /etc/sysctl.d/kubernetes.conf
echo "net.bridge.bridge-nf-call-ip6tables = 1" \
>> /etc/sysctl.d/kubernetes.conf
sysctl -p /etc/sysctl.d/kubernetes.conf配置 containerd、kubelet 和 kube-proxy
将 containerd 配置放入 /etc/containerd/config.toml。kubelet 通过 unix:///var/run/containerd/containerd.sock 连接运行时,并使用 systemd cgroup、Webhook 认证授权和独立节点证书。kube-proxy 使用 iptables 模式,clusterCIDR 为 10.200.0.0/16。
安装对应配置和 unit 后启动:
systemctl daemon-reload
systemctl enable --now containerd kubelet kube-proxy
systemctl --no-pager --full status containerd kubelet kube-proxy在 jumpbox 验证节点:
kubectl get nodes --kubeconfig admin.kubeconfig -o widenode-0 和 node-1 应均为 Ready。若长期 NotReady,应检查 kubelet 日志、证书 CN、主机名、containerd Socket、CNI 文件和内核转发配置。
9. 打通跨节点 Pod 网络
本实验不安装 Calico、Cilium 等网络方案,而是用静态路由展示 Kubernetes 的扁平网络模型。按前文示例 IP,在 server 执行:
ip route add 10.200.0.0/24 via 192.168.10.11
ip route add 10.200.1.0/24 via 192.168.10.12node-0 指向 node-1:
ip route add 10.200.1.0/24 via 192.168.10.12node-1 指向 node-0:
ip route add 10.200.0.0/24 via 192.168.10.11用 ip route 检查结果。直接添加的路由会在重启后丢失,正式环境应写入系统网络配置,或部署成熟 CNI。
10. 配置 kubectl 并验收
在管理机配置管理员凭据:
mkdir -p ~/.kube
cp admin.kubeconfig ~/.kube/config
kubectl cluster-info
kubectl get nodes验证 Secret 静态加密
kubectl create secret generic kubernetes-the-hard-way \
--from-literal=mykey=mydata
ssh root@server \
"etcdctl get /registry/secrets/default/kubernetes-the-hard-way | hexdump -C"etcd 原始数据中不应直接出现 mydata,并应能看到加密提供者前缀。
验证 Deployment、日志与远程执行
kubectl create deployment nginx --image=nginx:latest
kubectl get pods -l app=nginx -o wide
POD_NAME=$(kubectl get pods -l app=nginx \
-o jsonpath="{.items[0].metadata.name}")
kubectl logs "$POD_NAME"
kubectl exec -ti "$POD_NAME" -- nginx -v验证端口转发
kubectl port-forward deployment/nginx 8080:80
curl --head http://127.0.0.1:8080返回 HTTP 200,说明 API Server 到 kubelet 的流式连接正常。
验证 Service 与 NodePort
kubectl expose deployment nginx --port 80 --type NodePort
NODE_PORT=$(kubectl get svc nginx -o jsonpath='{.spec.ports[0].nodePort}')
NODE_NAME=$(kubectl get pods -l app=nginx \
-o jsonpath='{.items[0].spec.nodeName}')
curl -I "http://$NODE_NAME:$NODE_PORT"能拿到 nginx 响应头,说明 kube-proxy、iptables、Service 和节点网络均已打通。
11. 故障排查顺序
二进制部署问题通常集中在四类:
- 证书:用 openssl x509 检查有效期、CN、组织和 SAN,并确认所有主机时间同步。
- 服务参数:用 systemctl status 和 journalctl 查看启动参数、文件路径及权限。
- 节点运行时:检查 crictl info、containerd Socket 和 cgroup 驱动。
- 网络:检查 ip route、CNI 配置、br_netfilter、sysctl 和 iptables 规则。
建议严格按依赖链排查:
etcd
-> kube-apiserver
-> controller-manager / scheduler
-> containerd / kubelet
-> CNI / Pod 路由
-> kube-proxy / Service上游组件未恢复时,不必反复重启下游。例如 API Server 不可用时,kubelet 和 controller-manager 必然持续报连接错误。
12. 距离生产环境还差什么
完成以上步骤只说明 Kubernetes 核心链路已经跑通。生产环境至少还要补齐:
- • 三节点控制平面和奇数成员 etcd 集群;
- • API Server 前置负载均衡和稳定入口;
- • 成熟 CNI、CoreDNS 和集群内 DNS;
- • etcd 快照、证书轮换、升级及灾难恢复流程;
- • 镜像仓库、准入控制、NetworkPolicy、Pod Security 和审计策略;
- • 监控、日志、告警、容量管理与资源配额;
- • 稳定版组件、制品校验、配置管理和自动化交付。
二进制部署的价值不是把安装过程复杂化,而是让 Kubernetes 不再是黑盒:证书定义身份,kubeconfig 描述访问关系,API Server 连接控制逻辑,etcd 保存状态,kubelet 与运行时负责落地容器,CNI 和 kube-proxy 连接 Pod 与 Service 网络。理解这条链路后,无论使用 kubeadm、RKE2 还是云厂商托管集群,排障都会更有方向。
二进制部署并不神秘。把它拆开看,就是下载安装、PKI、etcd、控制平面、容器运行时、节点组件、CNI、DNS和负载均衡。
真正决定集群能否进入生产的,不是 systemctl status 全部变绿,而是每一层都有可验证的结果,每一次有状态变更都有备份、灰度、停止条件和回滚路径。
如果你准备动手,今天可以先做一件事:画出自己的节点、VIP、Pod CIDR、Service CIDR 和端口规划图,再开始生成证书。这个顺序能避开二进制部署中相当一部分返工。
如果这篇文章对你有帮助,欢迎点赞、在看、关注并转发给正在学习 Kubernetes 的同事。后续我还会继续整理证书签发、etcd 灾备、Kubernetes 升级和 Calico 排障等生产实践。
公众号:耕云躬行录
个人博客:躬行笔记
参考项目:Kelsey Hightower 的 kubernetes-the-hard-way。本文命令与版本按当前本地仓库整理,实际执行请以仓库内 docs、units、configs 和对应架构下载清单为准。
参考文档:https://github.com/kelseyhightower/kubernetes-the-hard-way/tree/master
参考项目:Kelsey Hightower 的 kubernetes-the-hard-way。本文命令与版本按当前本地仓库整理,实际执行请以仓库内 docs、units、configs 和对应架构下载清单为准。