【VM】单机三虚拟机集群实战:Bridge 桥接、固定 IP 与避开 cloud-init 的坑

单机三虚拟机集群:为什么网络一定要选 Bridge,而不是 NAT

在一台 Ubuntu 22 物理机上,用 Virtual Machine Manager(virt-manager / KVM/libvirt) 跑起三台虚拟机(node-01 / node-02 / node-03),组成一个学习与测试用的集群,部署 K8S、Redis Cluster、Elasticsearch。本文先把"为什么选 Bridge"讲透,再给出一套可照抄的固定 IP 配置流程:宿主机建桥 → VMM 部署虚拟机 → 每台虚拟机用 netplan 固定 IP → 屏蔽 cloud-init 防覆盖。


一、来龙去脉:为什么要在一台机器上起一个集群

很多分布式中间件,本质上是"多节点"的:

  • Kubernetes 至少要有一个控制面 + 若干工作节点,才能体会调度、网络、故障转移;
  • Redis Cluster 官方要求最少 6 个实例(3 主 3 从),节点之间靠 Gossip 协议互相发现;
  • Elasticsearch 想验证分片、副本、选主,也得有 3 个节点起步。

可现实是:大多数人手里只有一台还算能打的机器。买三台物理服务器太奢侈,上云按小时计费又心疼。于是最务实的方案就是------一台宿主机,虚拟出三台"准物理机",既省钱,又能逼真地复现多节点环境。

到这里,真正的分水岭出现了:这三台虚拟机,要怎么联网?

这不是个无所谓的细节。它直接决定了你的集群"像不像真的",以及局域网里其他机器(你的笔记本、同事的电脑、另一台测试机)能不能直接访问到这三个节点


二、核心诉求:节点必须像真实物理机一样"出现在局域网里"

把需求一句话讲清:

局域网内其他机器,要能像访问一台普通服务器那样,直接访问 node-01 / node-02 / node-03。

为什么这个诉求如此关键?因为一旦做集群,你几乎一定会遇到这些场景:

  • 在笔记本上用 kubectl 直连虚拟机里的 K8S API Server;
  • 用客户端连 Redis Cluster------而 Redis Cluster 会把节点自己的 IP 通过 MOVED/ASK 重定向给客户端,客户端必须能直接连上那个 IP;
  • 用浏览器或 Kibana 访问 ES 的 9200/5601;
  • 节点之间互相发现、心跳、选主,要求彼此地址对等、可路由

这些场景的共同点是:虚拟机需要一个局域网里真实、独立、可被别人主动连入的 IP,而不是藏在宿主机背后的"内部地址"。

能不能满足这个诉求,就看你选 NAT 还是 Bridge


三、NAT vs Bridge:从本质看区别

两种模式的差异,可以用"虚拟机在网络里的身份"来理解。

NAT 模式:虚拟机藏在宿主机背后

NAT(网络地址转换)下,libvirt 会建一个私有虚拟网络 (默认 virbr0,网段如 192.168.122.0/24),虚拟机拿到的是这个私有网段的地址。对外通信时,所有流量都被"伪装"成宿主机的 IP 发出去。

这就像住在一栋楼里、没有独立门牌号 的房间:你能主动出门(访问外网 OK),但外面的人想找你,只能先敲楼的总门(宿主机),再由前台转发------你必须在宿主机上一条条配端口转发(hostfwd / iptables DNAT),否则外部根本无法主动连入

对一个动辄十几个端口、还会互相重定向 IP 的集群来说,这是灾难。

Bridge 模式:虚拟机是局域网里的"正式居民"

Bridge(桥接)的做法完全不同。宿主机上建一个网桥 br0 ,它扮演一台虚拟交换机:把宿主机的物理网卡和每台虚拟机的虚拟网卡,统统"插"到这台交换机上。

结果是:虚拟机直接接入了你家/公司的物理局域网,由路由器(192.168.1.1)像给真实设备发地址一样,给每台虚拟机分配一个 192.168.1.x 的 IP 。它和宿主机、和其他物理机处在同一个二层网段,彼此平等、互相可达,不需要任何端口转发。

这正是我们要的------虚拟机像真实物理机一样,出现在局域网中

