存储和检索实例元数据

每个实例都会将其元数据存储在元数据服务器上。您可以使用 Compute Engine API 在实例上以编程方式查询元数据服务器,以获取有关实例的信息,例如实例的主机名、实例 ID、启动和关闭脚本、自定义元数据以及服务帐号信息。您的实例可自动获得对元数据服务器 API 的访问权限,而无需任何额外的授权。

元数据服务器在与启动关停脚本结合使用时会特别有用,因为您可以使用元数据服务器以编程方式获取实例的专属信息,而无需额外的授权。例如,您可以编写一个启动脚本来获取实例外部 IP 地址的元数据键值对,并在您的脚本中使用该 IP 来设置数据库。 由于所有实例的默认元数据键都相同,因此您可以重复使用您的脚本,而无需针对每个实例更新该脚本。这有助于您为应用创建较不易出错的代码。

元数据以 key:value 格式存储。每个实例都可以访问一组默认的元数据条目。您还可以设置自定义元数据

如要访问元数据服务器,您可以查询元数据网址

当前版本:v1

Compute Engine 一次可以提供多个元数据版本,但我们建议您始终使用可用的最新元数据服务器版本。Compute Engine 会随时向元数据服务器添加新条目,也会随时向响应添加新字段。请定期回来查看变化情况。

如需了解如何检查元数据服务器端点的版本,请参阅检查服务器端点的版本

v1beta1 与 v0.1 元数据服务器端点已弃用,并将按计划关停。请务必将所有请求更新为使用 v1。如需了解详情,请参阅转换到 v1 元数据服务器端点

准备工作

执行此任务所需的权限

如需执行此任务,您必须拥有以下权限

  • 针对实例的 compute.instances.setMetadata 权限(如果要设置实例元数据)
  • 针对项目的 compute.projects.setCommonInstanceMetadata 权限(如果要设置项目级元数据)
  • 针对项目的 compute.projects.get 权限(如果只需获取元数据)
  • 针对实例的 compute.instances.get 权限(如果只需获取元数据)

项目元数据和实例元数据

您可以为项目和实例分配元数据。项目元数据会传播到项目内的所有虚拟机 (VM) 实例,而实例元数据只会对该实例产生影响。

默认元数据键

Compute Engine 定义了一组默认元数据条目,用于提供有关您实例或项目的信息。默认元数据始终由服务器定义和设置,您无法手动修改其中任何元数据对。

以下是项目可用的默认元数据。某些元数据条目是包含其他元数据键的目录。此类条目的元数据名称会以斜杠结尾,因此很容易识别。例如,attributes/ 是包含其他键的目录,而 numeric-project-id 是映射到值的元数据键。

相对于 http://metadata.google.internal/computeMetadata/v1/project/
元数据条目 说明
attributes/ 为此项目设置的自定义元数据值的目录。
attributes/disable-legacy-endpoints 对此项目中的所有实例停用旧版元数据服务器端点。除非您的项目使用旧版端点,否则请务必设置 disable-legacy-endpoints=TRUE。请将您的应用更新为使用 v1 端点。
attributes/enable-oslogin 如果您设置了 enable-oslogin=TRUE,则会对您的项目启用 OS Login SSH 密钥管理功能。
attributes/vmdnssetting 配置如何针对您项目中的实例设置内部 DNS 名称的格式。如需详细了解内部 DNS 名称,请参阅配置 DNS 名称
attributes/ssh-keys 如果您的项目和实例未配置为使用 OS Login 进行 SSH 密钥管理,您可以使用此特性来配置 SSH 公钥,以用于连接此项目中的实例。如果有多个 SSH 密钥,则各个密钥之间将以换行符 (\n) 分隔。此值为一个字符串。由 OS Login 管理的 SSH 密钥不会显示在此元数据值中。

示例"user1:ssh-rsa mypublickey user1@host.com\nuser2:ssh-rsa mypublickey user2@host.com"

numeric-project-id 此实例的数字项目 ID(项目编号)(而非 Google Cloud Console 中显示的项目名称)。此值与 project-id 元数据条目值不同。
project-id 项目 ID

以下是实例的默认元数据列表:

相对于 http://metadata.google.internal/computeMetadata/v1/instance/
元数据条目 说明
attributes/ 在启动或关停期间传递给此实例的自定义元数据值的目录。请参阅下面的指定自定义元数据
attributes/enable-oslogin 如果您设置了 enable-oslogin=TRUE,则会对此实例启用 OS Login SSH 密钥管理功能。
attributes/vmdnssetting 配置如何针对此实例设置内部 DNS 名称的格式。如需详细了解内部 DNS 名称,请参阅配置 DNS 名称
attributes/ssh-keys 如果您的实例未配置为使用 OS Login 进行 SSH 密钥管理,您可以使用此特性配置 SSH 公钥,以用于连接此实例。如果有多个 SSH 密钥,则各个密钥之间将以换行符 (\n) 分隔。此值为一个字符串。由 OS Login 管理的 SSH 密钥不会显示在此元数据值中。

