场景:本集群(测试环境 192.168.6.36,k8s v1.29.2)使用 kube-vip 作为 API Server 的高可用入口,VIP 192.168.6.249 绑定 eth0,端口 6443。kube-vip 通过 ARP + Leader Election 在 master 节点间漂移 VIP,任意一台 master 宕机 VIP 自动切换。
部署范围:5 台 master(k8s-master / master01 / master02 / master03 / master04)。worker 节点不部署,它们不提供 API 入口。
一、两种部署方式选型
DaemonSet 方式
-
支持 imagePullSecrets(普通 pod,无限制)
-
kubectl 完全可管理,支持滚动更新
-
新节点加入自动调度
-
依赖 API Server 可用(控制器需要调度)
-
适合集群运行稳定后的管理场景
Static Pod 方式
-
不支持 imagePullSecrets(mirror pod 被 API Server 拒绝,详见排障一节)
-
不依赖 API Server,kubelet 直接读 manifests 文件拉起
-
适合集群 bootstrap 阶段,或 API 不可用时兜底
-
每台 master 手动放文件,新节点要手动补
结论:集群已经在运行、API 可用,用 DaemonSet 最省心。如果是"从零搭集群、API 还没起来"的场景,用 Static Pod。
二、DaemonSet 方式部署(推荐)
1. 确认镜像
crictl images | grep kube-vip
# 期望输出 harbor.wulaoer.org/ops/kube-vip v0.6.2
镜像和 secret 依赖 harbor,如果 harbor 密码轮换过,先确认 kube-system 的 eft-image-auth 凭据是否仍有效(见排障一节)。
2. manifest 文件
apiVersionapps/v1
kindDaemonSet
metadata
namekube-vip
namespacekube-system
spec
selector
matchLabels
app.kubernetes.io/namekube-vip
template
metadata
labels
app.kubernetes.io/namekube-vip
spec
# 关键:只调度到 control-plane 节点,worker 不会跑
affinity
nodeAffinity
requiredDuringSchedulingIgnoredDuringExecution
nodeSelectorTerms
matchExpressions
keynode-role.kubernetes.io/control-plane
operatorExists
tolerations
keynode-role.kubernetes.io/control-plane
operatorExists
effectNoSchedule
containers
namekube-vip
imageharbor.wulaoer.org/ops/kube-vipv0.6.2
imagePullPolicyIfNotPresent
imagePullSecrets
nameeft-image-auth
env
namevip_arp
value"true"
nameport
value"6443"
namevip_interface
valueeth0
namevip_cidr
value"32"
namecp_enable
value"true"
namecp_namespace
valuekube-system
namesvc_enable
value"true"
namevip_leaderelection
value"true"
namevip_leasename
valueplndr-cp-lock
namevip_leaseduration
value"5"
namevip_renewdeadline
value"3"
namevip_retryperiod
value"1"
namevip_address
value192.168.6.249
nameprometheus_server
value2112
securityContext
capabilities
add
NET_ADMIN
NET_RAW
volumeMounts
mountPath/etc/kubernetes/admin.conf
namekubeconfig
hostNetworktrue
volumes
hostPath
path/etc/kubernetes/admin.conf
namekubeconfig
几个要点:
-
nodeAffinity 限制 node-role.kubernetes.io/control-plane,DaemonSet 只会调度到 master
-
tolerations 容忍 master 的 NoSchedule 污点,否则调度不上去
-
hostNetwork 必须为 true,否则 VIP 绑不到宿主机网卡
-
NET_ADMIN / NET_RAW 权限必须有,否则无法操作网卡和 ARP
-
imagePullSecrets 在 DaemonSet 里合法,直接用 kube-system 的 eft-image-auth
3. 应用
kubectl apply -f kube-vip-ds.yaml
4. 验证
# 确认只出现在 master 上,共 5 个,worker 上不应有
kubectl get pods -n kube-system -o wide | grep kube-vip
# 确认全部 Running
kubectl get pods -n kube-system | grep kube-vip
# 查看当前 leader(谁持有 VIP)
kubectl get lease -n kube-system plndr-cp-lock -o jsonpath='{.spec.holderIdentity}'
# 测试 VIP 入口
curl -k https://192.168.6.249:6443/healthz
三、Static Pod 方式(备选)
1. manifest 文件
放到每台 master 的 /etc/kubernetes/manifests/kube-vip.yaml,kubelet 自动拉起:
apiVersionv1
kindPod
metadata
creationTimestampnull
namekube-vip
namespacekube-system
spec
containers
args
manager
env
namevip_arp
value"true"
nameport
value"6443"
namevip_interface
valueeth0
namevip_cidr
value"32"
namecp_enable
value"true"
namecp_namespace
valuekube-system
namesvc_enable
value"true"
namevip_leaderelection
value"true"
namevip_leasename
valueplndr-cp-lock
namevip_leaseduration
value"5"
namevip_renewdeadline
value"3"
namevip_retryperiod
value"1"
namevip_address
value192.168.6.249
nameprometheus_server
value2112
imageharbor.wulaoer.org/ops/kube-vipv0.6.2
imagePullPolicyIfNotPresent
namekube-vip
securityContext
capabilities
add
NET_ADMIN
NET_RAW
volumeMounts
mountPath/etc/kubernetes/admin.conf
namekubeconfig
hostNetworktrue
volumes
hostPath
path/etc/kubernetes/admin.conf
namekubeconfig
注意:Static Pod 的 yaml 里不能写 imagePullSecrets,写了会导致 mirror pod 创建失败,kubectl 看不到这个 pod(详见排障一节)。
2. 分发脚本
for ip in 192.168.6.36 192.168.6.41 192.168.6.42 192.168.6.236 192.168.6.237; do
scp /etc/kubernetes/manifests/kube-vip.yaml root@$ip:/etc/kubernetes/manifests/kube-vip.yaml
done
四、两种方式互相迁移
Static Pod 迁到 DaemonSet
-
先 apply DaemonSet,等 pod 起来
-
两者共用同一个 lease(plndr-cp-lock),leader election 互斥,不会出现双 VIP
-
确认 DaemonSet 正常后,删除所有 master 的 manifests 文件
-
确认最终只剩 DaemonSet 的 5 个 pod
kubectl apply -f kube-vip-ds.yaml
# 验证 Running 和 VIP 正常后:
for ip in 192.168.6.36 192.168.6.41 192.168.6.42 192.168.6.236 192.168.6.237; do
ssh root@$ip "rm -f /etc/kubernetes/manifests/kube-vip.yaml"
done
DaemonSet 迁到 Static Pod
顺序反过来:先放 static pod 文件到所有 master,验证正常后再 kubectl delete ds。
迁移期间两套并存是安全的,但不要长期并存。
五、排障记录(2026-08-28 事故复盘)
1. 镜像拉取 401 Unauthorized
现象:kubelet 报 Failed to pull image "harbor.wulaoer.org/ops/kube-vip:v0.6.2" ... 401 Unauthorized。
原因:harbor 密码被轮换,k8s 里的 eft-image-auth secret 没有同步更新。
排查:
kubectl get secret eft-image-auth -n kube-system -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
kubectl get secret -A | grep eft-image-auth
修复:更新各 namespace 的 secret;临时应急可以节点本地预置镜像 + imagePullPolicy 改 IfNotPresent。
2. kubectl 看不到 kube-vip 的 pod(Static Pod 方式)
现象:kubelet 日志持续报 Failed creating a mirror pod ... forbidden: a mirror pod may not reference secrets。
原因:static pod 的 yaml 里写了 imagePullSecrets。Kubernetes 不允许 mirror pod(static pod 在 API Server 上的影子对象)引用 secret,这是安全限制,不是 bug。
注意:这个限制只影响"kubectl 能不能看到",不影响本地容器运行。容器真正起不来是 401 拉不到镜像导致的。
修复:删除 yaml 里的 imagePullSecrets 块,或改用 DaemonSet 方式。
3. 改了 IfNotPresent 还是拉镜像失败
现象:imagePullPolicy 已改 IfNotPresent,仍然报 401 拉取失败。
原因:该节点 containerd 本地没有 harbor tag 的镜像缓存。本次事故中 master04 的 kube-vip.yaml 是新加的,从未成功拉过 harbor 镜像,本地只有 ghcr.io 的 tag,IfNotPresent 找不到本地镜像才会去拉。
排查和修复:
# 看本地有哪些 tag
crictl images | grep kube-vip
# 本地有同 digest 的 ghcr 镜像时,直接打 tag 复用
ctr -n k8s.io images tag ghcr.io/kube-vip/kube-vip:v0.6.2 harbor.wulaoer.org/ops/kube-vip:v0.6.2
# 或从其他节点导出导入
# ctr -n k8s.io images export /tmp/kube-vip.tar harbor.wulaoer.org/ops/kube-vip:v0.6.2
# ctr -n k8s.io images import /tmp/kube-vip.tar
4. 节点 NotReady
现象:节点 Ready 条件变 Unknown,Kubelet stopped posting node status。
排查:先 ping / SSH 节点本身,确认是节点宕机、网络断还是 kubelet 故障,与 kube-vip 无关时单独处理。
5. 本集群其他待办隐患
-
containerd 1.6.21 与 1.6.33 混用 + CentOS7 内核,存在 netns 删除失败(remove netns: unlinkat ... device or resource busy),导致 pod 卡 Terminating
-
k8s-node18 上有 3 个长期 RunContainerError 的 pod
-
control-plane 组件(kube-apiserver / kube-controller-manager / calico-node)存在频繁重启记录,建议单独排查
六、速查命令
# 部署(DaemonSet)
kubectl apply -f kube-vip-ds.yaml
# 查看分布(应只有 master)
kubectl get pods -n kube-system -o wide | grep kube-vip
# 查看 leader
kubectl get lease -n kube-system plndr-cp-lock -o jsonpath='{.spec.holderIdentity}'
# 测试入口
curl -k https://192.168.6.249:6443/healthz
# 本地镜像检查
crictl images | grep kube-vip
# 本地打 tag(镜像缺失时)
ctr -n k8s.io images tag ghcr.io/kube-vip/kube-vip:v0.6.2 harbor.wulaoer.org/ops/kube-vip:v0.6.2

您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