排查元数据服务器访问问题


本文档介绍如何解决 Compute Engine 元数据服务器的问题。

Compute Engine 虚拟机将元数据存储在元数据服务器上。虚拟机会自动获得对元数据服务器 API 的访问权限,而无需任何额外的授权。但是,虚拟机有时可能会因以下原因之一而无法访问元数据服务器:

  • 无法解析元数据服务器域名
  • 与元数据服务器的连接会被以下某项阻止:
    • 操作系统级层防火墙配置
    • 代理设置
    • 自定义路由

当虚拟机无法访问元数据服务器时,某些进程可能会失败。

如需了解如何对 gke-metadata-server 进行问题排查,请参阅排查 GKE 身份验证问题

准备工作

  • 如果您尚未设置身份验证,请进行设置。身份验证是通过其进行身份验证以访问 Google Cloud 服务和 API 的过程。如需从本地开发环境运行代码或示例,您可以选择以下任一选项向 Compute Engine 进行身份验证:

    Select the tab for how you plan to use the samples on this page:

    Console

    When you use the Google Cloud console to access Google Cloud services and APIs, you don't need to set up authentication.

    gcloud

    1. Install the Google Cloud CLI, then initialize it by running the following command:

      gcloud init
    2. Set a default region and zone.
    3. REST

      如需在本地开发环境中使用本页面上的 REST API 示例,请使用您提供给 gcloud CLI 的凭据。

        Install the Google Cloud CLI, then initialize it by running the following command:

        gcloud init

      如需了解详情,请参阅 Google Cloud 身份验证文档中的使用 REST 时进行身份验证

排查服务器代码问题

当您调用 Compute Engine 元数据服务器时,系统会返回以下服务器代码。请参阅本部分,了解如何响应元数据服务器返回的每个服务器代码。

常见服务器代码

这些服务器代码通常由元数据服务器返回。

服务器代码 说明 解决方法
200 OK:请求成功 不适用
400 Bad Request:在许多不同情况下,系统都会返回此错误状态,例如请求包含不当的查询参数或未满足相应端点的要求。 查看错误消息,了解有关如何修正错误的建议
404 未找到:请求的端点不存在 修正请求路径
429 请求过多:这是因为某些端点使用速率限制来防止后备服务过载 请等待几秒钟,然后重试通话
503 服务不可用:元数据服务器尚未准备好提供服务。在以下任一情况下,元数据服务器都可能会返回 Error 503 状态代码:
  • 元数据服务器仍在启动
  • 元数据服务器正在迁移
  • 元数据服务器暂时不可用
  • 宿主机正在执行维护事件
503 错误是暂时性的,最多几秒钟后应该就会解决。如需解决此问题,请等待几秒钟,然后重试通话

罕见的服务器代码

虽然很少见,但元数据服务器也可能会返回这些服务器代码。

服务器代码 说明 解决方法
301 永久移除:适用于包含重定向的路径 更新请求路径
403 Forbidden:如果元数据服务器认为请求不安全,则会返回此值。如果您与服务器的 TCP 连接在网络层关闭,就可能会发生这种情况。 检查您的网络配置
405 不允许:如果请求了不受支持的方法,系统会返回此错误代码。

元数据服务器仅支持 GET 操作,但支持写入的访客元数据除外,该元数据支持 SET 操作。
更新请求路径中的相应方法

重试指南

元数据服务器通常会返回 503 和 429 错误代码。为了使您的应用能够应对各种问题,我们建议您为查询元数据服务器的应用实现重试逻辑。我们还建议您在脚本中实现指数退避算法,以应对任何可能的速率限制。

排查对元数据服务器失败的请求

以下是您的虚拟机可能无法访问元数据服务器时可能会遇到的错误示例:

curl: (6) Could not resolve host: metadata.google.internal
postAttribute error: Put "http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/guestInventory/ShortName": dial tcp: lookup metadata.google.internal on [::1]:53: read udp [::1]:58319->[::1]:53: read: connection refused

如果您的虚拟机失去对元数据服务器的访问权限,请执行以下操作:

