GCP L4 Passthrough 负载均衡器“假死超时”深度排查复盘
2026/8/2 2:15:47 网站建设 项目流程

GCP L4 Passthrough 负载均衡器“假死超时”深度排查复盘:从 OpenSSH 秘钥丢失、DPKG 锁死到 Guest Agent VIP 路由机制

在 GCP (Google Cloud Platform) 上使用 Terraform 自动化部署L4 区域级外部网络负载均衡器 (Regional External Network Load Balancer)时,我们遭遇了一个非常经典的生产级故障:公网访问 LB IP (34.39.47.144:22) 报Connection timed out超时,且 GCP Backend Service 持续被标记为UNHEALTHY

然而诡异的是:在同一个 VPC 内部网络中(通过同一子网的 Bastion VM)直连目标机器的内网 IP (192.168.0.242:22/80),TCP 握手与 SSH / Nginx 响应一切正常!

本文记录针对此“内网通、公网超时”异常的深度排查全过程,揭示 OpenSSH Host Key 缺失、DPKG 锁竞争、GCP Passthrough 包直通路由机制以及google-guest-agent在云原生网络中的关键作用。


1. 现象描述与矛盾点

故障现象

对 L4 LB 预留的公网静态 IP 22 端口发起探测:

$nc-zv-w534.39.47.14422nc: connect to34.39.47.144 port22(tcp)failed: Connection timed out

查询 GCP 云端 Backend Service 的健康探针状态:

$ gcloud compute backend-services get-health poc-l4-lb-backend-service--region=europe-west2 --- backend:.../instanceGroups/poc-unmanaged-instance-group status: healthStatus: - forwardingRuleIp:34.39.47.144 healthState: UNHEALTHY instance:.../instances/poc-internal-vm ipAddress:192.168.0.242 port:22

内网对比实测

使用同一 VPC 子网内的另一台测试节点(Alice VM34.39.2.90)对poc-internal-vm的内网 IP 进行 Socket 直连:

# 内网 Socket 探测结果:Port22:0# (0 表示成功连接 SSH)Port80:0# (0 表示成功连接 Nginx)

矛盾核心:内网 22 与 80 端口都在坚强地监听并响应请求,防火墙已配置0.0.0.0/0放行,但外网走 L4 LB 访问却连 SYN/ACK 回包都收不到,只能默默等待超时。


2. 深入 Linux 串口日志与云网络底层的 3 大根因拆解

通过抓取 GCP 实例串口输出(Serial Port Output)与 Linuxjournalctl系统日志,我们层层剥开了引发此故障的三重死锁链:

死锁 3: UnMIG 端口名称错配

死锁 2: Guest Agent 停运与 Passthrough VIP 路由缺失

死锁 1: DPKG 锁争抢 & HostKey 丢失

gcevm.tf 配置修改 (新增开机脚本)

Terraform 重建 VM (分配新 IP: 192.168.0.242)

开机脚本运行 apt-get 独占 /var/lib/dpkg/lock-frontend

google-guest-agent 生成 HostKeys 失败 (拿不到锁)

sshd 无秘钥抛出 'no hostkeys available' 挂掉

systemd 重试 5 次被频率限制锁定为 Failed

google-guest-agent-manager 进程崩溃

google-guest-agent.service 未能在系统启动

Linux 内核缺少 34.39.47.144 的本地 VIP 别名路由

GCP Passthrough LB 转发的数据包被 VM 内核静默丢弃

UnMIG 仅定义 http:80, 未指定 ssh:22

Backend Service 默认匹配 80 端口

Health Check (22) 与 Backend 目标端口 (80) 错配报 UNHEALTHY

GCP SDN (Andromeda) 入口静默丢包 (Connection timed out)

根因 1:DPKG 锁争抢引发 OpenSSH Host Key 缺失与 systemd 熔断

