运行启动脚本

要让实例在每次启动时执行自动化任务,您可以在虚拟机上创建并运行自己的启动脚本。启动脚本可以执行许多操作,例如安装软件、执行更新、开启服务以及脚本中定义的任何其他任务。您可以使用启动脚本以编程方式轻松地自定义虚拟机实例,包括在创建时自定义新实例。

例如,用于安装和启动 Apache 服务器的简单启动脚本可能如下所示:

#! /bin/bash
apt-get update
apt-get install -y apache2
cat <<EOF > /var/www/html/index.html
<html><body><h1>Hello World</h1>
<p>This page was created from a simple startup script!</p>
</body></html>
EOF

启动脚本是通过元数据服务器使用启动脚本元数据键指定的。您可以使用 gcloud 命令行工具、API 或 Google Cloud Platform Console 提供启动脚本。

准备工作

执行此任务所需的权限

要执行此任务,您必须具有以下权限

  • 创建新实例所需的所有权限
  • 针对实例执行 compute.instances.setMetadata 的权限

执行启动脚本

在网络可用后,实例始终以 root 身份执行启动脚本。

启动脚本可以是任何文件类型。如果存在启动脚本,则 Compute Engine 将执行以下操作:

  1. 将启动脚本复制到实例中的本地文件。
  2. 设置针对文件的权限,使其可以执行。
  3. 执行文件。

例如,您可以提供 Python 脚本而不是 bash 脚本。请注意,无论是什么类型的脚本,Compute Engine 都会逐字运行脚本。

要执行非 bash 脚本,请在文件顶部添加 shebang 行,告知操作系统要使用哪个解释器。例如,对于 Python 脚本,您可以添加如下的 shebang 行:

#! /usr/bin/python

使用本地启动脚本

本地启动脚本是位于您本地计算机上的脚本。要使用本地启动脚本,请传入本地启动脚本文件,或者将启动脚本的内容直接提供给元数据服务器。以下小节中的示例显示如何从本地文件添加或直接输入启动脚本元数据。

本地启动脚本受限于元数据值长度限制 (256 KB)。如果您的启动脚本超出此限制,您将无法在本地加载该脚本。在这种情况下,您需要将文件保存到 Google Cloud Storage,并在创建实例期间指定脚本的网址。要了解详情,请参阅使用存储在 Cloud Storage 上的启动脚本

提供启动脚本文件

您只能通过 gcloud 命令行工具传入本地启动脚本文件。

要传入本地启动脚本文件,请使用 gcloud 命令行工具并提供 --metadata-from-file 标志,后跟元数据键/值对 startup-script=PATH/TO/FILE,其中 PATH/TO/FILE 是启动脚本的相对路径,如下所示:

gcloud compute instances create example-instance \
    --metadata-from-file startup-script=examples/scripts/install.sh

直接提供启动脚本内容

您还可以使用 Console、gcloud 命令行工具或 API 直接输入或粘贴启动脚本内容。

Console

在 GCP Console 中,可以直接在启动脚本部分指定启动脚本:

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

    转到“虚拟机实例”页面

  2. 点击创建实例
  3. 创建新实例页面上,为实例填写所需的属性。 对于高级配置选项,展开管理、安全、磁盘、网络、单独租用部分。
  4. 自动化部分的启动脚本下,提供启动脚本的内容。

    在 GCP Console 中设置启动脚本的屏幕截图

  5. 点击创建以创建实例。

gcloud

gcloud 命令行工具中,指定 --metadata 标志并使用 startup-script=[CONTENTS] 键/值对来提供启动脚本的内容,其中 [CONTENTS] 是启动脚本的内容。

例如,以下命令创建的实例可以在启动时执行一些系统更新、安装 Apache 以及发布单个网页。您可以运行此命令,然后访问实例的外部 IP 地址,以查看 index.html 页面的内容。

在 Linux 桌面系统上,运行类似如下的命令:

gcloud compute instances create example-instance --tags http-server \
--metadata startup-script='#! /bin/bash
# Installs apache and a custom homepage
sudo su -
apt-get update
apt-get install -y apache2
cat <<EOF > /var/www/html/index.html
<html><body><h1>Hello World</h1>
<p>This page was created from a simple start up script!</p>
</body></html>
EOF'

如果您使用 Windows 桌面系统,则可以在 cmd 终端上运行此命令:

gcloud compute instances create example-instance --tags http-server --metadata startup-script="
apt-get update;
apt-get install -y apache2;
echo \"This page was created from a simple start up script!\" ^> /var/www/html/index.html"

同样,如果您使用 Powershell,则可以使用 --% 标记来运行此命令,将命令原样传入 gcloud 工具:

