使用 Google Distributed Cloud 1.13.0 及更高版本时,您可以指定启动例程,以自定义虚拟机在启动时的初始化。您可以配置虚拟机以创建 SSH 密钥、添加用户和密码、安装软件包、写入文件、配置网络设置等。
这些启动任务使用 cloud-init API 或启动脚本 API(但不能同时使用两者)进行配置。这些启动指令在 VirtualMachine
YAML 清单文件中指定,并在每次虚拟机启动时自动执行。
前提条件
如需使用启动指令配置虚拟机,您必须满足以下前提条件:
使用经过验证的 Linux 客户机操作系统,并在虚拟机清单中将
osType
设置为Linux
。此功能不支持 Windows 客户机操作系统,因为它们不支持 cloud-init。确保客户机操作系统已安装 cloud-init。最新的 Linux 操作系统包括 cloud-init。
以下部分介绍如何使用 cloud-init API 或启动脚本在虚拟机清单中指定启动例程。
使用 cloud-init API 初始化虚拟机
Cloud-init 通常用于云实例初始化以及在启动期间自定义虚拟机。虚拟机初始化通常涉及软件包安装、代码库设置、SSH 密钥创建、将数据写入文件以及设置虚拟机其他方面等任务。通过 spec.cloudInit
字段将 cloud-init 配置 YAML 整合到 VirtualMachine
自定义资源中。当虚拟机实例启动时,cloud-init 会读取提供的数据并相应地初始化虚拟机。
请注意我们的 cloud-init 实现的以下详细信息:
您可以在创建或更新虚拟机时,在
VirtualMachine
YAML 清单中指定 cloud-init 数据。如需了解如何通过应用清单来创建虚拟机,请参阅教程:在 GDC 上的虚拟机运行时中创建和管理 Linux 虚拟机。我们在虚拟机规范中使用
NoCloud
数据源spec.cloudInit.noCloud
。您可以在
VirtualMachine
清单的单独部分中指定用户数据和网络数据。部分命名和结构取决于您决定使用的数据格式。您可以使用以下数据格式指定 cloud-init 配置信息:
- 明文
- Base64 编码的字符串
- Kubernetes Secret
为了帮助您开始使用,我们提供了常见虚拟机初始化任务的一些配置示例。
Cloud-init 用户数据
GDC 上的虚拟机运行时支持采用 cloud-config 语法的 cloud-init 用户数据,因此应以 #cloud-config
作为用户数据的开头。您可以将用户数据的格式设置为明文、base64 编码的字符串或 Kubernetes Secret。
如需详细了解用户数据语法和模块参考,请参阅 cloud-init 文档。
将 Cloud-init 用户数据指定为明文
以下示例清单显示如何将用户数据指定为明文。在此示例中,在虚拟机启动时,cloud-init 会执行命令:
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
userData: |
#cloud-config
runcmd:
- echo hello
将 Cloud-init 用户数据指定为 base64 编码的字符串
下面的示例展示了如何采用 base64 编码格式指定用户数据。在此示例中,用户数据由与明文示例相同的 echo hello
命令组成:
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
userDataBase64: I2Nsb3VkLWNvbmZpZwpydW5jbWQ6CiAgLSBlY2hvIGhlbGxvCg==
将 Cloud-init 用户数据指定为 Kubernetes Secret
以下示例展示了 VirtualMachine
和 Secret
的 YAML 清单。VirtualMachine
配置中的 spec.cloudInit.noCloud.secretRef
部分表示 cloud-init 用户数据位于名为 my-sec
的 Kubernetes Secret 中。相应的 Secret
配置以键值对的形式指定用户数据。在这种情况下,base64 编码的值是采用 cloud-config 语法的 cloud-init 用户数据。
在引用的 Secret 中,使用数据键 userData
(显示)或 userdata
来指定 cloud-init 用户数据。
在此示例中,用户数据由与明文示例相同的 echo hello
命令组成:
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
secretRef:
name: my-sec
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: my-sec
data:
userData: I2Nsb3VkLWNvbmZpZwpydW5jbWQ6CiAgLSBlY2hvIGhlbGxvCg==
如果找不到引用的 Secret 或者 Secret 中不存在数据键 userData
或 userdata
,请注意以下虚拟机启动行为:
为了创建虚拟机,系统会将虚拟机置于
ErrorConfiguration
状态,并提供详细原因和消息。在其他情况下,虚拟机会继续使用旧的 cloud-init 用户数据,直到正确配置虚拟机。因此,客户机代理启用或停用更新在正确配置虚拟机后才会生效。
如需检索虚拟机信息(包括所使用的 cloud-init 用户数据),请使用以下命令:
kubectl get vm VM_NAME -o yaml --kubeconfig KUBECONFIG_PATH
请替换以下内容:
VM_NAME
:您的虚拟机的名称。KUBECONFIG_PATH
:包含虚拟机的集群的 kubeconfig 文件路径。
如需检索相关的 Kubernetes 警告事件,请使用 kubectl get event
或 kubectl describe gvm
。
Cloud-init 网络数据
与用户数据类似,您可以将网络数据的格式设置为明文、base64 编码的字符串或 Kubernetes Secret。与用户数据不同,网络数据不使用 cloud-config 语法。
使用明文或 base64 编码的字符串时,允许的大小上限为 2048 字节。如果用户数据大小接近或大于 2048 字节,请将其指定为 Kubernetes Secret。
如需详细了解网络数据语法和相关详情,请参阅 cloud-init 文档中的 Networking Config 版本 2。
将 Cloud-init 网络数据指定为明文
以下示例清单显示如何将网络数据指定为明文。在此示例中,cloud-init 为名称以“e”(e*
) 开头的所有以太网设备启用 DHCP:
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
userData: |
#cloud-config
runcmd:
- echo hello
networkData: |
version: 2
ethernets:
alleths:
match:
name: e*
dhcp4: true
将 Cloud-init 网络数据指定为 base64 编码的字符串
下面的示例展示了如何采用 base64 编码格式指定网络数据。在此示例中,网络数据由明文示例中指定的相同 DHCP 配置组成:
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
networkDataBase64: dmVyc2lvbjogMgpldGhlcm5ldHM6CiAgYWxsZXRoczoKICAgIG1hdGNoOgogICAgICBuYW1lOiBlKgogICAgZGhjcDQ6IHRydWUK
将 Cloud-init 网络数据指定为 Kubernetes Secret
以下示例展示了 VirtualMachine
和 Secret
的 YAML 清单。VirtualMachine
配置中的 spec.cloudInit.noCloud.networkDataSecretRef
部分表示 cloud-init 网络数据位于名为 my-sec
的 Kubernetes Secret 中。相应的 Secret
配置以键值对的形式指定网络数据。在这种情况下,base64 编码的值是 cloud-init 网络数据。
在引用的 Secret 中,使用数据键 networkData
(显示)或 networkdata
来指定 cloud-init 网络数据。
在此示例中,网络数据由明文示例中指定的相同 DHCP 配置组成:
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
networkDataSecretRef:
name: my-sec
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: my-sec
data:
networkData: dmVyc2lvbjogMgpldGhlcm5ldHM6CiAgYWxsZXRoczoKICAgIG1hdGNoOgogICAgICBuYW1lOiBlKgogICAgZGhjcDQ6IHRydWUK
Cloud-init 示例
以下部分包含使用 cloud-init 进行虚拟机初始化的一些常见用例的明文示例:
配置已获授权的 SSH 密钥
以下用户数据示例将已获授权的 SSH 密钥 ssh-rsa AAAAB3NzaK8L93bWxnyp
分配给默认用户。
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
userData: |
#cloud-config
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaK8L93bWxnyp
添加新用户
以下用户数据示例创建一个用户 test
,并为 test
授予完整的 sudo 访问权限。此示例为用户分配未到期的密码 pwd
。
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
userData: |
#cloud-config
users:
- default
- name: test
sudo: ALL=(ALL) NOPASSWD:ALL
chpasswd:
list: |
test:pwd
expire: False
在第一次启动时运行命令
以下用户数据示例运行 echo
命令和 ls
命令。您可以在虚拟机启动时使用这些命令来安装软件包等。
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
userData: |
#cloud-config
runcmd:
- [ echo, hello ]
- [ ls, -l, / ]
写入文件
以下用户数据示例将 bash 脚本写入虚拟机 /var/lib/google
目录中的 test
文件。cloud-init 指令设置文件所有者的读取、写入和执行文件权限 (0744
)。
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
cloudInit:
noCloud:
userData: |
#cloud-config
write_files:
- path: /var/lib/google/test
permissions: 0744
content: |
#!/bin/bash
echo hello
排查 cloud-init 问题
如果您的虚拟机初始化出现问题并且您使用的是 cloud-init,请在虚拟机中检查以下 cloud-init 日志:
/var/log/cloud-init.log
:默认情况下,cloud-init 会将级别为DEBUG
或更高级别的所有事件写入此日志。/var/log/cloud-init-output.log
:默认情况下,cloud-init 会将所有 cloud-init 阶段中的 stdout 和 stderr 定向到此日志。
使用启动脚本初始化虚拟机
启动脚本用于在虚拟机 (VM) 实例的启动过程中执行任务。您可以在 VirtualMachine
规范的 spec.startupScripts
部分中指定一个或多个脚本。启动脚本可用于初始化您的虚拟机。虚拟机初始化通常涉及软件包安装、代码库设置、SSH 密钥创建、将数据写入文件以及设置虚拟机其他方面等任务。
请注意启动脚本的以下详细信息:
您可以在创建或更新虚拟机时,在
VirtualMachine
YAML 清单中指定启动脚本。如需了解如何通过应用清单来创建虚拟机,请参阅教程:在 GDC 上的虚拟机运行时中创建和管理 Linux 虚拟机。每次虚拟机启动时,指定的脚本都会运行。
在脚本顶部添加
#!/bin/...
,以指示脚本解释器。例如,添加#!/bin/bash
以使用 Bash shell 执行脚本。您不能在同一个
VirtualMachine
清单中同时指定 cloud-init API 指令 (spec.cloudInit
) 和启动脚本 (spec.startupScripts
)。
脚本格式
您可以使用以下数据格式指定启动脚本:
- 明文
- Base64 编码的字符串
- Kubernetes Secret
请注意使用不同脚本格式的以下规则:
使用明文或 base64 编码的字符串时,脚本内容的大小上限为 2048 字节。如果脚本内容大小接近或大于 2048 字节,请将脚本指定为 Kubernetes Secret。
使用 Kubernetes Secret 时,请使用引用的 Secret 中的数据键
script
来指定脚本内容。如果未找到引用的 Secret 或引用的 Secret 中不存在数据键
script
,则虚拟机会继续运行该脚本。但是,虚拟机不会写入或更新脚本内容。在这种情况下,您可以使用kubectl get event
或kubectl describe gvm
来查找 Kubernetes 警告事件。
以下示例 VirtualMachine
YAML 清单包含三个脚本,每种受支持的格式各一个。在此示例中,每个脚本都会运行 myscript1
(明文示例)中显示的 echo
hello
命令。
apiVersion: vm.cluster.gke.io/v1
kind: VirtualMachine
metadata:
name: "my-vm"
spec:
...
startupScripts:
- name: myscript1
script: |
#!/bin/bash
echo hello
- name: myscript2
scriptBase64: IyEvYmluL2Jhc2gKICAgICAgZWNobyBoZWxsbwo=
- name: myscript3
scriptSecretRef:
name: my-sec
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: my-sec
data:
script: IyEvYmluL2Jhc2gKICAgICAgZWNobyBoZWxsbwo=
脚本问题排查
如需检查脚本结果或日志,请运行以下命令:
journalctl -u cloud-final
启动脚本日志条目以以下文本开头:
started to run the command /var/lib/google/startup-scripts/SCRIPT_NAME ...
日志条目包含 SCRIPT_NAME
(启动脚本的名称)。