
1. 集群节点IP变更这件事远比想象中麻烦做过OpenShift运维的人都有一个共识集群装好之后最怕动的就是底层网络。但现实往往不给你选择——机房搬迁、网段重新规划、VLAN调整、硬件替换任何一个理由都可能导致你不得不面对一个棘手的问题节点IP地址要改而且改完之后集群还得能正常跑起来。这件事在单机上可能只是改个配置文件重启网卡的事但在OpenShift集群里节点IP远不止是一个网络接口地址那么简单。它渗透在证书SAN列表、etcd成员列表、kubelet注册信息、API Server端点、SDN/OVN隧道地址、内部DNS记录等几乎所有核心组件的配置中。你改了一个IP等于在集群的神经系统里动了一刀牵一发而动全身。这篇文章要聊的就是当你不得不修改OpenShift集群中某个或某几个节点的IP地址时到底有哪些配置需要同步修改修改的顺序是什么哪些地方最容易踩坑以及如何验证集群是否真正恢复了健康状态。适合有一定OpenShift运维基础的读者也适合正在做集群迁移规划、想提前了解风险点的同行参考。需要提前说明的是不同OpenShift版本4.x的不同小版本之间在细节上会有差异本文以OpenShift 4.x以4.12-4.14为主要参考为基准展开涉及具体路径和命令时我会标注版本适用范围。另外集群的部署方式UPI还是IPI、网络插件OVN-Kubernetes还是OpenShift SDN也会影响具体操作文中会分别说明。2. 先搞清楚改IP到底动了哪些东西2.1 OpenShift里IP地址的“存在感”为什么这么强很多人第一次做这个操作时会低估复杂度觉得不就是把旧IP换成新IP嘛。但OpenShift的设计哲学是“声明式自愈”这意味着集群里到处都存着对节点IP的引用而且这些引用分布在不同的层级和组件中。打个比方OpenShift集群就像一栋大楼节点IP是每个房间的门牌号。门牌号变了不只是门口那块牌子要换——快递系统DNS、消防系统证书、物业管理系统etcd、内部通讯录kubelet注册、监控系统Prometheus target里存的地址全都要更新。漏掉任何一个那个环节就会出问题。具体来说一个节点IP地址在以下位置有引用etcd集群成员列表每个etcd成员的peer URL和client URL都绑定了IPKubernetes证书API Server证书、etcd证书、kubelet证书等的SAN列表中包含节点IPkubelet配置文件/var/lib/kubelet/kubeconfig和/etc/kubernetes/kubelet.conf中的地址引用Node对象kubectl get node -o yaml中status.addresses字段API Server的--advertise-address控制平面节点上这个参数绑定了IPSDN/OVN隧道端点OVN-Kubernetes的ovn-k8s-mp0接口、Geneve隧道端点地址内部DNS集群内DNS解析中节点相关的A记录Machine Config PoolMachineConfig中可能包含与IP相关的配置监控栈Prometheus的target列表、Alertmanager配置Operator配置部分Operator的CR中可能硬编码了节点地址2.2 哪些场景需要改IP哪些场景可以绕开在动手之前先评估一下是否真的必须改IP。有些场景其实有更省事的替代方案场景是否必须改IP替代方案机房整体搬迁网段不变否保持IP不变只改物理位置网段重新规划旧网段不可用是无替代必须改单节点硬件故障替换否新节点用相同IP接入VLAN调整导致IP必须变是无替代必须改节点扩容到新网段部分新节点用新网段旧节点不动如果确认必须改那就要做好“这不是十分钟能搞定的事”的心理准备。根据集群规模和节点角色不同整个操作可能需要2-6小时而且过程中集群会有短暂不可用。2.3 控制平面节点和工作节点改IP的难度完全不同这是必须先分清楚的事工作节点Worker/Compute改IP相对简单。工作节点不参与etcd quorum不承载API Server改IP主要影响kubelet注册、SDN隧道和证书。操作得当的话对集群整体可用性影响较小。控制平面节点Master/Control Plane改IP复杂得多。控制平面节点承载etcd、API Server、Controller Manager、Scheduler等核心组件改IP涉及etcd集群成员变更、API Server证书重新签发、端点重新配置等。操作不当可能导致集群直接不可用甚至etcd数据丢失。注意如果你的集群只有一个控制平面节点单Master改IP的风险极高建议在操作前做好etcd快照备份并准备好回滚方案。三Master的高可用集群相对安全一些但也要逐个节点操作不能同时改。2.4 操作前的必备检查清单在开始任何操作之前先把这些信息收集齐# 记录当前集群节点列表和IP oc get nodes -o wide # 记录etcd成员列表 oc exec -n openshift-etcd etcd-node-name -- etcdctl member list -w table # 记录当前证书SAN oc get secret -n openshift-kube-apiserver loadbalancer-serving-certkey -o jsonpath{.data.tls\.crt} | base64 -d | openssl x509 -text | grep -A1 Subject Alternative Name # 记录集群版本 oc version # 记录网络插件类型 oc get network.operator cluster -o jsonpath{.spec.defaultNetwork.type} # 备份etcd oc exec -n openshift-etcd etcd-node-name -- etcdctl snapshot save /var/lib/etcd/backup-$(date %Y%m%d).db这些信息在后续操作和排查问题时都会用到。特别是etcd快照这是你最后的救命稻草。3. 核心操作全流程从改IP到集群恢复3.1 整体操作顺序与逻辑改IP的操作顺序不能乱乱了就会陷入“改了A导致B不可用修了B发现C又断了”的死循环。正确的顺序应该是准备工作备份etcd、记录当前状态、通知相关人员将节点从集群中优雅移除工作节点或做好etcd成员变更准备控制平面节点在操作系统层面修改IP地址更新节点上的Kubernetes/OpenShift配置文件重新将节点加入集群或恢复etcd成员更新集群级别的配置证书、DNS、监控等验证集群健康状态这个顺序的核心逻辑是先让集群“忘记”旧IP的节点再让节点以新IP“重新报到”最后修复集群层面的引用。如果反过来先改IP再处理集群配置集群会因为找不到节点而进入异常状态增加排查难度。3.2 工作节点改IP的详细步骤3.2.1 驱逐节点上的工作负载# 标记节点为不可调度 oc adm cordon node-name # 驱逐节点上的PodDaemonSet管理的Pod不会被驱逐这是正常的 oc adm drain node-name --ignore-daemonsets --delete-emptydir-data --force # 确认节点上业务Pod已迁移 oc get pods --all-namespaces --field-selector spec.nodeNamenode-name驱逐完成后节点上应该只剩下DaemonSet管理的Pod如OVN、监控agent等。这些Pod在节点重启后会自动恢复。3.2.2 从集群中删除节点# 删除Node对象 oc delete node node-name # 如果是IPI集群还需要删除对应的Machine对象 oc get machines -n openshift-machine-api | grep node-name oc delete machine -n openshift-machine-api machine-name注意如果是IPI集群删除Machine对象会触发MachineSet自动创建新节点。如果你不想让它自动创建需要先scale down对应的MachineSet或者直接修改MachineSet的副本数。3.2.3 操作系统层面修改IP这一步根据你的操作系统和网络管理方式不同而不同。以RHCOSOpenShift默认节点OS为例# 查看当前网络配置 nmcli connection show # 修改IP地址假设连接名为ens3 nmcli connection modify ens3 ipv4.addresses new-ip/prefix nmcli connection modify ens3 ipv4.gateway new-gateway nmcli connection modify ens3 ipv4.dns new-dns # 应用配置 nmcli connection up ens3 # 验证 ip addr show ens3 ping new-gateway如果是RHEL节点可能还需要更新/etc/hosts文件中的IP映射。3.2.4 清理节点上的旧配置节点上有些配置文件会缓存旧IP需要手动清理或更新# 清理kubelet的旧注册信息 rm -f /var/lib/kubelet/kubeconfig rm -f /etc/kubernetes/kubelet.conf # 清理CNI配置中的旧IP引用 rm -rf /var/lib/cni/networks/ovn-k8s-cni-overlay/* rm -rf /var/lib/cni/networks/default/* # 清理OVN相关状态 rm -rf /var/run/ovn-kubernetes/* rm -rf /var/lib/ovn-kubernetes/*实操心得清理CNI和OVN状态这一步很多人会忽略结果节点重新加入后Pod网络不通。原因是OVN的隧道端点还指向旧IP清理后让OVN重新初始化才能绑定新IP。3.2.5 重新加入集群对于IPI集群最简单的办法是让MachineSet自动创建新节点新节点会使用新IP。但如果是UPI集群或者你想保留原节点需要手动触发节点重新注册# 重启kubelet服务 systemctl restart kubelet # 重启CRI-O systemctl restart crio # 等待节点重新注册 watch oc get nodes节点重新注册后检查Node对象的IP地址是否已更新oc get node node-name -o jsonpath{.status.addresses}3.2.6 更新集群级别配置节点重新加入后还需要更新以下集群级别配置# 更新DNS Operator的配置如果节点IP在DNS记录中 oc get dns.operator default -o yaml dns-operator-backup.yaml # 编辑并更新相关IP oc apply -f dns-operator-updated.yaml # 更新监控栈的target配置通常会自动发现但可能需要手动触发 oc rollout restart deployment -n openshift-monitoring prometheus-k8s # 更新证书如果新IP不在证书SAN中 # 这通常需要重新签发证书具体操作见下一节3.3 控制平面节点改IP的详细步骤控制平面节点改IP是整个操作中最复杂的部分因为涉及etcd集群成员变更。这里以三Master集群中修改其中一个Master节点IP为例。3.3.1 准备工作etcd快照与成员信息记录# 在健康的etcd节点上执行快照 oc exec -n openshift-etcd etcd-healthy-node -- etcdctl snapshot save /var/lib/etcd/pre-ip-change.db # 将快照复制到安全位置 oc cp openshift-etcd/etcd-healthy-node:/var/lib/etcd/pre-ip-change.db ./etcd-backup.db # 记录当前etcd成员列表 oc exec -n openshift-etcd etcd-healthy-node -- etcdctl member list -w table3.3.2 从etcd集群中移除目标节点# 获取目标节点的etcd成员ID oc exec -n openshift-etcd etcd-healthy-node -- etcdctl member list -w table | grep target-node-ip # 移除该成员 oc exec -n openshift-etcd etcd-healthy-node -- etcdctl member remove member-id # 验证移除成功 oc exec -n openshift-etcd etcd-healthy-node -- etcdctl member list -w table注意移除etcd成员后集群的quorum会暂时降低。三Master集群移除一个后还剩两个仍然满足quorum2/3。但如果是两Master集群不推荐移除一个后只剩一个quorum变为1/2此时如果剩下的节点出问题集群就挂了。所以操作期间要确保剩余节点健康。3.3.3 修改操作系统IP并清理配置与控制平面节点类似但需要额外清理etcd相关状态# 修改IP同工作节点步骤 nmcli connection modify ens3 ipv4.addresses new-ip/prefix nmcli connection up ens3 # 清理etcd数据目录重要 # 因为etcd成员已被移除旧数据不再需要保留反而会导致冲突 rm -rf /var/lib/etcd/member/* # 清理kubelet和静态Pod配置 rm -f /var/lib/kubelet/kubeconfig rm -f /etc/kubernetes/kubelet.conf rm -rf /etc/kubernetes/manifests/*3.3.4 重新加入etcd集群这一步需要借助OpenShift的etcd Operator来重新部署etcd静态Pod# 重启kubelet让静态Pod重新部署 systemctl restart kubelet # 等待etcd Pod重新创建 oc get pods -n openshift-etcd -w # 检查etcd成员是否自动重新加入 oc exec -n openshift-etcd etcd-healthy-node -- etcdctl member list -w table如果etcd成员没有自动重新加入可能需要手动干预# 获取etcd Pod名称 oc get pods -n openshift-etcd | grep target-node # 进入etcd Pod手动添加成员 oc exec -it -n openshift-etcd etcd-pod -- etcdctl member add new-member-name --peer-urlshttps://new-ip:23803.3.5 更新API Server证书和端点控制平面节点IP变更后API Server的证书SAN需要包含新IP否则客户端连接会报证书错误。# 查看当前API Server证书SAN oc get secret -n openshift-kube-apiserver loadbalancer-serving-certkey -o jsonpath{.data.tls\.crt} | base64 -d | openssl x509 -text | grep -A1 Subject Alternative Name # 更新API Server的advertise-address # 这通常通过修改对应的ConfigMap或Operator配置实现 oc edit configmap -n openshift-kube-apiserver configmap-name实操心得OpenShift 4.x的证书管理由Operator自动处理但节点IP变更后Operator可能不会立即感知。可以尝试删除对应的证书Secret让Operator重新签发。但这一步风险较高建议先在测试环境验证。3.3.6 更新etcd端点配置# 更新etcd endpoints ConfigMap oc edit configmap -n openshift-etcd etcd-endpoints # 更新etcd serving certs oc get secret -n openshift-etcd etcd-serving-cert -o yaml etcd-cert-backup.yaml # 编辑并更新IP oc apply -f etcd-cert-updated.yaml3.4 证书更新最容易被忽略的关键环节OpenShift集群中大量证书的SAN列表中包含节点IP。改IP后如果证书没有同步更新会出现各种TLS握手失败。需要检查的证书包括证书名称所在Namespace用途loadbalancer-serving-certkeyopenshift-kube-apiserverAPI Server负载均衡etcd-serving-certopenshift-etcdetcd服务端证书etcd-peer-certopenshift-etcdetcd peer通信kubelet-serving-certopenshift-kubeletkubelet服务端ovn-certopenshift-ovn-kubernetesOVN组件通信更新证书的通用思路是删除旧Secret让Operator重新签发。但不同证书的重新签发机制不同有些需要重启对应组件有些会自动更新。# 以etcd证书为例 oc delete secret -n openshift-etcd etcd-serving-cert oc delete secret -n openshift-etcd etcd-peer-cert # 等待Operator重新签发 oc get secret -n openshift-etcd -w # 验证新证书SAN oc get secret -n openshift-etcd etcd-serving-cert -o jsonpath{.data.tls\.crt} | base64 -d | openssl x509 -text | grep -A1 Subject Alternative Name4. 验证与排查怎么确认集群真的恢复了4.1 集群健康状态全面检查改完IP后不要急着宣布成功。按以下清单逐项验证# 1. 节点状态 oc get nodes -o wide # 所有节点应为Ready状态IP地址正确 # 2. 集群Operator状态 oc get clusteroperators # 所有Operator应为AvailableTrue, ProgressingFalse, DegradedFalse # 3. etcd健康状态 oc exec -n openshift-etcd etcd-node -- etcdctl endpoint health --cluster # 所有端点应为healthy # 4. etcd成员列表 oc exec -n openshift-etcd etcd-node -- etcdctl member list -w table # 成员数量和IP地址正确 # 5. API Server可达性 oc get --raw /healthz # 应返回ok # 6. 集群版本 oc get clusterversion # 应显示正常版本无异常条件 # 7. 核心Pod状态 oc get pods -n openshift-etcd oc get pods -n openshift-kube-apiserver oc get pods -n openshift-ovn-kubernetes # 所有Pod应为Running状态4.2 常见问题速查表问题现象可能原因排查方法解决方案节点NotReadykubelet未正确注册journalctl -u kubelet -f检查kubelet配置和证书Pod网络不通OVN隧道端点未更新oc get pods -n openshift-ovn-kubernetes清理OVN状态并重启API Server无法访问证书SAN不含新IPopenssl x509 -text检查证书重新签发证书etcd成员缺失etcd未重新加入etcdctl member list手动添加etcd成员Operator Degraded配置引用旧IPoc describe clusteroperator name更新对应配置DNS解析失败DNS记录未更新oc get dns.operator -o yaml更新DNS Operator配置监控target丢失Prometheus配置未更新检查Prometheus target页面重启Prometheus或更新配置4.3 几个我踩过的坑坑一忘了清理CNI状态导致Pod网络不通。第一次操作时节点重新加入后Pod一直处于ContainerCreating状态。排查了半天才发现是/var/lib/cni/networks/下还存着旧IP的分配记录。清理后恢复正常。坑二etcd成员移除后没有清理数据目录。有一次改完IP后etcd一直起不来日志显示“member already exists”。原因是旧的数据目录还在etcd以为自己是旧成员。删除/var/lib/etcd/member/*后解决。坑三证书更新后没有重启对应组件。证书Secret更新了但组件还在用旧证书。需要重启对应的Pod或等待Operator自动滚动更新。可以通过oc rollout restart手动触发。坑四IPI集群删除Machine后自动创建了新节点。本来想保留原节点结果MachineSet自动创建了一个新节点导致节点数量超出预期。后来先scale down MachineSet再操作。4.4 回滚方案万一搞砸了怎么办如果操作过程中出现不可恢复的问题回滚是最后的手段恢复etcd快照如果etcd数据损坏可以用之前备份的快照恢复恢复节点IP把IP改回原来的地址恢复配置文件从备份中恢复kubelet、CNI等配置重新加入集群让节点以旧IP重新注册回滚的前提是你有完整的备份。这也是为什么我在文章开头就强调备份的重要性。5. 一些值得记住的经验整个操作做下来最深的体会是OpenShift集群改IP不是单纯的网络操作而是一次涉及证书、etcd、网络插件、监控栈的系统工程。任何一个环节漏掉都会在后续某个时刻以意想不到的方式暴露出来。几个关键原则值得记住第一能不改就不改。如果只是物理位置变化而网段不变保持IP不变是最省事的方案。改IP的代价远比你想象的大。第二控制平面节点和工作节点分开处理。工作节点改IP相对独立可以逐个操作控制平面节点改IP涉及etcd quorum必须谨慎规划操作窗口。第三证书是隐藏的雷区。很多人改完IP后集群表面看起来正常但某些组件之间的TLS通信已经悄悄失败了。定期检查证书SAN列表是个好习惯。第四验证要彻底。不要只看oc get nodes显示Ready就认为成功了。Operator状态、etcd健康、Pod网络、API Server可达性、监控target每一项都要确认。第五备份是底线。etcd快照、配置文件备份、当前状态记录这些准备工作花不了多少时间但关键时刻能救命。最后分享一个小技巧如果你需要在测试环境反复练习这个操作可以用一个三节点的最小集群1 Master 2 Worker来模拟。把操作步骤写成脚本每次练习时跑一遍熟练之后再到生产环境操作。这个操作对熟练度的要求很高临时查文档和胸有成竹地执行心态和结果完全不一样。