gcloud --% compute instances create example-instance --tags http-server --metadata startup-script="
apt-get update;
apt-get install -y apache2;
echo \"This page was created from a simple start up script!\" ^> /var/www/html/index.html"

API

在 API 中,使用 startup-script 作为元数据键,将启动脚本作为请求中元数据属性的一部分提供:

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

{
  ...
  "metadata": {
    "items": [
      {
       "key": "startup-script",
       "value": "#! /bin/bash\n\n# Installs apache and a custom homepage\napt-get update\napt-get install -y apache2\ncat <<EOF > /var/www/html/index.html\n<html><body><h1>Hello World</h1>\n<p>This page was created from a simple start up script!</p>\n</body></html>"
      }
    ]
  }
  ...
}

为 Windows 实例提供启动脚本

可以使用唯一的 Windows 专用元数据键,在 Windows 实例上运行启动脚本。请从下列任何专用键中选择。每个键都应该与您要运行的脚本类型匹配。您还可以通过向您的实例传入不同的键来指定多个脚本。对于每个实例,每个键只能指定一次。

可以按照上面的相同说明,将以下键与本地启动脚本一起使用。

脚本类型 在 sysprep 期间、启动之前运行 在 sysprep 完成后、后续每次启动时运行
url 启动脚本 sysprep-specialize-script-url windows-startup-script-url
cmd 启动脚本 sysprep-specialize-script-cmd windows-startup-script-cmd
bat 启动脚本 sysprep-specialize-script-bat windows-startup-script-bat
ps11 启动脚本 sysprep-specialize-script-ps1 windows-startup-script-ps1

提供存储在 Google Cloud Storage 上的启动脚本

创建实例时,您可以在 Google Cloud Storage 上存储脚本并提供该脚本的网址。这样,您就可以从任何位置访问启动脚本,同时绕过元数据服务器限制。

设置脚本的访问权限

为了使用 Google Cloud Storage 中的启动脚本,您必须有权访问此脚本。检查存储分区和文件的访问控制设置,以确保您具有权限。

默认情况下,如果您是项目所有者或编辑者,则应该能够访问来自同一个项目的文件,除非有访问控制明确禁止您访问。

提供启动脚本

  1. 创建存储分区。 您可以创建新存储分区或使用现有存储分区。如需了解如何创建新存储分区,请参阅在 Google Cloud Platform Console 中创建存储分区gsutil 中创建存储分区
  2. 将文件上传至存储分区。 按照说明,使用 gsutilGCP Console 上传对象。
  3. 创建新实例时,提供启动脚本文件的网址

    Console

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

      转到“虚拟机实例”页面

    2. 点击创建实例
    3. 创建新实例页面上,为实例填写所需的属性。 对于高级配置选项,展开管理、安全、磁盘、网络、单独租用部分。
    4. 元数据部分,提供 startup-script-url 作为元数据键。
    5. 框中,提供启动脚本文件的网址,格式为 gs://[BUCKET]/[FILE]https://storage.googleapis.com/[BUCKET]/[FILE]
    6. 身份和 API 访问权限部分,选择有权读取 Cloud Storage 中的启动脚本文件的服务帐号。例如,服务帐号应该具有存储对象查看者角色的权限。
    7. 点击创建以创建实例。

    gcloud

    gcloud 命令行工具中,使用 --scopes--metadata 标志并指定 startup-script-url 键来创建实例。--scopes 标志向虚拟机提供对 Google Cloud Storage 的访问权限,供其下载启动脚本。您可以提供脚本的 Google Cloud Storage 网址,格式为 gs://bucket/filehttps://storage.googleapis.com/bucket/file

    gcloud compute instances create example-instance --scopes storage-ro \
        --metadata startup-script-url=gs://bucket/startupscript.sh
    

    API

    在 API 中,使用 startup-script-url 作为元数据键,将启动脚本作为请求中元数据属性的一部分提供。此外,还需提供 scopes 列表(包括 Google Cloud Storage 范围),以便虚拟机可以访问启动脚本文件:

    POST https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances
    
    {
      ...
      "serviceAccounts": [
        {
          "email": "default",
          "scopes": [
            "https://www.googleapis.com/auth/devstorage.read_only"
          ]
        }
      ],
      "metadata": {
        "items": [
          {
           "key": "startup-script-url",
           "value": "gs://bucket/myfile"
          }
        ]
      },
      "tags": {
        "items": []
      },
      "machineType": "zones/us-central1-a/machineTypes/n1-standard-1",
      "name": "example-instance"
    }
    

    Windows

    gcloud 命令行工具中,使用 --scopes--metadata 标志并指定 windows-startup-script-url 键来创建实例。--scopes 标志向虚拟机提供对 Google Cloud Storage 的访问权限,供其下载启动脚本。您可以提供脚本的 Google Cloud Storage 网址,格式为 gs://bucket/filehttps://storage.googleapis.com/bucket/file

    gcloud compute instances create example-windows-instance --scopes storage-ro \
       --metadata windows-startup-script-url=gs://bucket/startupscript.ps1
    