维度 NAT 模式 Bridge 模式(本文选择)
虚拟机 IP 来源 libvirt 私有网段(如 192.168.122.x) 路由器分配的局域网 IP(192.168.1.x)
与局域网的关系 隔离,藏在宿主机背后 同一二层网段,平等成员
外部主动访问虚拟机 需逐端口配置转发,繁琐 直接访问,零额外配置
虚拟机访问外网 开箱即用 正常可用
节点间互相发现 受限,IP 不可对外 天然支持,地址对等
适合场景 单机自用、临时测试 多节点集群、需被外部访问

结论很清晰:做集群、要被局域网访问,就选 Bridge。


四、目标拓扑图

下图是采用 Bridge 模式后的网络结构。核心是中间那台"虚拟交换机" br0:物理网卡和三台虚拟机都挂在它下面,从而都成为 192.168.1.0/24 的正式成员。
#mermaid-svg-I6FzwhhY0HMG1XBY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-I6FzwhhY0HMG1XBY .error-icon{fill:#552222;}#mermaid-svg-I6FzwhhY0HMG1XBY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-I6FzwhhY0HMG1XBY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-I6FzwhhY0HMG1XBY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-I6FzwhhY0HMG1XBY .marker.cross{stroke:#333333;}#mermaid-svg-I6FzwhhY0HMG1XBY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-I6FzwhhY0HMG1XBY p{margin:0;}#mermaid-svg-I6FzwhhY0HMG1XBY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-I6FzwhhY0HMG1XBY .cluster-label text{fill:#333;}#mermaid-svg-I6FzwhhY0HMG1XBY .cluster-label span{color:#333;}#mermaid-svg-I6FzwhhY0HMG1XBY .cluster-label span p{background-color:transparent;}#mermaid-svg-I6FzwhhY0HMG1XBY .label text,#mermaid-svg-I6FzwhhY0HMG1XBY span{fill:#333;color:#333;}#mermaid-svg-I6FzwhhY0HMG1XBY .node rect,#mermaid-svg-I6FzwhhY0HMG1XBY .node circle,#mermaid-svg-I6FzwhhY0HMG1XBY .node ellipse,#mermaid-svg-I6FzwhhY0HMG1XBY .node polygon,#mermaid-svg-I6FzwhhY0HMG1XBY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-I6FzwhhY0HMG1XBY .rough-node .label text,#mermaid-svg-I6FzwhhY0HMG1XBY .node .label text,#mermaid-svg-I6FzwhhY0HMG1XBY .image-shape .label,#mermaid-svg-I6FzwhhY0HMG1XBY .icon-shape .label{text-anchor:middle;}#mermaid-svg-I6FzwhhY0HMG1XBY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-I6FzwhhY0HMG1XBY .rough-node .label,#mermaid-svg-I6FzwhhY0HMG1XBY .node .label,#mermaid-svg-I6FzwhhY0HMG1XBY .image-shape .label,#mermaid-svg-I6FzwhhY0HMG1XBY .icon-shape .label{text-align:center;}#mermaid-svg-I6FzwhhY0HMG1XBY .node.clickable{cursor:pointer;}#mermaid-svg-I6FzwhhY0HMG1XBY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-I6FzwhhY0HMG1XBY .arrowheadPath{fill:#333333;}#mermaid-svg-I6FzwhhY0HMG1XBY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-I6FzwhhY0HMG1XBY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-I6FzwhhY0HMG1XBY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I6FzwhhY0HMG1XBY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-I6FzwhhY0HMG1XBY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I6FzwhhY0HMG1XBY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-I6FzwhhY0HMG1XBY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-I6FzwhhY0HMG1XBY .cluster text{fill:#333;}#mermaid-svg-I6FzwhhY0HMG1XBY .cluster span{color:#333;}#mermaid-svg-I6FzwhhY0HMG1XBY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-I6FzwhhY0HMG1XBY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-I6FzwhhY0HMG1XBY rect.text{fill:none;stroke-width:0;}#mermaid-svg-I6FzwhhY0HMG1XBY .icon-shape,#mermaid-svg-I6FzwhhY0HMG1XBY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-I6FzwhhY0HMG1XBY .icon-shape p,#mermaid-svg-I6FzwhhY0HMG1XBY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-I6FzwhhY0HMG1XBY .icon-shape .label rect,#mermaid-svg-I6FzwhhY0HMG1XBY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-I6FzwhhY0HMG1XBY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-I6FzwhhY0HMG1XBY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-I6FzwhhY0HMG1XBY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-I6FzwhhY0HMG1XBY .router>*{fill:#1e3a5f!important;stroke:#4a90d9!important;color:#fff!important;stroke-width:1.5px!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .router span{fill:#1e3a5f!important;stroke:#4a90d9!important;color:#fff!important;stroke-width:1.5px!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .router tspan{fill:#fff!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .other>*{fill:#2a2a2a!important;stroke:#888888!important;color:#dddddd!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .other span{fill:#2a2a2a!important;stroke:#888888!important;color:#dddddd!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .other tspan{fill:#dddddd!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .nic>*{fill:#3d3320!important;stroke:#d9b84a!important;color:#fff!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .nic span{fill:#3d3320!important;stroke:#d9b84a!important;color:#fff!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .nic tspan{fill:#fff!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .bridge>*{fill:#3d2f5f!important;stroke:#b79bff!important;color:#fff!important;stroke-width:3px!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .bridge span{fill:#3d2f5f!important;stroke:#b79bff!important;color:#fff!important;stroke-width:3px!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .bridge tspan{fill:#fff!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .vm>*{fill:#1f3d2f!important;stroke:#5fb88a!important;color:#fff!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .vm span{fill:#1f3d2f!important;stroke:#5fb88a!important;color:#fff!important;}#mermaid-svg-I6FzwhhY0HMG1XBY .vm tspan{fill:#fff!important;} 🖥️ 宿主机 Ubuntu22
🌐 局域网入口层
虚拟机集群 (K8S / Redis / ES)
直接访问
路由器 / 网关