Linux

  1. 连接到您的 Linux 虚拟机。
  2. 从您的 Linux 虚拟机运行以下命令,以测试与元数据服务器的连接:

    1. 查询域名服务器:

      nslookup metadata.google.internal

      输出应类似如下所示:

      Server:         169.254.169.254
      Address:        169.254.169.254#53
      
      Non-authoritative answer:
      Name:   metadata.google.internal
      Address: 169.254.169.254
      
    2. 检查元数据服务器是否可访问。如需进行验证,请运行以下命令:

      ping -c 3 metadata.google.internal

      输出应类似如下所示:

      PING metadata.google.internal (169.254.169.254) 56(84) bytes of data.
      64 bytes from metadata.google.internal (169.254.169.254): icmp_seq=1 ttl=255 time=0.812 ms
      
      ping -c 3 169.254.169.254

      输出应类似如下所示:

      PING 169.254.169.254 (169.254.169.254) 56(84) bytes of data.
      64 bytes from 169.254.169.254: icmp_seq=1 ttl=255 time=1.11 ms
      
    3. 如果上述命令的输出与建议的输出相符,则您的虚拟机已连接到元数据服务器,无需执行进一步操作。如果命令失败,请执行以下操作:

      1. 检查域名服务器是否已配置为元数据服务器:

        cat /etc/resolv.conf

        输出应类似如下所示:

        domain ZONE.c.PROJECT_ID.internal
        search ZONE.c.PROJECT_ID.internal. c.PROJECT_ID.internal. google.internal.
        nameserver 169.254.169.254
        

        如果输出没有上述行,请参阅操作系统文档,了解如何修改 DHCP 政策以将域名服务器配置保留为 169.254.169.254。 这是因为如果对项目中的虚拟机应用可用区级 DNS 设置,则对 /etc/resolv.conf 的更改会在一小时内被覆盖。如果您的项目仍在使用全局 DNS,则 resolv.conf 文件将在 24 小时内还原为默认 DHCP。

      2. 检查元数据服务器域名与其 IP 地址之间的映射是否存在:

        cat /etc/hosts

        输出中应包含以下行:

        169.254.169.254 metadata.google.internal  # Added by Google
        

        如果输出没有上述行,请运行以下命令:

        echo "169.254.169.254 metadata.google.internal" >> /etc/hosts

Windows

  1. 连接到您的 Windows 虚拟机。
  2. 从 Windows 虚拟机运行以下命令:

    1. 查询域名服务器:

      nslookup metadata.google.internal

      输出应类似如下所示:

      Server:  UnKnown
      Address:  10.128.0.1
      
      Non-authoritative answer:
      Name:    metadata.google.internal
      Address:  169.254.169.254
      
    2. 检查元数据服务器是否可访问。如需进行验证,请运行以下命令:

      ping -n 3 metadata.google.internal

      输出应类似如下所示:

      Pinging metadata.google.internal [169.254.169.254] with 32 bytes of data:
      Reply from 169.254.169.254: bytes=32 time=1ms TTL=255
      

      ping -n 3 169.254.169.254

      输出应类似如下所示:

      Pinging metadata.google.internal [169.254.169.254] with 32 bytes of data:
      Reply from 169.254.169.254: bytes=32 time=1ms TTL=255
      
    3. 如果上述命令的输出与建议的输出相符,则您的虚拟机已连接到元数据服务器,无需执行进一步操作。如果命令失败,请执行以下操作:

      1. 运行以下命令,检查是否存在指向元数据服务器的永久性路由:

        route print

        输出应该包含以下内容:

        Persistent Routes:
        Network Address          Netmask  Gateway Address  Metric
        169.254.169.254  255.255.255.255         On-link        1
        

        如果输出没有上述行,请使用以下命令添加路由:

        $Adapters = Get-NetKVMAdapterRegistry
        $FirstAdapter = $Adapters | Select-Object -First 1
        route /p add 169.254.169.254 mask 255.255.255.255 0.0.0.0 'if' $FirstAdapter.InterfaceIndex metric 1
      2. 检查元数据服务器域名与其 IP 地址之间的映射是否存在:

        type %WINDIR%\System32\Drivers\Etc\Hosts

        输出中应包含以下行:

        169.254.169.254 metadata.google.internal  # Added by Google
        

        如果输出没有上述行,请运行以下命令:

        echo 169.254.169.254 metadata.google.internal >> %WINDIR%\System32\Drivers\Etc\Hosts

对使用网络代理时失败的请求进行问题排查

