运行启动脚本

Compute Engine 允许您在虚拟机实例上创建并运行自己的启动脚本,以便在实例每次启动时执行自动化任务。启动脚本可以执行操作,例如安装软件、执行更新、开启服务以及脚本中定义的任何其他任务。

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

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

如需指定启动脚本,您可以将启动脚本元数据键与元数据服务器搭配使用。您可以使用 Google Cloud Console、gcloud 命令行工具或 Compute Engine API 来提供启动脚本。

准备工作

执行此任务所需的权限

您必须拥有以下权限才能执行此任务:

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

运行启动脚本

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

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

  1. 将启动脚本复制到实例中的本地文件。
  2. 设置针对该文件的运行权限。
  3. 运行该文件。

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

如需执行非 bash 脚本,请在文件顶部添加一个 shebang(以 #! 开头的行)。这会指示操作系统使用哪个解释器。例如,如果您使用的是 Python 脚本,则可以添加以下 shebang 行:

#! /usr/bin/python

使用本地启动脚本

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

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

提供启动脚本文件

您只能通过使用 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

直接提供启动脚本内容

或者,您可以使用 Google Cloud Console、gcloud 命令行工具或 Compute Engine API 直接输入或粘贴启动脚本的内容。

控制台

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

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

    转到“虚拟机实例”页面

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

    在 Cloud 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 update
  apt -y install apache2
  cat <<EOF > /var/www/html/index.html
  <html><body><h1>Hello World</h1>
  <p>This page was created from a start up script.</p>
  </body></html>
  EOF'

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

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

同样,如果您使用的是 PowerShell,则可以通过使用“停止解析”特殊字符 (--%) 将精确命令传递给 gcloud 工具来运行上面所说的命令:

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

API

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

POST https://compute.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 update\napt -y install apache2\ncat <<EOF > /var/www/html/index.html\n<html><body><h1>Hello World</h1>\n<p>This page was created from a start up script.</p>\n</body></html>"
      }
    ]
  }
  ...
}

为 Windows 实例提供启动脚本

可以使用唯一的 Windows 专用元数据键,在 Windows 实例上运行启动脚本。从下表中列出的任何专用元数据键中进行选择。每个元数据键都必须与您要运行的脚本类型相匹配。您还可以通过将不同的元数据键传递给实例来指定多个脚本。您可以为每个虚拟机实例仅指定每个元数据键一次。

如果需要在虚拟机实例启动后在该虚拟机实例上手动运行启动脚本,则管理员可以使用以下命令执行此操作:

C:\Program Files\Google\Compute Engine\metadata_scripts\run_startup_scripts.cmd

下表显示了受支持的启动脚本的类型、运行时间以及用于指定脚本的元数据键。如需了解如何使用这些元数据键,请参阅使用本地启动脚本。 请注意,只有在您使用 GCESysprep 命令准备映像时,这些脚本才会运行。

脚本类型 运行时间:
  • GCESysprep2 运行期间
  • 启动前
运行时间:
  • GCESysprep2 完成后
  • 后续每次启动时
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

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

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

设置脚本的访问权限

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

默认情况下,如果您是 Project Owner 或 Editor,则可以访问来自同一个项目的文件,除非有访问权限控制明确禁止您访问。

提供启动脚本

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

    控制台

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

      转到“虚拟机实例”页面

    2. 点击创建实例

    3. 创建新实例页面上,填写实例的属性。

    4. 身份和 API 访问权限部分,选择有权读取 Cloud Storage 中的启动脚本文件的服务帐号。例如,服务帐号必须具有 Storage Object Viewer 角色的权限。

    5. 展开管理、安全、磁盘、网络、单独租用部分。

    6. 元数据部分中,提供 startup-script-url 作为元数据键。

    7. 框中,提供启动脚本文件的网址,格式为 gs://BUCKET/FILEhttps://storage.googleapis.com/BUCKET/FILE

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

    gcloud

    gcloud 命令行工具中,使用 --scopes--metadata 标志创建实例,并指定 startup-script-url 键。--scopes 标志允许虚拟机访问 Cloud Storage 以下载启动脚本。您可以采用 gs://BUCKET/FILEhttps://storage.googleapis.com/BUCKET/FILE 格式提供脚本的 Cloud Storage 网址。

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

    API

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

    POST https://compute.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/FILE"
          }
        ]
      },
      "tags": {
        "items": []
      },
      "machineType": "zones/us-central1-a/machineTypes/e2-medium",
      "name": "example-instance"
    }
    

    Windows

    gcloud 命令行工具中,使用 --scopes--metadata 标志创建实例,并指定 windows-startup-script-url 键。--scopes 标志允许虚拟机访问 Cloud Storage 以下载启动脚本。您可以采用 gs://BUCKET/FILEhttps://storage.googleapis.com/BUCKET/FILE 格式提供脚本的 Cloud Storage 网址。

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

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

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

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

控制台

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

    转到“虚拟机实例”页面

  2. 点击您要为其添加启动脚本的实例。

  3. 在实例详细信息页面上,完成以下步骤:

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

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

gcloud

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

  • --metadata startup-script=CONTENTS:使用此键直接提供启动脚本内容。
  • --metadata startup-script-url=URL:使用此键提供启动脚本文件的 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://compute.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:使用此键提供启动脚本文件的 Cloud Storage 网址。

例如:

POST https://compute.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 映像上,使用以下代码

sudo google_metadata_script_runner startup

GCEMetadataScripts: Starting startup scripts (version YYMMDD.NN).
GCEMetadataScripts: Found startup-script in metadata.
GCEMetadataScripts: startup-script exit status 0
GCEMetadataScripts: Finished running startup scripts.

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

sudo google_metadata_script_runner --script-type startup --debug

查看启动脚本日志

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

  • CentOS 和 RHEL:/var/log/messages
  • Debian:/var/log/daemon.log
  • Ubuntu:/var/log/syslog
  • SLES:/var/log/messages

您还可以使用 journalctl 命令查看启动脚本输出。

sudo journalctl -u google-startup-scripts.service

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

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

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

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

#! /bin/bash
VALUE_OF_FOO=$(curl http://metadata.google.internal/computeMetadata/v1/instance/attributes/foo -H "Metadata-Flavor: Google")
apt update
apt -y install 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 是已尝试的次数。

    由于一个暂时性的网络问题,此问题可能持续长达七分钟,但会自行解决。如果问题在七分钟后无法自行解决,请重新创建虚拟机实例。

后续步骤