192.168.1.0/24 · 192.168.1.1
局域网其他机器

192.168.1.xxx
物理网卡 enp55s0

桥接成员 · 无独立 IP
网桥 br0(虚拟交换机)

宿主机 IP: 192.168.1.188
node-01

192.168.1.189
node-02

192.168.1.190
node-03

192.168.1.191

读图三个要点:

  1. br0 是中枢(图中紫色六边形)。它就是虚拟交换机,所有成员都接在它上面。
  2. 物理网卡没有独立 IP 。在桥接里,网卡只是 br0 的一个"端口",宿主机自己的 IP(192.168.1.188)落在 br0,而不是网卡上。这一步是新手最容易配错的地方。
  3. 其他机器到虚拟机是直达的(虚线)。因为大家在同一二层网段,数据帧经交换/网桥直接转发,不必绕路由器做转换。

五、落地四步总览

从零到一,整套部署就是四步,后面逐步展开:

步骤 在哪做 做什么
① 建网桥 br0 宿主机 屏蔽 cloud-init,用 netplan 把物理网卡桥接成 br0,宿主机 IP 落到 br0(192.168.1.188)
② 部署虚拟机 宿主机(VMM) Virtual Machine Manager 创建 3 台 Ubuntu 22 虚拟机,网卡都选 br0
③ 固定虚拟机 IP 每台虚拟机 同样屏蔽 cloud-init,用 netplan 配静态 IP(.189/.190/.191),用 routes 替代已弃用的 gateway4
④ 名称解析 所有节点 统一写 /etc/hosts,集群内用 node-01/02/03 互访

贯穿全程的关键点:屏蔽 cloud-init。 Ubuntu 22 默认用 cloud-init 管网络,每次开机会自动生成 /etc/netplan/50-cloud-init.yaml,覆盖你手写的配置。无论宿主机还是虚拟机,只要你想用自己的固定 IP,就必须先把 cloud-init 的网络管理关掉(见每一步的说明)。


六、第一步:宿主机建网桥 br0

6.1 先屏蔽 cloud-init 的网络管理

让你手写的 netplan 生效、不被开机覆盖:

bash 复制代码
sudo nano /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg

写入:

yaml 复制代码
network: {config: disabled}

保存退出后,cloud-init 就不会再生成或覆盖 50-cloud-init.yaml。可顺手删掉旧文件避免冲突:

bash 复制代码
sudo rm -f /etc/netplan/50-cloud-init.yaml

6.2 用 netplan 建桥

核心思想:把物理网卡的 IP 摘下来,改成"无 IP 的桥接成员",再把 IP 配到 br0 。新建 /etc/netplan/01-netcfg.yaml(网卡名 enp55s0ip link show 查你自己的):