示例"user1:ssh-rsa mypublickey user1@host.com\nuser2:ssh-rsa mypublickey user2@host.com"

cpu-platform 实例的 CPU 平台。
description 此实例的自由文本说明;可以使用 --description 标志分配或在 API 中设置。
disks/ 挂接到此实例的磁盘目录。
guest-attributes/ 自定义实例元数据值,可用于发布有关不常更改状态的通知、少量数据或更改次数很少的数据。这些值可用于指示启动脚本的完成时间,或用于向其他应用提供有关其他不常见状态的通知。虚拟机实例上的任何用户或进程都可以对“guest-attributes”元数据中的命名空间和键执行读写操作。
hostname 此实例的主机名。
id 此实例的 ID。这是由 Compute Engine 生成的唯一数字 ID。如果您不想使用实例名称,则此 ID 可以帮助您有效识别实例。
machine-type 此实例的机器类型的元数据值,其格式如下:projects/[NUMERIC_PROJECT_ID]/machineTypes/[MACHINE_TYPE]
name 实例名称。
network-interfaces/ 此实例的网络接口目录。
network-interfaces/<index>/forwarded-ips/ 针对位于 <index> 的网络接口,当前指向此虚拟机实例的所有外部 IP 地址的目录。具体来说,此元数据条目提供外部 IP 列表,这些外部 IP 由将数据包引向此实例的转发规则处理。
scheduling/ 包含实例调度选项的目录。
scheduling/on-host-maintenance 此实例的透明维护事件行为设置。您可以使用 --on_host_maintenance 标志或通过 API 设置此值。
scheduling/automatic-restart 此实例的自动重启设置。您可以使用 ‑‑automatic_restart 标志或通过 API 设置此值。
scheduling/preemptible 此实例的抢占式设置。如果此值为 TRUE,则表示此实例为抢占式实例。该值是在您创建实例时设置的,无法更改。
maintenance-event 指示透明维护事件正影响此实例的路径。如需了解详情,请参阅透明维护通知
service-accounts/ 与此实例关联的服务帐号的目录。
service-accounts/<service-account-name>/identity 此实例独有的 JSON Web 令牌。您必须在针对此实例元数据值的请求中加入“audience”参数。例如,“?audience=http://www.example.com”。如需了解如何请求和验证实例身份令牌,请参阅验证实例身份
tags 与实例关联的任何标记
zone 运行此实例的地区的元数据值。该值的格式如下: projects/[NUMERIC_PROJECT_ID]/zones/[ZONE]

获取元数据

如要查询元数据服务器的内容,您可以从虚拟机实例中向以下根网址发出请求。请使用 http://metadata.google.internal/computeMetadata/v1/ 网址向元数据服务器发出请求。

所有元数据值都会定义为这些根网址下面的子路径。

您只能从关联的实例中查询默认元数据值,而不能从其他实例或者直接从本地计算机查询实例的默认元数据。您可以使用 curlwget 等标准工具,从实例中查询其元数据服务器。

在查询元数据时,您必须在您的所有请求中提供以下标头:

Metadata-Flavor: Google

此标头指示请求是为了检索元数据值而发出的(而非由不安全的来源意外发出),并且允许元数据服务器返回您请求的数据。如果您不提供此标头,则元数据服务器会拒绝您的请求。

X-Forwarded-For 标头

元数据服务器会自动拒绝任何包含 X-Forwarded-For 标头的请求。此标头通常指示请求已被代理,可能不是已获授权的用户发出的请求。出于安全考虑,所有此类请求都会遭到拒绝。

限制

请注意,使用 curl 命令在服务器中检索元数据时,请求路径不支持某些编码字符。编码字符仅在查询路径中受支持。

例如,以下请求可能无法正常运行:

http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/123456789-compute%40developer.gserviceaccount.com/?query_path=https%3A%2F%2Flocalhost%3A8200%2Fexample%2Fquery&another_param=true

为使此请求能够正常运行,您必须将请求路径中不受支持的编码字符 (%40) 替换为等效的受支持值 (@)。

http://metadata.google.internal/computeMetadata/v1/instance/service-accounts1234567898-compute@developer.gserviceaccount.com/?query_path=https%3A%2F%2Flocalhost%3A8200%2Fexample%2Fquery&another_param=true

下表汇总了请求路径不支持的编码字符。

编码字符 接受的值
%21

!
%24

$
%27

'
%28

(
%29

)
%2A

*
%2C

,
%40

@

元数据信息是否安全?

当您发出从元数据服务器获取信息的请求时,您的请求和后续元数据响应永远不会在运行虚拟机实例的物理主机外执行。

查询目录列表

元数据服务器使用目录来整理某些元数据键。以斜杠结尾的元数据条目表示目录。例如,disks/ 条目是包含挂接到该实例的磁盘的目录:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/" -H "Metadata-Flavor: Google"