网络代理服务器会阻止虚拟机直接访问互联网。从虚拟机内部发送的所有查询都改由代理服务器处理。

使用从元数据服务器获取凭据(如身份验证令牌)的应用时,虚拟机需要直接访问元数据服务器。 如果虚拟机位于代理后面,您必须为 IP 地址和主机名设置 NO_PROXY 配置。

如果您未设置 NO_PROXY 配置时,您可能会在运行 Google Cloud CLI 命令或直接查询元数据服务器时看到错误,因为调用 metadata.google.internal 将发送到代理,而无需在实例本地进行本地解析。

以下是您可能会看到的错误示例:

ERROR 403 (Forbidden): Your client does not have permission to get URL

如需解决此代理问题,请执行以下操作,从而将元数据服务器主机名和 IP 地址添加到环境变量 NO_PROXY 中:

Linux

  1. 连接到您的 Linux 虚拟机。
  2. 从 Linux 虚拟机运行以下命令:

    export no_proxy=169.254.169.254,metadata,metadata.google.internal

    如需保存更改,请运行以下命令:

    echo no_proxy=169.254.169.254,metadata,metadata.google.internal >> /etc/environment

Windows

  1. 连接到您的 Windows 虚拟机。
  2. 从 Windows 虚拟机运行以下命令:

    set NO_PROXY=169.254.169.254,metadata,metadata.google.internal

    如需保存更改,请运行以下命令:

    setx NO_PROXY 169.254.169.254,metadata,metadata.google.internal /m

排查对 HTTPS 元数据服务器端点的失败请求

本部分介绍了您在查询 HTTPS 元数据服务器端点时可能会看到的一些错误。

当您使用 cURL 工具进行查询时,系统会返回本部分列出的错误,但对于其他工具,返回的错误消息类似。

客户端证书不正确

如果您为 -E 标志提供的值不正确,则会发生以下错误。

  • curl: (56) OpenSSL SSL_read: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate
    required, errno 0
  • curl: (58)  unable to set private key file:
  • curl: (58) could not load PEM client certificate, OpenSSL error error:02001002:system library:fopen:No such file or directory

如需解决此问题,请提供客户端身份证书的正确路径。如需查看客户端身份证书的位置,请参阅客户端身份证书

主机名不正确

如果在证书中找不到用于访问元数据服务器的主机名,就会发生以下错误。

curl: (60) SSL: no alternative certificate subject name matches target host name

如需解决此问题,请验证查询中的根网址或主机名是否为 metadata.google.internal。如需详细了解元数据服务器的根网址,请参阅元数据请求的各部分

根证书或客户端证书不正确

查询 HTTPS 元数据服务器端点时,您可能会看到以下错误:

curl: (77) error setting certificate verify locations:

这种情况可能发生在以下场景中:

  • --cacert 标志的路径可能格式不正确
  • 信任存储区中可能缺少根证书

如需解决此问题,您需要在查询 https 端点时同时指定根证书和客户端证书。如需了解证书位置,请参阅证书存储位置

例如,如需查询虚拟机的启动映像,请运行以下查询:

user@myinst:~$ curl "https://metadata.google.internal/computeMetadata/v1/instance/image" \
    -E /run/google-mds-mtls/client.key \
    --cacert /run/google-mds-mtls/root.crt \
    -H "Metadata-Flavor: Google"

排查标头格式不正确的问题

元数据服务器会执行格式检查,以确保标头符合标头格式准则 RFC 7230 第 3.2 节。如果标头格式未能通过这些检查,则会发生以下情况:

  • 请求被接受。但是,您会收到建议,告知您虚拟机使用格式错误的标头向元数据服务器发出请求。系统只为每个虚拟机发送一次建议。您可以使用 Google Cloud CLI 或 Recommender REST API 访问这些建议。

    应用建议后,将建议状态设置为 succeeded

  • 从 2024 年 1 月 20 日开始,元数据服务器会拒绝标头格式不正确的请求。

下面显示了有效和无效标头请求格式的示例。

无效:标头名称和冒号之间包含空格

Metadata-Flavor : Google

有效:标头名称和冒号之间没有空格,检查器会忽略冒号后面的空格

Metadata-Flavor: Google

有效:标头中不含空格

Metadata-Flavor:Google

如需详细了解如何向元数据服务器发出查询,请参阅访问虚拟机元数据