kubeadm —— K8s 集群引导工具
一句话定义
kubeadm 不是 K8s 的"管理工具",而是集群安装工具:把一堆裸机/虚拟机变成可用的 K8s 集群。装完之后 kubeadm 就退场了,日常管理用 kubectl。
典型场景
训练营 Day1 用 kubeadm 做完整 K8s HA 集群(3 控制面 + 2 worker)。后续也用它:
- Day1:
kubeadm init起第一个控制面 - Day1:
kubeadm join把另外 4 个节点加进来 - Day2:
kubeadm token create重新生成 join token - Day12:
kubeadm certs renew all续证书(默认有效期 1 年) - Day14:
kubeadm upgrade升级集群版本 - 故障:
kubeadm reset把节点恢复到加群前状态
kubeadm 做的事 / 不做的事
✅ kubeadm 做
- 装控制面:apiserver、controller-manager、scheduler、etcd(静态 pod 形式)
- 生成 PKI(一整套 TLS 证书)
- 配置 kubelet
- 生成 admin.conf(管理员 kubeconfig)
- 设置网络 / kube-proxy 基础
❌ kubeadm 不做
- 不装 CNI 网络插件(Calico / Cilium / Flannel 要你自己 apply)
- 不装 metrics-server、dashboard、ingress
- 不管节点 OS(hostname、防火墙、swap、内核模块等要你自己搞定,Day0 干的)
- 不管 high-availability load balancer(HA 控制面前面那个 VIP / HAProxy)
kubeadm 是"集群骨架",不是"开箱即用的产品"。骨架装完上面还要叠很多东西。
init —— 起第一个控制面
最小命令:
kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
--apiserver-advertise-address=10.0.24.28
| 参数 | 含义 |
|---|---|
--pod-network-cidr | pod 用的 IP 段(CNI 决定,常见 10.244.0.0/16) |
--service-cidr | service ClusterIP 段(默认 10.96.0.0/12,一般不动) |
--apiserver-advertise-address | apiserver 监听的 IP(多网卡时必须明确) |
--control-plane-endpoint | HA 用:VIP / 域名 |
--upload-certs | HA 用:把控制面证书上传到 secret 供其它 cp 拉 |
跑完之后的输出
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 10.0.24.28:6443 --token abc.def... \
--discovery-token-ca-cert-hash sha256:...
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
kubeadm join 10.0.24.28:6443 --token abc.def... \
--discovery-token-ca-cert-hash sha256:... \
--control-plane --certificate-key xxxx
这段输出存下来:里面有 worker join token 和 control-plane join 命令。后面要用。
init 之后必做:装 CNI
集群起来但 CoreDNS 一直 Pending。因为没 CNI。
# Cilium(推荐)
helm install cilium cilium/cilium -n kube-system
# 或 Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/calico.yaml
CNI 起来后 CoreDNS 才能跑、节点才会变 Ready。
init 之后做:admin.conf 拷贝
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
或者直接:
export KUBECONFIG=/etc/kubernetes/admin.conf
/etc/kubernetes/admin.conf 是 cluster-admin 凭证 —— 能干一切,千万别泄漏。
HA 控制面:--control-plane-endpoint
3 控制面 HA 模式:
# 第 1 个 cp 节点
kubeadm init \
--control-plane-endpoint "k8s-api.local:6443" \ # ← VIP / 负载均衡 / 域名
--upload-certs \ # ← 把证书上传到 secret
--pod-network-cidr=10.244.0.0/16
--control-plane-endpoint 是关键:
- 写VIP 或 LB 域名,不是某台机器的 IP
- 所有 kubeconfig / 节点配置里 apiserver 都指向这个 endpoint
- 第一个 cp 挂了,VIP 切到另一个 cp、其它节点无感
--upload-certs 把 PKI 上传到 kube-system 命名空间的 secret(24 小时有效),后续 cp 节点 join 时能下载。
其它 2 个 cp 节点加入
kubeadm join k8s-api.local:6443 \
--token abc.def... \
--discovery-token-ca-cert-hash sha256:... \
--control-plane \ # ← 关键:作为控制面加入
--certificate-key xxxx # ← upload-certs 给的 key
worker 节点加入
kubeadm join k8s-api.local:6443 \
--token abc.def... \
--discovery-token-ca-cert-hash sha256:...
不带 --control-plane 就是 worker。
VIP 怎么搞
kubeadm 不提供 VIP,要你自己:
- 物理硬件:F5 / 硬件 LB
- 云:cloud load balancer(AWS NLB、阿里云 SLB)
- 自建:kube-vip、keepalived + haproxy
训练营 Day1 用 kube-vip:3 个控制面之间选举一个持有 VIP,挂了自动 failover。
token 管理
看现有 token
kubeadm token list
# TOKEN TTL EXPIRES USAGES
# abc.def... 23h 2026-05-28T13:23:00 authentication,signing
默认 token TTL 24 小时。过了就 join 不了新节点。
重新生成
kubeadm token create
# new.token.value...
kubeadm token create --print-join-command
# kubeadm join 10.0.24.28:6443 --token ... --discovery-token-ca-cert-hash sha256:...
--print-join-command 直接生成可以复制粘贴的 join 命令,强烈推荐用这个。
永久 token(不要在生产用)
kubeadm token create --ttl=0
# 0 = 永不过期;只在实验环境用
删 token
kubeadm token delete abc.def...
证书续期:certs renew
kubeadm 集群默认所有证书 1 年有效(除了 etcd CA 是 10 年)。过期的话整个集群挂。
看证书状态
kubeadm certs check-expiration
# CERTIFICATE EXPIRES RESIDUAL TIME
# admin.conf May 27, 2027 10:00 UTC 364d
# apiserver May 27, 2027 10:00 UTC 364d
# apiserver-etcd-client May 27, 2027 10:00 UTC 364d
# apiserver-kubelet-client May 27, 2027 10:00 UTC 364d
# controller-manager.conf May 27, 2027 10:00 UTC 364d
# etcd-healthcheck-client May 27, 2027 10:00 UTC 364d
# etcd-peer May 27, 2027 10:00 UTC 364d
# etcd-server May 27, 2027 10:00 UTC 364d
# front-proxy-client May 27, 2027 10:00 UTC 364d
# scheduler.conf May 27, 2027 10:00 UTC 364d
生产至少每半年跑一次 check。
续期
kubeadm certs renew all # 续所有
kubeadm certs renew apiserver # 续单个
# 续完要重启控制面 pod 让新证书生效
systemctl restart kubelet # kubelet 会重建静态 pod
# 或者手动重启容器
crictl ps | grep -E "kube-apiserver|controller-manager|scheduler" \
| awk '{print $1}' | xargs -r crictl stop
# kubelet 自动拉起新的,加载新证书
CKA / CKS 必考题。Day12 演练。
自动续期:kubelet RotateCertificates
kubelet 自己的证书可以自动续:
# /var/lib/kubelet/config.yaml
rotateCertificates: true
serverTLSBootstrap: true
控制面证书自动续:kubeadm upgrade 时会续。
reset —— 把节点拆干净
kubeadm reset
# 提示输入 y 确认;删 manifests、etcd、kubelet 配置等
kubeadm reset -f # 不提示
reset 只删 kubeadm 创建的东西。要彻底清干净:
kubeadm reset -f
# 清 CNI 残留
rm -rf /etc/cni/net.d
ip link delete cni0 2>/dev/null
ip link delete flannel.1 2>/dev/null
ip link delete cilium_* 2>/dev/null
# 清 iptables / ipvs
iptables -F && iptables -X
iptables -t nat -F && iptables -t nat -X
iptables -t mangle -F && iptables -t mangle -X
ipvsadm -C 2>/dev/null
# 清 kubelet 残留状态
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/
rm -rf /etc/kubernetes/
rm -rf $HOME/.kube/
Day1 init 失败了排错时常做这个全套,否则一堆残留状态混进新集群。
upgrade —— 升集群版本
整体流程(详见 Day14):
# 第 1 步:升 kubeadm 包本身(每个节点)
apt-mark unhold kubeadm
apt-get install -y kubeadm=1.29.3-1.1
apt-mark hold kubeadm
# 第 2 步:在第一个 cp 节点看升级计划
kubeadm upgrade plan
# 显示能升到哪个版本
# 第 3 步:在第一个 cp 节点真升
kubeadm upgrade apply v1.29.3
# 第 4 步:其它 cp 节点
kubeadm upgrade node
# 第 5 步:升 kubelet(每个节点)
apt-mark unhold kubelet kubectl
apt-get install -y kubelet=1.29.3-1.1 kubectl=1.29.3-1.1
apt-mark hold kubelet kubectl
systemctl daemon-reload && systemctl restart kubelet
# 第 6 步:worker 节点
kubeadm upgrade node # 在 worker 上跑
# 然后同样升 kubelet
严格规则:
- 一次只升一个 minor 版本(1.28 → 1.29,不能直接 1.28 → 1.30)
- 控制面必须比 worker 不低于一个 minor(control plane 永远 ≥ worker)
- 升级前先备份 etcd(详见 etcdctl.md)
init 之后的健康检查 checklist
# 1. 节点 Ready
kubectl get nodes
# m1 Ready control-plane ...
# 2. 控制面静态 pod
kubectl get pods -n kube-system
# kube-apiserver-m1, kube-controller-manager-m1, kube-scheduler-m1, etcd-m1, kube-proxy-xxx, coredns-xxx
# 3. etcd 健康
kubectl exec -n kube-system etcd-m1 -- etcdctl \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--cert /etc/kubernetes/pki/etcd/server.crt \
--key /etc/kubernetes/pki/etcd/server.key \
endpoint health
# 4. 证书 OK
kubeadm certs check-expiration
# 5. CNI 起来(CoreDNS Running,不是 Pending)
kubectl get pod -n kube-system -l k8s-app=kube-dns
静态 pod manifest 位置
kubeadm 把控制面装成静态 pod(kubelet 直接管,不经 apiserver):
/etc/kubernetes/manifests/
├── etcd.yaml
├── kube-apiserver.yaml
├── kube-controller-manager.yaml
└── kube-scheduler.yaml
改这里的 yaml → kubelet 自动重启对应 pod。
举个例子:apiserver 加个 admission plugin:
vim /etc/kubernetes/manifests/kube-apiserver.yaml
# 改 --enable-admission-plugins
# 保存退出 → 几秒后 apiserver 自动重启加载新参数
重大陷阱:写错了 yaml → kubelet 起不来 apiserver → 控制面挂 → kubectl 不能用。修法:物理 console 登节点、改回 yaml、kubelet 自动恢复。
训练营 Day3 / Day4 经常改这些 yaml。改前 backup:
cp /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/kas.yaml.bak。
常见踩坑
坑 1:init 失败,常见原因
[ERROR Swap]: running with swap on is not supported. Please disable swap
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: ...
[ERROR CRI]: container runtime is not running
修:
# 关 swap
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
# 内核模块 / 参数
modprobe br_netfilter
echo "br_netfilter" > /etc/modules-load.d/k8s.conf
cat > /etc/sysctl.d/k8s.conf <<'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
# containerd 起来
systemctl enable --now containerd
crictl info # 验证
坑 2:CRI 配置不对,kubelet 起不来
containerd 装完默认配置可能不工作。生成默认配置 + 改 cgroup driver:
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
# 改 SystemdCgroup = true
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd
K8s 1.22+ 强制 cgroup driver = systemd。
坑 3:join 之后节点 NotReady
NAME STATUS ROLES AGE VERSION
m4 NotReady <none> 1m v1.28.0
99% 是 CNI 没装。看 kubelet 日志:
journalctl -u kubelet -n 50 | grep -i 'network\|cni'
# cni plugin not initialized
装 CNI:
kubectl apply -f https://...calico.yaml
# 几十秒后节点变 Ready
坑 4:第二台 cp join 报"discovery-token-ca-cert-hash 错误"
token 过期了。在 cp1 重新生成:
kubeadm token create --print-join-command
# 拿到新的 join 命令
# 如果是 cp 加入,还要新 cert key
kubeadm init phase upload-certs --upload-certs
# 给你新的 certificate-key
# 拼成完整命令
kubeadm join ... --token <new> --discovery-token-ca-cert-hash <new> \
--control-plane --certificate-key <new>
坑 5:reset 之后再 join 报"already exists"
reset 没清干净 iptables / CNI 残留。见上面"reset 清理脚本"。
坑 6:以为可以跳版本升级
kubeadm upgrade apply v1.30.0 # 当前 v1.28.x
# 报错:can only upgrade by one minor version
必须 1.28 → 1.29 → 1.30 一步一步。
坑 7:证书续完不重启控制面
kubeadm certs renew all
# 续完了,但 apiserver 还在用内存里旧证书
kubectl get nodes
# x509: certificate has expired
续完必须重启控制面 pod。改 manifest 时间戳 + kubelet 会自动重启:
touch /etc/kubernetes/manifests/kube-apiserver.yaml
# 或干脆
systemctl restart kubelet
坑 8:init 时 --apiserver-advertise-address 没指定,挑了错的网卡
多网卡机器(公网 IP + 内网 IP)kubeadm 可能选公网 IP 作 advertise,集群内通信不通。
多网卡必须显式指定内网 IP:
kubeadm init --apiserver-advertise-address=10.0.24.28 ...
关联命令
- kubectl —— 集群装完之后日常用
- crictl —— kubelet 找不到镜像 / 容器没起时排错
- etcdctl —— 备份 etcd、升级前必做
- systemctl —— 管 kubelet 服务
- journalctl —— 看 kubelet / containerd 日志