yaml 复制代码
network:
  version: 2
  renderer: networkd
  ethernets:
    enp55s0:                # 物理网卡名,用 ip link show 查看
      dhcp4: no
      dhcp6: no             # 网卡本身不再要 IP
  bridges:
    br0:
      interfaces: [enp55s0] # 把物理网卡接入网桥
      dhcp4: no
      dhcp6: no
      addresses: [192.168.1.188/24]
      routes:
        - to: default       # 用 routes 替代已弃用的 gateway4
          via: 192.168.1.1
      nameservers:
        addresses: [192.168.1.1, 8.8.8.8]

6.3 设权限并应用

bash 复制代码
sudo chmod 600 /etc/netplan/01-netcfg.yaml
sudo chown root:root /etc/netplan/01-netcfg.yaml
sudo netplan apply

确保 systemd-networkd 在运行:

bash 复制代码
sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd

完成后 ip a 应看到 IP 在 br0 上、enp55s0 无 IP------这就是桥接生效的标志。

⚠️ 远程操作要小心 :改桥接会瞬断网络。SSH 操作前务必有控制台兜底,或先 sudo netplan try(超时自动回滚)。


七、第二步:用 Virtual Machine Manager 部署三台虚拟机

打开 Virtual Machine Manager(virt-manager),依次创建 node-01 / node-02 / node-03(均为 Ubuntu 22 Server),关键只在网络这一步:

  1. File → New Virtual Machine,选择 Ubuntu 22 安装介质(ISO);
  2. 分配 CPU / 内存 / 磁盘(集群节点建议 ≥2 vCPU、≥4GB、≥40GB);
  3. 最后一步勾选 "Customize configuration before install";
  4. 在网络设置里,Network source 选 Bridge device... 并填 br0 (或选已有的桥接来源),网卡型号选 virtio 以获得更好性能;
  5. 完成创建,装系统。三台虚拟机重复以上步骤。

这一步等价于命令行的 virt-install --network bridge=br0,model=virtio ...。VMM 只是把它做成了图形界面。装好后,虚拟机网卡会临时从路由器拿到一个 192.168.1.x,下一步我们把它固定下来。


八、第三步:给每台虚拟机配固定 IP(netplan)

每台虚拟机也是 Ubuntu 22,同样要先屏蔽 cloud-init ,否则重启后 50-cloud-init.yaml 会覆盖你的静态配置:

bash 复制代码
# 在每台虚拟机里执行
echo 'network: {config: disabled}' | sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
sudo rm -f /etc/netplan/50-cloud-init.yaml

然后在每台虚拟机新建 /etc/netplan/01-netcfg.yaml,用 routes 替代 gateway4,分别固定 IP。网卡名 ens3ip link show 确认。

node-01 → 192.168.1.189

yaml 复制代码
network:
  version: 2
  renderer: networkd
  ethernets:
    ens3:                   # 虚拟机网卡名,用 ip link show 查看
      dhcp4: no
      dhcp6: no
      addresses: [192.168.1.189/24]
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses: [192.168.1.1, 8.8.8.8]

node-02 → 192.168.1.190 (仅 addresses 不同)

yaml 复制代码
network:
  version: 2
  renderer: networkd
  ethernets:
    ens3:
      dhcp4: no
      dhcp6: no
      addresses: [192.168.1.190/24]
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses: [192.168.1.1, 8.8.8.8]

node-03 → 192.168.1.191

yaml 复制代码
network:
  version: 2
  renderer: networkd
  ethernets:
    ens3:
      dhcp4: no
      dhcp6: no
      addresses: [192.168.1.191/24]
      routes:
        - to: default
          via: 192.168.1.1
      nameservers:
        addresses: [192.168.1.1, 8.8.8.8]

每台虚拟机应用配置:

bash 复制代码
sudo netplan apply
# 想先验证、出错自动回滚:
sudo netplan try

为什么用 routes 而不是 gateway4? 较新版本的 netplan 已弃用 gateway4,推荐用 routes: 下的 to: default / via: <网关> 来声明默认路由。现在就用新写法,免得日后告警或失效。


九、第四步:统一 /etc/hosts,集群内用名字互访

集群组件(K8S、ES)里写一串 IP 既难记又易错。在每台机器 (宿主机 + 三台虚拟机)的 /etc/hosts 末尾追加同一段映射,之后就能用 node-01 这样的名字互访:

text 复制代码
192.168.1.188   host-ubuntu
192.168.1.189   node-01
192.168.1.190   node-02
192.168.1.191   node-03

十、验证与后续访问方式

判断整套网络是否成功,只看一件事:局域网里另一台机器,能不能直接连上虚拟机的服务。

  • 在你的笔记本上 ping 192.168.1.189 通 → 二层打通;
  • 三台虚拟机之间互相 ping node-02 都通 → 集群内部网络与解析就绪。

固定 IP 后的访问方式:

  • 宿主机 :192.168.1.188(在 br0 上);
  • 虚拟机 :192.168.1.189 / .190 / .191;
  • 示例:
    • ssh root@192.168.1.189 -p 22
    • redis-cli -h 192.168.1.190 -p 6379
    • Kubernetes 各节点互通直接用各自固定 IP(或 /etc/hosts 里的名字)。

十一、使用场景:为什么这些组件"非 Bridge 不可"

回到最初的三个目标组件,看看 Bridge + 固定 IP 在它们身上具体解决了什么:

Kubernetes ------ 节点要互相通信、Pod 网络要可路由,外部还要用 kubectl 连 API Server。NAT 下节点 IP 对外不可见,kubeconfig 里写的地址外面连不上;Bridge 让每个节点都有真实局域网 IP,固定下来后 kubeadm/证书里的地址也不会因重启漂移。

Redis Cluster ------ 这是最典型的"NAT 杀手"。Redis Cluster 在重定向时会把节点自身记录的 IP 返回给客户端;如果那是个 NAT 私有地址,客户端根本连不上,集群形同虚设。Bridge + 固定 IP 下节点地址真实且稳定,重定向天然正确。

Elasticsearch ------ 节点靠相互发现组成集群、对外暴露 9200。Bridge 让发现和访问都走真实 IP,配 discovery.seed_hosts 时直接写 192.168.1.189/190/191(或 hosts 名字)即可,且重启不变。

一句话:凡是"节点用自己的真实 IP 对外打交道"的分布式系统,都依赖 Bridge,且强烈建议固定 IP。


十二、常见坑与注意事项

  • cloud-init 覆盖配置 :这是最高频的坑。手写 netplan 不生效、重启又变回 DHCP,十有八九是没屏蔽 cloud-init。宿主机和每台虚拟机都要做 network: {config: disabled}
  • 改桥接断网 :netplan apply 会重置网络,远程操作前务必准备好控制台兜底,或用 netplan try
  • IP 配错了位置 :桥接后 IP 必须在 br0 上,物理网卡不能再留 IP,否则路由混乱。
  • 网卡名不对 :宿主机(如 enp55s0)和虚拟机(如 ens3)网卡名不同,务必 ip link show 确认,别照抄。
  • gateway4 已弃用 :统一用 routes: - to: default / via: 写默认网关。
  • WiFi 网卡难桥接 :大多数无线网卡不支持桥接,宿主机尽量用有线网卡br0
  • 企业网络限制:部分公司网络对一个物理口下挂多个 MAC/IP 有端口安全限制,会导致虚拟机拿不到地址,需联系网管。
  • MTU 一致性 :跨节点大流量(如 ES 分片同步)时,确保宿主机、br0、虚拟机 MTU 一致,避免分片丢包。

十三、小结

在一台 Ubuntu 22 上搭三节点集群,最该想清楚的不是 CPU 内存怎么分,而是网络模式 + IP 稳定性:

  • 目标:让 node-01/02/03 像真实物理机一样出现在局域网,被直接访问,且 IP 永久固定。
  • 手段 :宿主机用 br0 网桥把物理网卡和虚拟机接到同一台"虚拟交换机";用 Virtual Machine Manager 部署虚拟机并选 br0;每台虚拟机用 netplan(routes 替代 gateway4)配静态 IP;宿主机与虚拟机都屏蔽 cloud-init 防止覆盖;最后用 /etc/hosts 统一解析。
  • 取舍 :NAT 适合单机自用、不需外部访问;只要做集群、要被局域网访问,就选 Bridge

br0 理解成一台交换机、把 cloud-init 这个"网络管家"先请走,整套配置就顺理成章了。剩下的,就是在三台"准物理机"上尽情折腾 K8S、Redis Cluster 和 ES 了。