GCP L4 Passthrough 负载均衡器“假死超时”深度排查复盘
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--regioneurope-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-frontendgoogle-guest-agent 生成 HostKeys 失败 (拿不到锁)sshd 无秘钥抛出 no hostkeys available 挂掉systemd 重试 5 次被频率限制锁定为 Failedgoogle-guest-agent-manager 进程崩溃google-guest-agent.service 未能在系统启动Linux 内核缺少 34.39.47.144 的本地 VIP 别名路由GCP Passthrough LB 转发的数据包被 VM 内核静默丢弃UnMIG 仅定义 http:80, 未指定 ssh:22Backend Service 默认匹配 80 端口Health Check (22) 与 Backend 目标端口 (80) 错配报 UNHEALTHYGCP SDN (Andromeda) 入口静默丢包 (Connection timed out)根因 1DPKG 锁争抢引发 OpenSSH Host Key 缺失与 systemd 熔断在gcevm.tf中配置metadata_startup_script后Terraform 替换重建了 VM。在新机器首秒启动时锁争抢 (Lock Contention)开机脚本的第一行命令apt-get update apt-get install -y nginx独占了全局包管理锁/var/lib/dpkg/lock-frontend。秘钥生成失败GCP 的 OS 初始化脚本在尝试通过dpkg-reconfigure openssh-server为新机器生成独立的主机秘钥Host Keys如/etc/ssh/ssh_host_rsa_key时因拿不到 DPKG 锁而抛错中断。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.systemd 频率保护熔断systemd连续重启ssh.service5 次均因缺秘钥而失败触发了Start request repeated too quickly保护熔断彻底将sshd锁定在Failed状态更恶劣的是因上次 unclean shutdown 留下的中断状态后续开机引发了E: dpkg was interrupted, you must manually run dpkg --configure -a的连锁死锁。根因 2GCP L4 Passthrough 流量转发模型与google-guest-agent的本地 VIP 路由这是解决“为什么内网能连走 LB 静态 IP 超时”的技术核心。GCP 的 L4 External Network Load Balancer 属于Passthrough (包直通模式)数据包特征公网客户端发送给 LB 地址34.39.47.144:22的数据包经由 GCP SDN 转发后数据包到达 VM 网卡ens4IP192.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根因 3UnMIG 端口名称 (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_FRONTENDnoninteractive # 1. 自动修复先前可能因抢锁中断的 dpkg 状态 dpkg --configure -a || true # 2. 安装与启动 Nginx Web 服务 apt-get update apt-get install -y nginx echo h1Hello 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.tf与tf-infra/l4-lb.tf端口显式映射与对齐在 UnMIG 中显式暴露ssh: 22与http: 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--regioneurope-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探针成功复活显示为HEALTHY2. 公网连通性与 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-5deb11u734.39.47.144 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGAND/947jA3pDd3...端口畅通且正确返回了目标内网 VM 的 OpenSSH 8.4 Banner验证全流程圆满解决5. 总结与云原生避坑指南Passthrough LB 依赖 Guest AgentGCP 4 层 External NLB 不做 DNAT 替换VM 必须运行google-guest-agent才能接收发往 LB IP 的直通流量。开机脚本预防抢锁死锁在 Cloud-Init 或 Startup Script 中运行apt-get时务必考虑并发锁竞争重要服务如sshd建议在脚本末尾显式加入ssh-keygen -A与systemctl reset-failed逻辑。端口映射要显式匹配在 Instance Group 中定义named_port时L4 与 L7 Backend Service 均应明确指定port_name避免因默认映射引发健康探针端口不一致。