0/
1/
2/

同样,如果您需要进一步了解 0/ 磁盘目录,可以查询该目录的特定网址:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/0/" -H "Metadata-Flavor: Google"

device-name
index
mode
type

查询端点

元数据键如果不是目录,就是返回一个或多个值的端点。例如,要查询特定磁盘的模式,请查询以下端点:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/0/mode" -H "Metadata-Flavor: Google"

READ_WRITE

默认情况下,每个端点都有一种预定义的响应格式。某些端点可能会默认返回 JSON 格式的数据,而其他端点则可能会返回字符串格式的数据。您可以使用 alt=jsonalt=text 查询参数替换默认的数据格式规范,这些参数分别会返回 JSON 字符串格式的数据或纯文本形式的数据。

例如,tags 键会自动返回 JSON 格式的数据。您可以指定 alt=text 查询参数,以改为返回文本格式的数据:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags" -H "Metadata-Flavor: Google"

["bread","butter","cheese","cream","lettuce"]
user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?alt=text" -H "Metadata-Flavor: Google"

bread
butter
cheese
cream
lettuce

以递归方式查询元数据

如果要返回某个目录下的所有内容,请在您的请求中使用 recursive=true 查询参数:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true" -H "Metadata-Flavor: Google"

[{"deviceName":"boot","index":0,"mode":"READ_WRITE","type":"PERSISTENT"},
{"deviceName":"persistent-disk-1","index":1,"mode":"READ_WRITE","type":"PERSISTENT"},
{"deviceName":"persistent-disk-2","index":2,"mode":"READ_ONLY","type":"PERSISTENT"}]

默认情况下,递归内容会以 JSON 格式返回。如果您希望以文本格式返回这些内容,请附加 alt=text 查询参数:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/disks/?recursive=true&alt=text" -H "Metadata-Flavor: Google"

0/device-name boot
0/index 0
0/mode READ_WRITE
0/type PERSISTENT
1/device-name persistent-disk-1
1/index 1
1/mode READ_WRITE
1/type PERSISTENT
2/device-name persistent-disk-1
2/index 2
2/mode READ_ONLY
2/type PERSISTENT

设置自定义元数据

您可以通过 Google Cloud Consolegcloud 命令行工具或 Compute Engine API 为实例或项目设置自定义元数据。如果您要将任意值传递给您的项目或实例,或设置启动关停脚本,自定义元数据会很有用。

自定义元数据大小限制

Compute Engine 会对自定义元数据值的长度实施以下限制:

  • 每个元数据条目的长度为 256 KB
  • 每个实例的所有元数据条目的总长度为 512 KB

尤其需要注意的是,SSH 密钥会以自定义元数据的形式存储在 ssh-keys 密钥下。如果此密钥的元数据内容超过 256 KB 的限制,您将无法添加更多 SSH 密钥。如果您受到此限制约束,请考虑移除未使用的密钥以为新密钥释放元数据空间。

如果您直接提供启动关停脚本内容,则启动和关停脚本内容也可能会存储为自定义元数据,并计入这些大小限制。为了避免出现这种情况,请将启动关停脚本存储为文件,并将其托管在 Cloud Storage 等外部位置,然后在创建实例时提供启动脚本网址。这些文件会下载到虚拟机实例上,而不是存储在元数据服务器中。

设置实例元数据

您可以使用 Cloud Consolegcloud 工具或 API 设置实例的自定义元数据。实例元数据仅适用于特定实例。

在创建实例期间设置元数据

控制台

  1. 在 GCP Console 中,转到虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 点击创建实例
  3. 创建新实例页面上,填写实例的属性。
  4. 元数据部分中,根据需求为您的自定义元数据填写任意数量的键值对。
  5. 点击创建以创建实例。

gcloud

gcloud 命令行工具中,使用 --metadata 标志设置自定义元数据。

gcloud compute instances create example-instance --metadata foo=bar

API

在 API 中,提供自定义元数据作为请求中元数据属性的一部分:

POST https://compute.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances

{
  "...
        }
      ]
    }
  ],
  "metadata": {
    "items": [
      {
       "key": "foo",
       "value": "bar"
      }
    ]
  },
  ..
}

更新正在运行的实例的元数据

控制台

  1. 在 Google Cloud Console 中,转到虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 点击您想要更新其元数据的实例。
  3. 点击页面顶部的修改按钮。
  4. 自定义元数据下,点击添加一项或修改现有的元数据条目。
  5. 保存更改。

gcloud

使用 gcloud 工具更新实例元数据是一项附加性操作。请仅指定您要添加或更改的元数据键。如果您提供的键已经存在,则系统将使用新值来更新该键对应的值。

gcloud 命令行工具中,使用 instances add-metadata 命令:

gcloud compute instances add-metadata INSTANCE \
  --metadata bread=mayo,cheese=cheddar,lettuce=romaine