gcevm.tf中配置metadata_startup_script后,Terraform 替换重建了 VM。在新机器首秒启动时:

  1. 锁争抢 (Lock Contention):开机脚本的第一行命令apt-get update && apt-get install -y nginx独占了全局包管理锁/var/lib/dpkg/lock-frontend
  2. 秘钥生成失败:GCP 的 OS 初始化脚本在尝试通过dpkg-reconfigure openssh-server为新机器生成独立的主机秘钥(Host Keys,如/etc/ssh/ssh_host_rsa_key)时,因拿不到 DPKG 锁而抛错中断。
  3. sshd启动崩溃:OpenSSH 的安全机制规定:无主机秘钥,决不提供盲服务。串口日志记录了极关键的一行:
    Aug 1 13:48:05 poc-internal-vm sshd[823]: sshd: no hostkeys available -- exiting. Aug 1 13:48:05 poc-internal-vm systemd[1]: ssh.service: Failed with result 'exit-code'.
  4. systemd 频率保护熔断systemd连续重启ssh.service5 次均因缺秘钥而失败,触发了Start request repeated too quickly保护熔断,彻底将sshd锁定在Failed状态!

更恶劣的是,因上次 unclean shutdown 留下的中断状态,后续开机引发了E: dpkg was interrupted, you must manually run 'dpkg --configure -a'的连锁死锁。


根因 2:GCP L4 Passthrough 流量转发模型与google-guest-agent的本地 VIP 路由

这是解决“为什么内网能连,走 LB 静态 IP 超时”的技术核心。

GCP 的 L4 External Network Load Balancer 属于Passthrough (包直通模式)

  • 数据包特征:公网客户端发送给 LB 地址34.39.47.144:22的数据包,经由 GCP SDN 转发后,数据包到达 VM 网卡(ens4,IP192.168.0.242)时,其目标 IP (Destination IP) 依然保持为34.39.47.144,并没有发生 DNAT 替换!
  • Guest Agent 的角色:为了让 VM 的 Linux 内核识别并接收目标 IP 为34.39.47.144的数据包,GCP 依赖运行在 VM 内部的google-guest-agent进程。该进程会自动侦听 GCP Metadata,并在 Linux 网络栈中动态添加 VIP 本地路由与回环别名。

串口日志排查显示:

● google-guest-agent.service - Google Compute Engine Guest Agent Loaded: loaded (/lib/systemd/system/google-guest-agent.service; disabled; vendor preset: disabled) Active: inactive (dead)

由于前期初始化失败,google-guest-agent处于inactive (dead)状态!
因为没有 Guest Agent 动态配置 VIP 路由,VM 系统的网络栈根本不认识34.39.47.144这个外来 IP,将所有由 L4 LB 投递过来的数据包在内核层静默丢弃 (Drop)

再加上当 GCP 健康检查判定 Backend 为UNHEALTHY时,GCP 底层 SDN (Andromeda) 也会在入口处开启丢包防护(Drop on Unhealthy),导致客户端永远收不到 TCP ACK,最终表现为Connection timed out


根因 3:UnMIG 端口名称 (named_port) 与 L4 Backend Service 探针对齐

unmig.tf中先前仅配置了:

named_port { name = "http" port = "80" }

google_compute_region_backend_service未显式配置port_name时,GCP 后端服务默认绑定了 UnMIG 中声明的 80 端口,而健康检查l4_lb_hc却在探测 22 端口,造成了Backend 目标端口 (80) 与 Health Check 探针端口 (22) 的错配


3. 完整 Fix 修复方案

针对上述三个根因,我们在 Terraform 代码库中进行了针对性的健壮性重构:

3.1tf-infra/gcevm.tf健壮开机脚本重构

在开机脚本中加入恢复 DPKG 中断、补齐 SSH HostKeys、重置 systemd 速率限制以及启动 Google Guest Agent的全套自愈逻辑:

resource "google_compute_instance" "poc_vm" { name = var.instance_name machine_type = "n2d-standard-4" zone = var.zone boot_disk { initialize_params { image = "debian-cloud/debian-11" size = 60 type = "pd-standard" } } network_interface { network = var.network_name subnetwork = var.subnet_name # 纯内网 Spot 节点,不分配公网 IP } scheduling { preemptible = true provisioning_model = "SPOT" automatic_restart = false on_host_maintenance = "TERMINATE" } tags = ["poc-internal-vm"] metadata_startup_script = <<-EOF #!/bin/bash export DEBIAN_FRONTEND=noninteractive # 1. 自动修复先前可能因抢锁中断的 dpkg 状态 dpkg --configure -a || true # 2. 安装与启动 Nginx Web 服务 apt-get update apt-get install -y nginx echo "<h1>Hello from GCP L7 LB Backend - $(hostname)</h1>" > /var/www/html/index.html systemctl restart nginx # 3. 显式使能与启动 Google Guest Agent,确保 Passthrough LB VIP 本地路由正确配置 systemctl enable --now google-guest-agent || true # 4. 补齐缺失的 OpenSSH Host Keys,重置 systemd 熔断计数器并重启 ssh ssh-keygen -A || true systemctl reset-failed ssh || true systemctl restart ssh EOF }

3.2tf-infra/unmig.tftf-infra/l4-lb.tf端口显式映射与对齐

在 UnMIG 中显式暴露ssh: 22http: 80双端口映射:

# tf-infra/unmig.tf resource "google_compute_instance_group" "poc_unmig" { name = "poc-unmanaged-instance-group" description = "Unmanaged Instance Group for Cloud LB PoC" zone = var.zone network = google_compute_instance.poc_vm.network_interface[0].network instances = [ google_compute_instance.poc_vm.id ] named_port { name = "ssh" port = "22" } named_port { name = "http" port = "80" } }

在 L4 Backend Service 中显式关联port_name = "ssh",确保 Backend 目标端口与l4_lb_hc(22 端口) 探针完全对齐:

# tf-infra/l4-lb.tf resource "google_compute_region_backend_service" "l4_lb_backend" { name = "poc-l4-lb-backend-service" region = var.region protocol = "TCP" port_name = "ssh" # 显式匹配 UnMIG 中的 ssh 22 端口 load_balancing_scheme = "EXTERNAL" health_checks = [google_compute_region_health_check.l4_lb_hc.id] backend { group = google_compute_instance_group.poc_unmig.id } }

4. 验证结果

提交代码至 GitHubmain分支触发 CI/CD 自动apply后,资源拉起并自动触发自愈逻辑。

1. GCP Backend Service 健康状态

$ gcloud compute backend-services get-health poc-l4-lb-backend-service--region=europe-west2 --- backend:.../instanceGroups/poc-unmanaged-instance-group status: healthStatus: - forwardingRuleIp:34.39.47.144 healthState: HEALTHY instance:.../instances/poc-internal-vm ipAddress:192.168.0.2 port:22

探针成功复活,显示为HEALTHY💚!

2. 公网连通性与 SSH Banner 验证

对 L4 LB 静态公网 IP34.39.47.144进行端口连接与 Banner 抓取:

$nc-zv-w534.39.47.14422Connection to34.39.47.14422port[tcp/ssh]succeeded!$ ssh-keyscan-trsa,ed2551934.39.47.144# 34.39.47.144:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u734.39.47.144 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGAND/947jA3pDd3...

端口畅通,且正确返回了目标内网 VM 的 OpenSSH 8.4 Banner,验证全流程圆满解决!


5. 总结与云原生避坑指南

  1. Passthrough LB 依赖 Guest Agent:GCP 4 层 External NLB 不做 DNAT 替换,VM 必须运行google-guest-agent才能接收发往 LB IP 的直通流量。
  2. 开机脚本预防抢锁死锁:在 Cloud-Init 或 Startup Script 中运行apt-get时,务必考虑并发锁竞争;重要服务(如sshd)建议在脚本末尾显式加入ssh-keygen -Asystemctl reset-failed逻辑。
  3. 端口映射要显式匹配:在 Instance Group 中定义named_port时,L4 与 L7 Backend Service 均应明确指定port_name,避免因默认映射引发健康探针端口不一致。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询