Ubuntu 22.04高可用Kubernetes 1.34集群部署(3 Master节点)
Kubernetes 1.34 高可用集群部署完全指南(小白也能看懂)
摘要:本文从零开始,教你在 Ubuntu 22.04 上部署一套包含 3 个 Master 节点的高可用 Kubernetes 1.34 集群。每个术语都会先解释,每个命令都会说明为什么要这么做。即使你完全没接触过 K8s,跟着走也能跑通。所有命令实测可过。
适用版本:Kubernetes 1.34,Ubuntu 22.04 LTS
零、读前必看
0.1 这篇教程适合谁
- ✅ 完全没接触过 K8s 的小白
- ✅ 部署过单机 K8s,想升级到 HA
- ✅ 公司需要私有化部署 K8s 集群
- ❌ 生产环境(生产请看 CNCF Kubernetes 最佳实践)
0.2 你需要准备什么
| 项目 | 要求 |
|---|---|
| 操作系统 | Ubuntu 22.04 LTS(必须是 22.04,其他版本命令可能不同) |
| 机器数量 | 至少 3 台(推荐 5 台:3 Master + 2 Worker) |
| 机器配置 | Master 至少 2 核 4GB / Worker 至少 2 核 4GB |
| 网络 | 所有机器在同一局域网内,能互相 ping 通 |
| 权限 | 全部需要 root 权限(用 sudo 或直接登录 root) |
| 公网 | 所有机器都能访问互联网(用于下载镜像和软件) |
小白解释:K8s 集群需要至少 3 台 Master 节点是为了"高可用"——如果只有 1 台 Master,这台机器挂了整个集群就废了。3 台 Master 允许其中 1 台挂了,剩下 2 台还能继续工作(这就是后面要讲的"集群投票机制")。
一、什么是高可用 K8s
1.1 普通 K8s 集群的隐患
如果你只有 1 个 Master 节点:
┌─────────────────┐
│ Master 节点 │
│ ┌────────────┐ │
│ │ API Server │ │
│ │ Scheduler │ │
│ │ etcd │ │
│ └────────────┘ │
└─────────────────┘
│
▼
Worker 节点
这台 Master 一旦宕机,整个集群就废了——所有 Worker 节点失去控制平面,无法调度新 Pod、无法响应 kubectl 命令。
1.2 高可用集群(HA Cluster)
高可用 = 多个 Master 节点同时提供服务,一台挂了其他顶上:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Master1 │ │ Master2 │ │ Master3 │
│ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌──────────┐ │
│ │API Server│ │ │ │API Server│ │ │ │API Server│ │
│ │Scheduler │ │ │ │Scheduler │ │ │ │Scheduler │ │
│ │etcd 节点 │ │ │ │etcd 节点 │ │ │ │etcd 节点 │ │
│ └──────────┘ │ │ └──────────┘ │ │ └──────────┘ │
└──────────────┘ └──────────────┘ └──────────────┘
▲ ▲ ▲
└───────────────┴───────────────┘
│
VIP: 192.168.1.100
(虚拟 IP,永远指向活着的 Master)
│
▼
┌──────────────┐
│ Worker │
└──────────────┘
关键概念:
| 术语 | 含义 |
|---|---|
| Master 节点 | K8s 控制平面(大脑),负责调度、存储集群状态 |
| Worker 节点 | K8s 数据平面(手脚),跑实际业务容器 |
| etcd | K8s 的数据库,存所有集群数据 |
| VIP | 虚拟 IP,所有 Master 共用一个浮动 IP,永远指向"活着的 Master" |
| kubeadm | K8s 官方提供的集群初始化工具 |
| kubelet | 每台机器上跑的 K8s 代理,负责跟 API Server 通信 |
1.3 本教程用到的组件
| 组件 | 作用 | 为什么用它 |
|---|---|---|
| Ubuntu 22.04 | 操作系统 | 稳定、与 K8s 兼容性好 |
| containerd | 容器运行时 | K8s 1.30+ 默认运行时,比 Docker 轻 |
| kubeadm | K8s 初始化工具 | 官方工具,标准化 |
| Cilium | 网络插件(替代 Calico) | 性能更好,支持 eBPF |
| HAProxy | 负载均衡 | 把请求分发到多个 Master |
| Keepalived | VIP 漂移 | Master 之间"抢"虚拟 IP |
小白解释:组件之间的关系就像一家公司—— - kubeadm = 公司筹备组,负责把公司搭起来 - containerd = 仓库,用来存放集装箱(容器) - Cilium = 快递公司网络,负责不同机器间的集装箱调度 - HAProxy + Keepalived = 总机 + 备用总机,保证电话永远有人接
二、规划你的集群
2.1 机器清单
| 主机名 | IP 地址 | 角色 | 配置 | 跑的服务 |
|---|---|---|---|---|
| k8s-master1 | 192.168.1.10 | Master | 2 核 4GB | kubelet, API Server, etcd, HAProxy, Keepalived |
| k8s-master2 | 192.168.1.11 | Master | 2 核 4GB | kubelet, API Server, etcd, HAProxy, Keepalived |
| k8s-master3 | 192.168.1.12 | Master | 2 核 4GB | kubelet, API Server, etcd, HAProxy, Keepalived |
| k8s-node1 | 192.168.1.13 | Worker | 2 核 4GB | kubelet, containerd |
| k8s-node2 | 192.168.1.14 | Worker | 2 核 4GB | kubelet, containerd |
| VIP | 192.168.1.100 | - | - | 浮动 IP,永远指向活着的 Master |
为什么 3 个 Master? K8s 用 Raft 协议做集群决策,需要"大多数同意"才能做决定。3 个节点的"大多数"是 2 个;5 个节点的"大多数"是 3 个。所以: - 3 个 Master:能容忍 1 个挂掉(剩 2 个能继续工作) - 5 个 Master:能容忍 2 个挂掉 - 绝对不要用偶数(4/6 个)——偶数时一旦网络分割成两半,可能两边都凑不够"大多数"
2.2 网络规划
| 网络段 | CIDR | 用途 |
|---|---|---|
| 节点物理网络 | 192.168.1.0/24 | 5 台机器所在的局域网 |
| Pod 网络 | 10.244.0.0/16 | K8s 给 Pod 分配的 IP 段(每个 Pod 一个独立 IP) |
| Service 网络 | 10.96.0.0/12 | K8s 给 Service 分配的 IP 段(Service 是 Pod 的"门牌号") |
小白解释:K8s 给每个 Pod 分配独立 IP(默认是 10.244.x.x),不同机器上的 Pod 能像在同一台机器一样互相访问——这是 K8s 最神奇的能力,由网络插件(Cilium)实现。
三、所有机器的前期准备
下面的命令在 5 台机器上都要执行一遍。我推荐用 ssh 批量执行或者用 Ansible,但小白可以一台一台手动来。
3.1 配置主机名和 hosts
# 每台机器设置自己的主机名(以 master1 为例)
sudo hostnamectl set-hostname k8s-master1
# 所有机器都加这些 hosts(让机器间能通过名字找到对方)
sudo tee -a /etc/hosts << 'EOF'
192.168.1.10 k8s-master1
192.168.1.11 k8s-master2
192.168.1.12 k8s-master3
192.168.1.13 k8s-node1
192.168.1.14 k8s-node2
EOF
# 验证(每台机器都要能 ping 通其他 4 台)
ping -c 2 k8s-master2
坑点:如果你用云服务器,内网 IP和公网 IP是不一样的。这里用内网 IP(192.168.x.x 或云厂商的 10.x.x.x),因为 K8s 内部通信走内网。
3.2 关闭 swap(必须!)
K8s 要求关闭 swap,否则 kubelet 会拒绝启动:
# 立即关闭 swap
sudo swapoff -a
# 永久关闭(注释掉 /etc/fstab 里的 swap 行)
sudo sed -i '/ swap / s/^/#/' /etc/fstab
# 验证
free -h
# 输出应该看不到 Swap 这一行,或者显示 0
小白解释:swap 是 Linux 的"虚拟内存",把磁盘当内存用。但 K8s 需要精确控制内存用量,swap 会让控制变得不精确,所以 K8s 要求关闭。
3.3 加载内核模块 + 网络配置
K8s 网络需要几个内核模块:
# 创建 modules 配置文件
sudo tee /etc/modules-load.d/k8s.conf << 'EOF'
overlay
br_netfilter
EOF
# 立即加载
sudo modprobe overlay
sudo modprobe br_netfilter
# 配置网络转发(让 Pod 之间能跨机器通信)
sudo tee /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
# 立即生效
sudo sysctl --system
小白解释:
br_netfilter让网桥(bridge)也能被 iptables 规则管理;ip_forward允许 Linux 像路由器一样转发 IP 包。这两个不开,K8s 网络就跑不起来。
3.4 配置时间同步
K8s 各节点时间必须一致(差不能超过 1 分钟),否则证书会报错:
# 安装 chrony
sudo apt-get install -y chrony
# 启动并设置开机启动
sudo systemctl enable --now chrony
# 验证(每台机器都跑一遍)
chronyc tracking
# 显示 "Last offset" 应该在 ±0.01 秒内
四、安装 containerd(所有机器)
containerd 是 K8s 1.30+ 默认的容器运行时(替代 Docker):
# 安装
sudo apt-get update
sudo apt-get install -y containerd
# 生成默认配置
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 关键配置:使用 systemd cgroup 驱动(与 K8s 一致)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
# 配置镜像加速(国内必须,否则拉镜像很慢)
sudo tee /etc/containerd/registries.toml << 'EOF'
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirror.ccs.tencentyun.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://gcr.lank8s.cn"]
EOF
# 重启并设置开机启动
sudo systemctl restart containerd
sudo systemctl enable containerd
# 验证
sudo ctr version
小白解释:cgroup 是 Linux 的资源控制机制(CPU、内存分配)。K8s 用 systemd 管理 cgroup,所以 containerd 必须配合用 systemd cgroup 驱动,否则 K8s 的资源限制会失效。
五、安装 kubeadm、kubelet、kubectl(所有机器)
5.1 添加 Kubernetes 仓库
# 下载 GPG key(用于验证包真实性)
sudo curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 添加 apt 源
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /' | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
# 更新包索引
sudo apt-get update
5.2 安装并锁定版本
# 安装(默认最新 1.34.x)
sudo apt-get install -y kubelet kubeadm kubectl
# 锁定版本(防止 apt upgrade 误升级 K8s 大版本)
sudo apt-mark hold kubelet kubeadm kubectl
# 验证
kubeadm version
kubelet --version
kubectl version --client
小白解释:
apt-mark hold告诉包管理器"不要升级这个包"。K8s 大版本升级需要手动操作,不能apt upgrade一把梭。
六、安装 HAProxy + Keepalived(仅 Master 节点)
这一步只在 3 台 Master 机器上做。Worker 节点不需要。
HAProxy 是负载均衡,Keepalived 是 VIP 漂移工具。两者配合,保证客户端永远能通过 VIP 192.168.1.100 访问到活着的 Master。
6.1 安装
# 3 台 Master 都执行
sudo apt-get install -y haproxy keepalived
6.2 配置 HAProxy
3 台 Master 都用相同的 HAProxy 配置:
sudo tee /etc/haproxy/haproxy.cfg << 'EOF'
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
log global
mode tcp
option tcplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend kube-apiserver
bind *:8443
mode tcp
option tcplog
default_backend kube-apiserver
backend kube-apiserver
mode tcp
option tcplog
option tcp-check
balance roundrobin
default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100
server k8s-master1 192.168.1.10:6443 check
server k8s-master2 192.168.1.11:6443 check
server k8s-master3 192.168.1.12:6443 check
EOF
# 重启
sudo systemctl restart haproxy
sudo systemctl enable haproxy
# 验证(应该看到 LISTEN 在 8443 端口)
sudo ss -tlnp | grep 8443
关键:HAProxy 监听 8443 端口,把请求轮询分发到 3 个 Master 的 6443 端口(6443 是 K8s API Server 默认端口)。所有客户端(kubectl、其他 Master、Worker)都通过 VIP:8443 访问 K8s,而不是直接连某个 Master 的 IP。
6.3 配置 Keepalived
3 台 Master 都装,但要配成"互斥"——同一时间只有一台"持有" VIP。
Master1(优先级 150,抢 VIP):
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
enable_script_security
script_user root
}
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight -30
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.1.10
unicast_peer {
192.168.1.11
192.168.1.12
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_haproxy
}
}
EOF
Master2(优先级 120):
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
enable_script_security
script_user root
}
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight -30
fall 3
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 120
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.1.11
unicast_peer {
192.168.1.10
192.168.1.12
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_haproxy
}
}
EOF
Master3(优先级 100):
sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
enable_script_security
script_user root
}
vrrp_script check_haproxy {
script "/usr/bin/killall -0 haproxy"
interval 2
weight -30
fall 3
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
unicast_src_ip 192.168.1.12
unicast_peer {
192.168.1.10
192.168.1.11
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_haproxy
}
}
EOF
小白解释 VRRP: - VRRP = Virtual Router Redundancy Protocol(虚拟路由冗余协议) - 3 台 Master 之间会互相发"心跳",告诉对方"我还活着" - 优先级最高的 Master(150)持有 VIP 192.168.1.100 - 如果这台 Master 挂了(或 HAProxy 挂了),优先级次高的(120)会"抢"过来 - 整个切换过程大约 5-10 秒,对客户端几乎无感
关键参数说明: -
interface eth0:你的网卡名(不一定是 eth0,用ip a查) -virtual_router_id 51:3 台必须相同,相当于"同一个集群" -auth_pass 1111:3 台必须相同的密码 -unicast_src_ip:本机 IP(用单播通信,避免组播问题) -virtual_ipaddress:VIP 地址
6.4 启动 Keepalived
# 3 台 Master 都执行
sudo systemctl restart keepalived
sudo systemctl enable keepalived
# 验证:在 Master1 上能看到 VIP
ip a show eth0 | grep 192.168.1.100
# 应该看到 inet 192.168.1.100/24
# 其他 Master 上不应该有
# 如果都有,说明 VRRP 没正常工作
如果 VIP 没出现在 Master1 上:检查网络、unicast_peer 配错没、网卡名是否对(不一定是 eth0)。
七、初始化 Master1 节点
只在 master1 上执行:
7.1 准备 kubeadm 配置
# kubeadm 1.30-1.34 使用 v1beta3(stable);v1beta4 在 1.34 已被标记 experimental
cat > kubeadm-config.yaml << 'EOF'
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.1.10 # 本机 IP(master1 的 IP)
bindPort: 6443
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock
imagePullPolicy: IfNotPresent
taints: [] # 允许 Master 也跑业务 Pod(可选,生产建议去掉)
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.34.0
controlPlaneEndpoint: "192.168.1.100:8443" # VIP + HAProxy 端口
apiServer:
timeoutForControlPlane: 4m0s
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
imageRepository: registry.aliyuncs.com/google_containers
imageTag: v1.11.1
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
imageTag: 3.5.12-0
imageRepository: registry.aliyuncs.com/google_containers
networking:
dnsDomain: cluster.local
podSubnet: 10.244.0.0/16 # Pod 网络段
serviceSubnet: 10.96.0.0/12 # Service 网络段
scheduler: {}
EOF
小白解释: -
v1beta3:K8s API 版本。v1beta3 是 K8s 1.30-1.34 的稳定版本,v1beta4 在 1.34 还在实验阶段 -advertiseAddress:告诉集群"我的 API Server 监听在哪个 IP",必须填本机真实 IP -controlPlaneEndpoint:所有客户端访问的入口,是 VIP + HAProxy 端口,不是单台 Master 的 IP
7.2 执行初始化
sudo kubeadm init --config kubeadm-config.yaml --upload-certs
这一步会做这些事:
- 下载 K8s 组件镜像(约 5 分钟)
- 生成证书、kubeconfig
- 启动 API Server、etcd、scheduler、controller-manager
- 输出加入集群的命令(一定保存好!)
成功输出长这样:
Your Kubernetes control-plane has initialized successfully!
To start start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
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/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join 192.168.1.100:8443 --token xxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxxxx \
--control-plane --certificate-key xxxxxx
Please note that the certificate-key gives access to cluster root ca
and should not be shared broadly.
You can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.1.100:8443 --token xxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxxxx
把这两段 join 命令保存下来! 后面加其他 Master 和 Worker 用。
7.3 配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 验证
kubectl get nodes
# 应该看到 master1 状态是 NotReady(还没装网络插件)
八、安装网络插件(Cilium)
还是在 master1 上:
# 用 Cilium 替代 Calico(性能更好,支持 eBPF)
# 1.34 推荐 Cilium 1.16+
# 安装 Cilium CLI
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all \
https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum -c cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
# 安装 Cilium 到集群
cilium install --version 1.16.5
# 等待所有 Pod 就绪(大约 1-3 分钟)
cilium status --wait
# 验证
kubectl get nodes
# 现在 master1 应该是 Ready 状态
为什么用 Cilium 而不是 Calico? - Cilium 基于 eBPF(Linux 内核新特性),性能比 Calico 高 30%+ - 网络策略可视化做得更好(Hubble UI) - K8s 1.30+ 的默认推荐 - Calico 仍然是很多教程在用,但 Cilium 是未来趋势
九、加入其他 Master 节点
在 master2 和 master3 上各执行一次:
# 用 master1 初始化时输出的 control-plane join 命令
sudo kubeadm join 192.168.1.100:8443 \
--token abcdef.1234567890abcdef \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxx \
--control-plane \
--certificate-key xxxxxxxxxx \
--cri-socket=unix:///run/containerd/containerd.sock
# 配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 验证(在 master1 上)
kubectl get nodes
# 应该看到 3 个 master 都是 Ready
坑点:join 命令里的 token 24 小时后会过期。如果过期,在 master1 上重新生成: ``
bash kubeadm token create --print-join-command --certificate-key $(sudo kubeadm certs certificate-key)``
十、加入 Worker 节点
在 node1 和 node2 上各执行一次:
# 用 master1 初始化时输出的 worker join 命令(没有 --control-plane 参数的那个)
sudo kubeadm join 192.168.1.100:8443 \
--token abcdef.1234567890abcdef \
--discovery-token-ca-cert-hash sha256:xxxxxxxxxx \
--cri-socket=unix:///run/containerd/containerd.sock
# 验证(在 master1 上)
kubectl get nodes
# 应该看到 5 个节点都是 Ready
十一、验证集群
在 master1 上:
# 1. 节点状态
kubectl get nodes -o wide
# 输出应该是:
# NAME STATUS ROLES AGE VERSION
# k8s-master1 Ready control-plane 30m v1.34.0
# k8s-master2 Ready control-plane 20m v1.34.0
# k8s-master3 Ready control-plane 20m v1.34.0
# k8s-node1 Ready <none> 10m v1.34.0
# k8s-node2 Ready <none> 10m v1.34.0
# 2. 集群信息
kubectl cluster-info
# 3. 测试应用部署
kubectl create deployment nginx --image=nginx:1.27
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pods,svc
# 4. 测试集群 HA(**危险操作,看清楚**)
# 在 master1 上 shutdown,模拟故障
sudo shutdown -h now
# 用 master2 或 master3 验证 VIP 是否漂移
# 在 client 机器上:
kubectl get nodes --server=https://192.168.1.100:8443
# 应该能看到所有节点(通过 VIP 访问活着的 Master)
# 测试完记得把 master1 启动回来
十二、常见问题排查
12.1 初始化失败:apiVersion v1beta4 not allowed
原因:用了 kubeadm.k8s.io/v1beta4。 解决:改为 kubeadm.k8s.io/v1beta3(K8s 1.34 唯一稳定版本)。
12.2 kubelet 启动失败:failed to load kubelet
原因:swap 没关,或 cgroup 驱动不一致。 解决:
sudo swapoff -a
# 检查 cgroup 配置
sudo grep -E 'SystemdCgroup|cgroup-driver' /etc/containerd/config.toml
# 确保 SystemdCgroup = true
sudo systemctl restart containerd kubelet
12.3 网络插件 Pod 一直 Pending
原因:镜像拉不下来(国内网络)。 解决:手动改镜像源,或配置 containerd mirror。
12.4 VIP 不出现
检查:
# 1. 看 Keepalived 日志
sudo journalctl -u keepalived -f
# 2. 看网卡名(不一定是 eth0)
ip a
# 把 keepalived.conf 里的 interface 改成实际网卡名
# 3. 看 VRRP 通信(用 tcpdump)
sudo tcpdump -i eth0 -nn vrrp
# 应该看到 3 台机器之间互相发 VRRP 心跳包
12.5 kubectl 连不上集群
原因:kubeconfig 配错。 解决:
# 重新拷 admin.conf
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 验证(用 VIP 地址)
kubectl get nodes --server=https://192.168.1.100:8443
十三、日常运维
13.1 查看证书有效期
kubeadm certs check-expiration
# 续期所有证书(**慎用,会重启控制平面**)
kubeadm certs renew all
13.2 节点维护(驱逐 Pod)
# 标记节点不可调度
kubectl cordon k8s-node1
# 驱逐 Pod(自动迁移到其他节点)
kubectl drain k8s-node1 --ignore-daemonsets
# 恢复
kubectl uncordon k8s-node1
13.3 etcd 备份
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-backup.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 恢复
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-backup.db \
--data-dir=/var/lib/etcd-restore
13.4 重新生成 join 命令
kubeadm token create --print-join-command --certificate-key \
$(kubeadm certs certificate-key)
十四、写在最后
到这里,一套完整的 3 Master + 2 Worker 高可用 K8s 1.34 集群就跑起来了。
跟着教程一步步走,理论上 1-2 小时能搞定。如果你卡在某一步,去看:
journalctl -u kubelet -n 50(kubelet 日志)kubectl describe pod xxx(Pod 详情)kubectl get events(集群事件)
进阶方向(推荐下一步学):
- Ingress(Nginx Ingress Controller)
- StorageClass(动态创建 PV)
- MetalLB(裸金属 LoadBalancer)
- Argo CD(GitOps 部署)
- cert-manager(自动签发证书)
- Prometheus + Grafana(监控)
把这套集群用熟,你就是 K8s 中级工程师了。
参考资源:
- Kubernetes 官方文档:https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/
- Cilium 文档:https://docs.cilium.io/
- kubeadm 配置参考:https://kubernetes.io/docs/reference/config-api/kubeadm-config.v1beta3/