如果您要将 lettuce=romaine 条目更改为 lettuce=green,请使用以下命令:

gcloud compute instances add-metadata INSTANCE --metadata lettuce=green

如果您要移除 lettuce=romaine 条目,请指定现有键并排除对应的值。

gcloud compute instances remove-metadata INSTANCE --keys lettuce

API

在 API 中,向 instances().setMetadata 方法发出请求。请提供新元数据值和当前 fingerprint 值的列表。

指纹是由 Compute Engine 生成的随机字符串,可用于执行乐观锁定。请提供匹配的指纹值以执行您的请求。每次请求后指纹都会更改,因此如果您提供的指纹不匹配,请求将被拒绝。如此,一次就只能进行一项更新,以免发生冲突。

要获取实例的当前指纹并查看实例的任何现有键值对,请发送 instances().get 请求:

GET https://compute.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/example-instance

{
 ...
 "name": "example-instance",
 "metadata": {
  "kind": "compute#metadata",
  "fingerprint": "zhma6O1w2l8="
  "items": [
   {
    "key": "foo",
    "value": "bar"
   }
  ]
 },
 ...
}

接下来,向 instances().setMetadata 方法发出请求,并设置您的自定义元数据键值对。如果您想要保留实例的现有键值对,则必须将这些现有键值对和新键值对都加入此请求中:

POST https://compute.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/example-instance/setMetadata

{
 "fingerprint": "zhma6O1w2l8=",
 "items": [
  {
   "key": "foo",
   "value": "bar"
  },
  {
   "key": "baz",
   "value": "bat"
  }
 ]
}

如要从实例中移除所有元数据键值对,请指定 instances().setMetadata 请求并排除 items 属性。请注意,您仍必须添加当前的元数据指纹属性,这样此请求才能成功:

POST https://compute.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/example-instance/setMetadata

{
 "fingerprint": "5rC_DXxBUZw="
}

设置项目级自定义元数据

您可以设置项目级元数据,以将元数据应用于项目中的所有实例。 例如,如果您定义了项目级元数据对 baz=bat,则该元数据对将自动应用于项目中的所有实例。

控制台

  1. 在 Google Cloud Console 中,转到元数据页面。

    转到“元数据”页面

  2. 点击修改
  3. 添加或修改元数据条目。
  4. 保存更改。

gcloud

gcloud 命令行工具中,使用 project-info add-metadata 命令。例如:

gcloud compute project-info add-metadata --metadata foo=bar,baz=bat

使用 describe 命令查看元数据:

gcloud compute project-info describe

例如,您可能会得到类似如下内容的响应:

...
commonInstanceMetadata:
  fingerprint: RfOFY_-eS64=
  items:
  - key: baz
    value: bat
  - key: foo
    value: bar
  - key: ssh-keys
...

请使用等号指定一个元数据键值对,例如 key=value;如果有多个键值对,请使用空格进行分隔。

您可以视情况使用 --metadata-from-file 标志指定一个或多个要从中读取元数据的文件。您可以使用 project-info remove-metadata 命令移除元数据值。

API

在 API 中,向 projects().setCommonInstanceMetadata 方法发出请求,并提供所有新元数据值和 fingerprint 值。

指纹是由 Compute Engine 生成的随机字符串,可用于执行乐观锁定。请提供匹配的指纹值以执行您的请求。每次请求后指纹都会更改,因此如果您提供的指纹不匹配,请求将被拒绝。如此,一次就只能进行一项更新,以免发生冲突。

要获取实例的当前指纹,请执行 project().get 请求并复制指纹值:

GET https://compute.googleapis.com/compute/v1/projects/myproject