将启动脚本应用于正在运行的实例

如果您的实例正在运行,可向其添加启动脚本,当实例下次重启时,启动脚本将会运行。实例以后每次重新启动时,启动脚本都会运行。

按照以下说明在运行的实例上设置启动脚本。

Console

  1. 转到“虚拟机实例”页面
  2. 点击您要为其添加启动脚本的实例。此时将显示实例详细信息页面。
  3. 在实例详细信息页面中,完成以下步骤:

    1. 点击页面顶部的修改按钮。
    2. 自定义元数据下,点击添加一项
    3. 使用以下键之一添加您的启动脚本:

      • startup-script:直接使用此键来提供启动脚本内容。
      • startup-script-url:使用此键提供启动脚本文件的 Google Cloud Storage 网址。

gcloud

gcloud 命令行工具中,使用 instances add-metadata 向实例添加元数据。您可使用以下任何可用的启动脚本键:

  • --metadata startup-script=CONTENTS:直接使用此键来提供启动脚本内容。
  • --metadata startup-script-url=URL:使用此键提供启动脚本文件的 Google Cloud Storage 网址。
  • --metadata-from-file startup-script=FILE:提供本地存储的启动脚本文件。

例如:

gcloud compute instances add-metadata example-instance \
    --metadata-from-file startup-script=path/to/file
gcloud compute instances add-metadata example-instance \
    --metadata startup-script-url=gs://bucket/file

API

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

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

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

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

 ...
 "name": "example-instance",
 "metadata": {
  "kind": "compute#metadata",
  "fingerprint": "zhma6O1w2l8="
 },
 "...
}

接下来,使用以下元数据键之一和指纹值向 instances().setMetadata 方法发出请求:

  • startup-script:直接使用此键来提供启动脚本内容。
  • startup-script-url:使用此键提供启动脚本文件的 Google Cloud Storage 网址。

例如:

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

{
 "fingerprint": "zhma6O1w2l8=",
 "items": [
  {
   "key": "startup-script-url",
   "value": "gs://bucket/file"
  }
 ]
}

重新运行启动脚本

您可以通过连接到实例并运行以下命令之一,在您的虚拟机实例上强制启动脚本重新运行:

在 Debian、CentOS、RHEL、SLES、Container-Optimized OS 和 Ubuntu 映像上,使用以下代码:

$ sudo google_metadata_script_runner --script-type startup --debug

startup-script: INFO Starting startup scripts.
startup-script: INFO startup-script: Return code 0.
startup-script: INFO Finished running startup scripts.

在 Container-Optimized OS 上,您还可以使用 journalctl 查看启动脚本输出。

$ sudo journalctl -u google-startup-scripts.service

启动脚本输出会写入以下日志文件:

  • CentOS 和 RHEL:/var/log/messages
  • Debian:/var/log/daemon.log
  • Ubuntu 14.04、16.04 和 16.10:/var/log/syslog
  • SLES 11 和 12:/var/log/messages

在启动脚本中设置自定义值

跨实例运行启动脚本时,可能会出现需要在启动脚本中使用自定义值的情况。例如,您可能希望在不同的实例上运行启动脚本,并让每个实例输出自定义消息。

您可以在创建实例期间将这些自定义值指定为自定义元数据键/值对,并在启动脚本中引用这些键/值对。如需详细了解如何创建自定义元数据键,请参阅设置自定义元数据

设置自定义元数据键/值对后,您可以修改启动脚本以查询新元数据。例如,以上脚本可改为:

#! /bin/bash
VALUE_OF_FOO=$(curl http://metadata.google.internal/computeMetadata/v1/instance/attributes/foo -H "Metadata-Flavor: Google")
apt-get update
apt-get install -y apache2
cat <<EOF > /var/www/html/index.html
<html><body><h1>Hello World</h1>
<p>The value of foo: $VALUE_OF_FOO</p>
</body></html>
EOF

问题排查

与元数据服务器的网络连接

对于 Linux 虚拟机,Compute Engine 在尝试从元数据服务器获取信息(例如自定义启动或关闭脚本)之前,将等待连接到元数据服务器。如果元数据服务器无响应,或您尚未配置网络,则虚拟机将无法完成启动。

对于映像早于 v20160606 的 Linux 虚拟机,串行端口输出将显示 "Waiting for metadata server, attempt N",其中 N 是已尝试的次数。

此问题可能持续长达七分钟,因为发生的短暂网络问题应该会自行解决。如果问题在七分钟后无法自行解决,请重新创建虚拟机实例。

后续步骤

此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
Compute Engine 文档