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避免因默认映射引发健康探针端口不一致。