{
 "name": "myproject",
 "commonInstanceMetadata": {
  "kind": "compute#metadata",
  "fingerprint": "FikclA7UBC0=",
  ...
}

接着,向 projects().setCommonInstanceMetadata 方法发出请求,并设置您的自定义元数据键值对:

POST https://compute.googleapis.com/compute/v1/projects/myproject/setCommonInstanceMetadata

{
 "fingerprint": "FikclA7UBC0=",
 "items": [
  {
   "key": "foo",
   "value": "bar"
  }
 ]
}

查询自定义元数据

您可以通过 Cloud Console、gcloud 命令行工具或 API 查询自定义实例或项目元数据。

控制台

如需查看项目级自定义元数据,请转到元数据页面。

要查看实例的自定义元数据,请执行以下操作:

  1. 转到“虚拟机实例”页面
  2. 点击您要查看其元数据的实例。
  3. 自定义元数据下方,查看该实例的自定义元数据。

gcloud

查询项目元数据:

gcloud compute project-info describe --flatten="commonInstanceMetadata[]"

查询实例元数据:

gcloud compute instances describe example-instance --flatten="metadata[]"

使用 --flatten 标志将输出范围限定为相关的元数据键。例如,以下实例的自定义元数据键值对为 foo:bar

$ gcloud compute instances describe example-instance

...
metadata:
  fingerprint: Cad2L9eKNR0=
  items:
  - key: foo
    value: bar
  kind: compute#metadata
...

要查询键 foo 的值,请运行以下命令:

$ gcloud compute instances describe example-instance --flatten="metadata[foo]"

---
  bar

API

要查询项目的元数据,请对 projects().get 方法执行空请求:

GET https://compute.googleapis.com/compute/v1/projects/myproject

要查询实例的元数据,请对 instance().get 方法执行空请求:

GET https://compute.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/example-instance

设置和查询客机特性

客机特性是指应用在实例上运行期间可写入的特定类型的自定义元数据。实例上的任何应用或用户都可以对这些客机特性元数据值执行数据读取和写入操作。

何时使用客机特性

客机特性仅适用于需要少量不常更改的数据的用例,最适合使用客机特性的用例具有以下特征:

  • 每个虚拟机实例的查询次数限制为每分钟最多 10 次查询。
  • 查询作业的爆发速率不超过每秒 3 次查询。如果超出此速率上限,Compute Engine 可能会任意移除正在写入的客机特性。移除此数据是为了确保能将其他关键系统数据写入服务器。

客机属性非常适合您需要发布少量不常见数据的情况。例如,客机特性在以下用例中会很实用:

  • 启动脚本可以通过在客机特性中设置自定义状态值来发送初始化成功信号。
  • 配置管理代理可以将客机操作系统名称和版本发布到客机特性。
  • 库存管理代理可以将虚拟机实例中安装的软件包列表发布到客机特性。
  • 工作负载编排软件可以通过在客机特性中设置自定义状态值,向软件控制层发送客机内部操作的完成信号。

客机特性不能替代事件流、Pub/Sub 或其他形式的数据存储和配置代码库。

对于实例内部的读取和写入操作,元数据服务器会提供实例级的自动身份验证和授权。每个实例只能对自己的元数据服务器执行读取或写入操作。一个实例的元数据服务器不可供其他实例访问。用户和服务帐号只有在其 Cloud Identity and Access Management 角色具备 compute.instances.getGuestAttributes 权限的情况下,才能从实例外部读取实例的客机特性。

在您的实例上启用客机特性

默认情况下,客机特性处于停用状态。要启用客机特性,请在个别实例或项目级元数据中设置必要的元数据值:

控制台

创建实例时,请在实例元数据中设置 enable-guest-attributes

  1. 在 Google Cloud Console 中,转到虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 点击创建实例
  3. 创建新实例页面上,填写所需的实例属性。
  4. 元数据部分中,添加键为 enable-guest-attributes 且值为 TRUE 的元数据条目。
  5. 点击创建以创建实例。

在项目级元数据中设置 enable-guest-attributes,使其应用于项目中的所有实例:

  1. 在 Google Cloud Console 中,转到元数据页面。

    转到“元数据”页面

  2. 点击修改
  3. 添加一个键为 enable-guest-attributes 且值为 TRUE 的元数据条目。或者,将值设置为 FALSE 以停用该功能。
  4. 点击保存以应用更改。

在现有实例的元数据中设置 enable-guest-attributes

  1. 在 Google Cloud Console 中,转到虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 点击要为其设置元数据值的实例的名称。
  3. 在实例详情页面的顶部,点击修改以修改实例设置。
  4. 自定义元数据下方,添加一个元数据条目,其中键为 enable-guest-attributes,值为 TRUE。或者,将值设置为 FALSE 以在实例上停用该功能。
  5. 在实例详情页面的底部,点击保存以将更改应用于实例。

gcloud

创建实例时,请在实例元数据中设置 enable-guest-attributes

gcloud 命令行工具中使用 gcloud compute instances create 命令,并设置 enable-guest-attributes=TRUE 以启用客机特性:

gcloud compute instances create [INSTANCE_NAME] --metadata enable-guest-attributes=TRUE

在项目级元数据中设置 enable-guest-attributes,使其应用于项目中的所有实例

gcloud 命令行工具中使用 project-info add-metadata 命令,并设置 enable-guest-attributes=TRUE 以启用客机特性:

gcloud compute project-info add-metadata --metadata enable-guest-attributes=TRUE

您也可以将 enable-guest-attributes 设为 FALSE 以停用客机特性。

在现有实例的元数据中设置 enable-guest-attributes

gcloud 命令行工具中使用 instances add-metadata 命令,并设置 enable-guest-attributes=TRUE 以启用客机特性:

gcloud compute instances add-metadata [INSTANCE_NAME] --metadata enable-guest-attributes=TRUE

您也可以将 enable-guest-attributes 设为 FALSE,以对实例停用客机特性。

设置客机特性

在虚拟机实例中运行的任何进程都可以写入客机特性值,包括没有 sudo 或管理员级权限的脚本和应用。实例外部的用户或服务帐号不能写入客机特性元数据值。

例如,您可以在自己的实例中使用 curl 请求向 guest-attributes 元数据路径写入值:

curl -X PUT --data "[VALUE]" http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/[NAMESPACE]/[KEY] -H "Metadata-Flavor: Google"

其中:

  • [NAMESPACE][KEY] 的逻辑分组。客机特性必须具有命名空间。
  • [VALUE] 是您要写入的值。
  • [KEY]guest-attributes 中用于存储值的路径。

获取客机特性

如果用户或服务帐号的 Cloud IAM 角色具备 compute.instances.getGuestAttributes 权限,则该用户或服务帐号便可读取客机特性。此外,实例中的任何用户或应用也都可以读取该特定实例的元数据值。

在虚拟机中运行的任何进程都可以写入客机特性值,包括没有 sudo 或管理员级权限的脚本和应用。例如,您可以在自己的实例中使用 curl 请求从guest-attributes 元数据路径中读取值:

curl http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/[NAMESPACE]/[KEY] -H "Metadata-Flavor: Google"

其中:

  • [KEY] 是您要从中读取元数据值的 guest-attributes 路径。

您也可以在一个请求中返回所有客机特性值:

curl http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/[NAMESPACE]/ -H "Metadata-Flavor: Google"

其中:

  • [NAMESPACE][KEY] 的逻辑分组。客机特性必须具有命名空间。
  • [KEY]guest-attributes 中用于存储值的路径。

gcloud

使用 gcloud 命令行工具读取实例中的客机特性元数据值。例如,您可以检索实例的所有值:

gcloud compute instances get-guest-attributes [INSTANCE_NAME] --zone [ZONE]

如需检索特定命名空间下的所有值,请加入 --query-path 标志和您定义的命名空间:

gcloud compute instances get-guest-attributes [INSTANCE_NAME] --query-path=[NAMESPACE]/ --zone [ZONE]

如需检索特定命名空间下的所有值,请加入 --query-path 标志、相应命名空间和您所定义值对应的键:

gcloud compute instances get-guest-attributes [INSTANCE_NAME] --query-path=[NAMESPACE]/[KEY] --zone [ZONE]

其中:

  • [INSTANCE_NAME] 是您要从中读取客机特性元数据值的实例的名称。
  • [KEY] 是用于存储值的 guest-attributes 元数据路径。
  • [ZONE] 是实例所在的地区。

API

使用 compute.instances.getguestattributes API 方法:

GET https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/instances/[INSTANCE_NAME]/getGuestAttributes?queryPath=[NAMESPACE]/[KEY]

其中:

  • [PROJECT_ID] 是您的项目 ID。
  • [ZONE] 是您的实例所在的地区。
  • [INSTANCE_NAME] 是您要从中读取客机特性元数据值的实例的名称。
  • [KEY]guest-attributes 元数据中用于存储值的路径。

如需检索 [NAMESPACE] 的所有键,请省略 [KEY]

GET https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/instances/[INSTANCE_NAME]/getGuestAttributes?queryPath=[NAMESPACE]

如需检索该实例在每个命名空间中的所有键,请完全省略 [NAMESPACE]queryPath

GET https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/instances/[INSTANCE_NAME]/getGuestAttributes

或者,如果您有 OAuth 令牌,则可以使用 curl

curl -H "Authorization: Bearer [OAUTH_TOKEN]" https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/instances/[INSTANCE_NAME]/getGuestAttributes?queryPath=[NAMESPACE]/[KEY]

其中:

  • [OAUTH_TOKEN] 是您的 OAuth 令牌。
  • [PROJECT_ID] 是您的项目 ID。
  • [ZONE] 是您的实例所在的地区。
  • [INSTANCE_NAME] 是您要从中读取客机特性元数据值的实例的名称。
  • [NAMESPACE][KEY] 的逻辑分组。客机特性必须具有命名空间。
  • [KEY]guest-attributes 元数据中用于存储值的路径。

删除客机特性

您还可以删除客机特性。例如,使用 curl 删除特定键:

curl -X DELETE http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/[NAMESPACE]/[KEY] -H "Metadata-Flavor: Google"

其中:

  • [NAMESPACE][KEY] 的逻辑分组。客机特性必须具有命名空间。
  • [KEY]guest-attributes 中用于存储值的路径。

对组织或文件夹停用客机特性

如果您不希望您的组织或文件夹中的任何实例启用客机特性,则可以完全替换并停用该功能。

对您的组织或文件夹设置 constraints/compute.disableGuestAttributesAccess 限制条件:

gcloud resource-manager org-policies enable-enforce \
    constraints/compute.disableGuestAttributesAccess --project [PROJECT_ID]

其中:

  • [PROJECT_ID] 是您的项目的名称。

如需详细了解如何设置和管理针对组织的限制条件,请参阅使用限制条件

等待更新

鉴于元数据值可能会在实例运行时发生更改,元数据服务器会使用 wait-for-change 功能来接收元数据更改通知。借助这项功能,您可以执行挂起的 HTTP GET 请求,让系统仅在您指定的元数据发生更改时返回响应。您可以对自定义元数据或服务器定义的元数据使用此功能;因此如果您的实例或项目发生任何变化,或者有人更新了某个自定义元数据,您可以编程方式来响应这项更改。例如,您可以对 tags 键执行请求,使系统仅在 tags 元数据的内容发生更改时才返回响应。请求返回后,会提供该元数据键的新值。

如需执行 wait-for-change 请求,请查询元数据键并附加 ?wait_for_change=true 查询参数:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true" -H "Metadata-Flavor: Google"

指定的元数据键发生更改后,查询会返回新值。在此示例中,如果向 setInstanceTags 方法发出请求,则请求会返回新值:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true" -H "Metadata-Flavor: Google"

cheese
lettuce

您还能以递归方式对目录内容执行 wait-for-change 请求:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&wait_for_change=true" -H "Metadata-Flavor: Google"

如果发生任何更改,元数据服务器就会返回新内容:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&wait_for_change=true" -H "Metadata-Flavor: Google"

{"cheese":"lettuce","cookies":"cream"}

您还可以使用 wait-for-change 功能来匹配请求和设置超时值

使用 ETag

当您提交简单的 wait-for-change 查询后,如果元数据内容发生了任何更改,元数据服务器就会返回响应。但是,由于元数据更新作业与发出的 wait-for-change 请求之间存在固有的竞争条件,因此通过一种可靠的方式来获悉您正在获取最新的元数据值将会很有帮助。

为实现此目的,您可以使用 last_etag 查询参数来将您提供的 ETag 值与保存在元数据服务器中的 ETag 值进行比较。如果这些 ETag 值一致,则系统将接受 wait-for-change 请求。如果这些 ETag 值不一致,则表明自您上次检索 ETag 值以后,元数据内容已更改,因此元数据服务器会立即返回此最新值。

要获取元数据键的最新 ETag 值,请向该键发出请求并输出标头。在 curl 中,您可以使用 -v 标志来执行此操作:

user@myinst:~$ curl -v "http://metadata.google.internal/computeMetadata/v1/instance/tags" -H "Metadata-Flavor: Google"
* About to connect() to metadata port 80 (#0)
*   Trying 169.254.169.254... connected
* Connected to metadata (169.254.169.254) port 80 (#0)
> GET /computeMetadata/v1/instance/tags HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: metadata
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/text
< ETag: 411261ca6c9e654e
< Date: Wed, 13 Feb 2013 22:43:45 GMT
< Server: Metadata Server for VM
< Content-Length: 26
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
<
cheese
lettuce

然后,您可以在 wait-for-change 请求中使用该 ETag 值:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true&last_etag=411261ca6c9e654e" -H "Metadata-Flavor: Google"

元数据服务器会对您指定的 ETag 值进行匹配,如果该值发生更改,则请求将返回元数据键的新内容。

以下 Python 示例演示了如何以编程方式监控元数据服务器的更改:

last_etag = '0'

while True:
    r = requests.get(
        url,
        params={'last_etag': last_etag, 'wait_for_change': True},
        headers=METADATA_HEADERS)

    # During maintenance the service can return a 503, so these should
    # be retried.
    if r.status_code == 503:
        time.sleep(1)
        continue
    r.raise_for_status()

    last_etag = r.headers['etag']

设置超时值

如果您希望 wait-for-change 请求在特定秒数后超时,则可以设置 timeout_sec=<timeout-in-seconds> 查询参数。timeout_sec 参数会将请求的等待时间限制为您所指定的秒数,因此达到这一限制时,请求就会返回元数据键的当前内容。以下示例 wait-for-change 请求被设置为在 360 秒后超时。

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/tags?wait_for_change=true&timeout_sec=360" -H "Metadata-Flavor: Google"

当您设置 timeout_sec 参数时,无论元数据值是否已发生实际更改,请求始终会在指定的秒数后返回响应。超时值必须设置为整数值。

状态代码

当您执行 wait-for-change 请求时,元数据服务器会返回标准 HTTP 状态代码以指示成功与否。如果发生错误,则网络状况可能会导致元数据服务器使您的请求失败,并返回错误代码。在此类情况下,您应该将您的应用设计成容错型,并且可以识别和处理这些错误。

元数据服务器返回的可能状态如下:

状态 说明
HTTP 200 成功!值已更改,或者您已达到指定的 timeout_sec,且请求已成功返回响应。
Error 400 您的请求无效。请修正您的查询并重试请求。
Error 404 您指定的元数据值不再存在。如果您的元数据在您等待更改时遭到删除,则元数据服务器也会返回此错误。
Error 503 发生临时服务器错误或临时维护事件。请重试请求。

获取实时迁移通知

元数据服务器通过 scheduling/ 目录和 maintenance-event 特性提供有关实例的调度选项和设置的信息。您可以使用这些特性来了解虚拟机实例的调度选项,并使用此元数据,在维护事件即将发生时通过 maintenance-event 特性接收通知。默认情况下,所有虚拟机实例都设置为实时迁移,因此元数据服务器将在虚拟机实例实时迁移前收到维护事件通知。如果您选择在维护期间终止虚拟机实例,并且设置了 automaticRestart 特性,则 Compute Engine 将会自动终止您的虚拟机实例并视情况重启这些实例。如需详细了解维护事件以及这些事件发生时的实例行为,请参阅调度选项和设置

您可以定期查询 maintenance-event 特性,了解何时会发生维护事件。此特性的值会在维护事件开始前 60 秒发生更改,让您的应用代码能够在维护事件之前触发您要执行的任何任务,例如备份数据或更新日志。Compute Engine 还提供示例 Python 脚本来演示如何检查是否有维护事件通知。

只有在以下情况下,Compute Engine 才会发出 60 秒的警告:

  • 您已将实例的可用性选项设置为在维护事件期间实时迁移。

  • 自上次维护事件以来,您已查询 maintenance-event 特性至少一次。如果您从未查询过 maintenance-event 特性,或者自上次迁移后未查询过该特性,则 Compute Engine 会假定实例并不需要接收维护事件的提前警告。维护事件会跳过 60 秒的警告期而立即启动。如果您不想跳过 60 秒的警告期,请确保您的客户端代码会在两次迁移事件之间至少查询一次 maintenance-event 特性。

要查询 maintenance-event 特性,请运行以下命令:

user@myinst:~$ curl http://metadata.google.internal/computeMetadata/v1/instance/maintenance-event -H "Metadata-Flavor: Google"

NONE

maintenance-event 特性的初始值和默认值为 NONE

对于 GPU 实例,在发生维护事件时,属性会从 NONE 更改为 TERMINATE_ON_HOST_MAINTENANCE。此特性会在终止事件开始前 60 分钟更新。

对于调度选项为 migrate 的非 GPU 实例,maintenance-event 特性会发生如下变化:

  1. 在迁移事件开始时,值会从 NONE 更改为 MIGRATE_ON_HOST_MAINTENANCE
  2. 在整个事件持续期间以及您的虚拟机实时迁移期间,该值仍为 MIGRATE_ON_HOST_MAINTENANCE
  3. 在维护事件结束后,该值会恢复为 NONE

您可以将 maintenance-event 特性与等待更新功能搭配使用,以便在维护事件即将开始和结束时向您的脚本和应用发送通知。如此,您就能够自动执行可能需要在该事件前后运行的任意操作。以下 Python 示例演示了如何将这两种功能一起实现。


import time

import requests

METADATA_URL = 'http://metadata.google.internal/computeMetadata/v1/'
METADATA_HEADERS = {'Metadata-Flavor': 'Google'}

def wait_for_maintenance(callback):
    url = METADATA_URL + 'instance/maintenance-event'
    last_maintenance_event = None
    last_etag = '0'

    while True:
        r = requests.get(
            url,
            params={'last_etag': last_etag, 'wait_for_change': True},
            headers=METADATA_HEADERS)

        # During maintenance the service can return a 503, so these should
        # be retried.
        if r.status_code == 503:
            time.sleep(1)
            continue
        r.raise_for_status()

        last_etag = r.headers['etag']

        if r.text == 'NONE':
            maintenance_event = None
        else:
            maintenance_event = r.text

        if maintenance_event != last_maintenance_event:
            last_maintenance_event = maintenance_event
            callback(maintenance_event)

def maintenance_callback(event):
    if event:
        print('Undergoing host maintenance: {}'.format(event))
    else:
        print('Finished host maintenance')

def main():
    wait_for_maintenance(maintenance_callback)

if __name__ == '__main__':
    main()

检查服务器端点的版本

如需检查元数据服务器端点的版本,请查看您用来向服务器发出请求的 URI。

元数据端点版本 URI
v0.1 http://metadata.google.internal/0.1/meta-data/…
v1beta1 http://metadata.google.internal/computeMetadata/v1beta1/…
v1 http://metadata.google.internal/computeMetadata/v1/…

停用旧版端点

在准备关停 v0.1 和 v1beta1 元数据服务器端点时,您可以在项目级或实例级停用这些端点。

如需停用 v0.1 和 v1beta1 元数据服务器端点,请按照设置自定义元数据的说明来设置 disable-legacy-endpoints=TRUE

例如,如要使用 gcloud 命令行工具在项目级停用元数据服务器端点,请运行以下命令:

gcloud compute project-info add-metadata --metadata disable-legacy-endpoints=TRUE

转换到 v1 元数据服务器端点

如需了解如何从 v0.1 或 v1beta1 端点转换到 v1 端点,请参阅迁移至 v1 元数据服务器端点

后续步骤