Ale*_*lex 1 vsphere terraform terraform-provider-vsphere
我编写了一个 Terraform 脚本,该脚本应该从一个模板创建多个服务器实例。我现在创建了两个不同的变量文件。
但是当我运行脚本时,会使用第一个变量文件创建一个新实例,但使用第二个变量文件时,第一个实例始终会被覆盖/更改。我不知道为什么 Terraform 引用之前新创建的实例。我怎样才能防止这种情况发生?
服务器1.tfvars:
vsphere_user = "administrator@vsphere.local"
vsphere_password = "#Password"
vsphere_server = "vsphere.server"
vsphere_datacenter = "Datacenter"
vsphere_datastore = "Storage_1"
vsphere_compute_cluster = "Cluster"
vsphere_network = "Network_1"
vsphere_virtual_machine_template = "Template_Microsoft_Windows_Server_2019_x64_english"
system_name = "server-1"
system_cores = 2
system_cores_per_socket = 2
system_memory = 2048
system_local_admin_password = "#Password"
system_ipv4_address = "172.22.15.11"
system_ipv4_netmask = 24
system_dns_server_list = ["172.22.15.101"]
system_ipv4_gateway = "172.22.15.1"
system_disk1_size = 75
system_domain_admin_user = "Administrator"
system_domain_admin_password = "#Password"
Run Code Online (Sandbox Code Playgroud)
服务器2.tfvars:
vsphere_user = "administrator@vsphere.local"
vsphere_password = "#Password"
vsphere_server = "vsphere.server"
vsphere_datacenter = "Datacenter"
vsphere_datastore = "Storage_1"
vsphere_compute_cluster = "Cluster"
vsphere_network = "Network_1"
vsphere_virtual_machine_template = "Template_Microsoft_Windows_Server_2019_x64_english"
system_name = "server-2"
system_cores = 2
system_cores_per_socket = 2
system_memory = 2048
system_local_admin_password = "#Password"
system_ipv4_address = "172.22.15.12"
system_ipv4_netmask = 24
system_dns_server_list = ["172.22.15.101"]
system_ipv4_gateway = "172.22.15.1"
system_disk1_size = 75
system_domain_admin_user = "Administrator"
system_domain_admin_password = "#Password"
Run Code Online (Sandbox Code Playgroud)
提供商.tf:
provider "vsphere" {
user = var.vsphere_user
password = var.vsphere_password
vsphere_server = var.vsphere_server
allow_unverified_ssl = true
}
Run Code Online (Sandbox Code Playgroud)
数据.tf:
# Data Sources
# Datacenter
data "vsphere_datacenter" "dc" {
name = var.vsphere_datacenter
}
# Datastore
data "vsphere_datastore" "datastore" {
name = var.vsphere_datastore
datacenter_id = data.vsphere_datacenter.dc.id
}
# Cluster
data "vsphere_compute_cluster" "cluster" {
name = var.vsphere_compute_cluster
datacenter_id = data.vsphere_datacenter.dc.id
}
# Network
data "vsphere_network" "network" {
name = var.vsphere_network
datacenter_id = data.vsphere_datacenter.dc.id
}
# Template
data "vsphere_virtual_machine" "template" {
name = var.vsphere_virtual_machine_template
datacenter_id = data.vsphere_datacenter.dc.id
}
Run Code Online (Sandbox Code Playgroud)
资源.tf:
# Virtual Machine Resource
resource "vsphere_virtual_machine" "server-instance" {
# System
firmware = "efi"
guest_id = data.vsphere_virtual_machine.template.guest_id
scsi_type = data.vsphere_virtual_machine.template.scsi_type
# VM-Name
name = var.system_name
resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
datastore_id = data.vsphere_datastore.datastore.id
# CPU
num_cpus = var.system_cores
num_cores_per_socket = var.system_cores_per_socket
cpu_hot_add_enabled = true
cpu_hot_remove_enabled = true
# Memory
memory = var.system_memory
memory_hot_add_enabled = true
# Network
network_interface {
network_id = data.vsphere_network.network.id
adapter_type = "e1000e"
}
# Storage
# Drive 0 (C)
disk {
label = "disk0"
unit_number = 0
size = data.vsphere_virtual_machine.template.disks.0.size
eagerly_scrub = data.vsphere_virtual_machine.template.disks.0.eagerly_scrub
thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
}
# Drive 1 (D)
disk {
label = "disk1"
unit_number = 1
size = var.system_disk1_size
eagerly_scrub = data.vsphere_virtual_machine.template.disks.1.eagerly_scrub
thin_provisioned = data.vsphere_virtual_machine.template.disks.1.thin_provisioned
}
# Template clone and OS settings
clone {
template_uuid = data.vsphere_virtual_machine.template.id
customize {
windows_options {
computer_name = var.system_name
admin_password = random_password.password.result
join_domain = var.system_domain
domain_admin_user = var.system_domain_admin_user
domain_admin_password = var.system_domain_admin_password
auto_logon = true
}
network_interface {
ipv4_address = var.system_ipv4_address
ipv4_netmask = var.system_ipv4_netmask
dns_server_list = var.system_dns_server_list
}
ipv4_gateway = var.system_ipv4_gateway
}
}
}
Run Code Online (Sandbox Code Playgroud)
密码.tf:
# Import the Random Password Provider
terraform {
required_providers {
random = {
source = "hashicorp/random"
}
}
}
resource "random_password" "password" {
length = 25
upper = true
lower = true
number = true
special = true
min_upper = 2
min_lower = 2
min_numeric = 2
min_special = 1
override_special = "!@#$%&*()-_=+[]{}<>:?"
}
Run Code Online (Sandbox Code Playgroud)
Terraform 的模型是,配置中的每个资源实例都绑定到零个或一个远程对象 - 如果您尚未创建远程对象,则绑定到零;如果第一次创建对象,则绑定到一个。
Terraform 模型的另一个重要特征是它是声明性的。您不应该理解terraform apply为“创建所有这些东西”,而应该理解为“采取任何需要的操作来使远程系统匹配此配置”。在第一次运行时,通常会导致许多创建操作,但在后续运行中,您通常会对已存在的对象进行更改,因为提供程序的目标是找到破坏性最小的方法来更改远程系统以匹配更新的配置。
考虑到这一点,当您使用不同的参数值重新运行 Terraform 时vsphere_virtual_machine.server-instance,Terraform(和vsphere提供者)会理解,因为您想要更改之前创建的现有对象,而不是创建新对象。
为了同时存在多个虚拟机,您必须有多个相应的资源实例,每个虚拟机都有一个实例。在Terraform的模型中,每个resource块可以代表一个或多个资源实例;获取两个资源实例的最直接方法是编写两个resource块,因此每个块声明一个实例:
resource "vsphere_virtual_machine" "server_1" {
# ...
}
resource "vsphere_virtual_machine" "server_2" {
# ...
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您的多个实例是以可以使用 Terraform 语言中的表达式表达的方式系统创建的,那么您还有其他一些选择。
如果您认为所有虚拟机在某种意义上都是彼此的“副本”,并且在功能上都是等效的,那么您可能会选择使用元count参数,这会导致一个resource块具有与其关联的多个资源实例——表达式给出的数字count-- 除了以特殊符号 表示的一些细微差别外,所有这些都具有基本相同的配置count.index,该特殊符号给出了当前实例的索引:
resource "vsphere_virtual_machine" "server" {
count = 2
# VM-Name
name = "${var.system_name}-${count.index}"
resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
datastore_id = data.vsphere_datastore.datastore.id
# System
firmware = "efi"
guest_id = data.vsphere_virtual_machine.template.guest_id
scsi_type = data.vsphere_virtual_machine.template.scsi_type
# CPU
num_cpus = var.system_cores
num_cores_per_socket = var.system_cores_per_socket
cpu_hot_add_enabled = true
cpu_hot_remove_enabled = true
# Memory
memory = var.system_memory
memory_hot_add_enabled = true
# Network
network_interface {
network_id = data.vsphere_network.network.id
adapter_type = "e1000e"
}
# Storage
# Drive 0 (C)
disk {
label = "disk0"
unit_number = 0
size = data.vsphere_virtual_machine.template.disks.0.size
eagerly_scrub = data.vsphere_virtual_machine.template.disks.0.eagerly_scrub
thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
}
# Drive 1 (D)
disk {
label = "disk1"
unit_number = 1
size = var.system_disk1_size
eagerly_scrub = data.vsphere_virtual_machine.template.disks.1.eagerly_scrub
thin_provisioned = data.vsphere_virtual_machine.template.disks.1.thin_provisioned
}
# Template clone and OS settings
clone {
template_uuid = data.vsphere_virtual_machine.template.id
customize {
windows_options {
computer_name = var.system_name
admin_password = random_password.password.result
join_domain = var.system_domain
domain_admin_user = var.system_domain_admin_user
domain_admin_password = var.system_domain_admin_password
auto_logon = true
}
network_interface {
ipv4_address = var.system_ipv4_address
ipv4_netmask = var.system_ipv4_netmask
dns_server_list = var.system_dns_server_list
}
ipv4_gateway = var.system_ipv4_gateway
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的内容与您包含的内容相同,只是我在开始时resource "vsphere_virtual_machine" "server"添加并进行了更改,以便将其视为名称前缀而不是整个名称,添加当前索引以创建完整的唯一名称。我想您可能还需要遵循类似的策略,可能使用该函数来系统地计算 IP 地址,但为了简单起见,我将在此处将其保留。count = 2namevar.system_namesystem_ipv4_addresscidrhost
如果我们还更改变量文件,那么var.system_name这将从单个资源块中声明两个资源"server"实例:"server-1"
vsphere_virtual_machine.server[0]和name = "server-0"vsphere_virtual_machine.server[1]和name = "server-1"在您共享的示例中,它似乎count最适合您的情况,因为您的服务器虚拟机的其他配置都是相同的。但是,如果您需要将每个服务器视为完全独立配置,以便它们都可以具有潜在不同的参数,那么您还有元for_each参数形式的另一种选择。与它一样,count它从单个资源块声明多个资源实例,但它是针对映射中的每个元素执行此操作,而不仅仅是将整数增加到特定限制。
这种方法确实需要对输入变量采取稍微不同的策略,因为我们需要输入是对象映射,其中映射的每个元素代表一个虚拟机:
variable "virtual_machines" {
type = map(object({
system_cores = number
system_cores_per_socket = number
system_memory = number
system_ipv4_address = string
# (and so on, for all of the attributes that vary between
# your virtual machines)
}))
}
Run Code Online (Sandbox Code Playgroud)
因为这是定义所有虚拟机的单个变量,所以您还需要更改.tfvars文件以以不同的方式设置它:
vsphere_user = "administrator@vsphere.local"
vsphere_password = "#Password"
vsphere_server = "vsphere.server"
vsphere_datacenter = "Datacenter"
vsphere_datastore = "Storage_1"
vsphere_compute_cluster = "Cluster"
vsphere_network = "Network_1"
vsphere_virtual_machine_template = "Template_Microsoft_Windows_Server_2019_x64_english"
virtual_machines = {
server-1 = {
system_cores = 2
system_cores_per_socket = 2
system_memory = 2048
system_ipv4_address = "172.22.15.11"
# ...
}
server-2 = {
system_cores = 2
system_cores_per_socket = 2
system_memory = 2048
system_ipv4_address = "172.22.15.12"
# ...
}
}
Run Code Online (Sandbox Code Playgroud)
resource带有 set 的块看起来for_each像这样:
resource "vsphere_virtual_machine" "server" {
for_each = var.virtual_machines
# VM-Name
name = each.key
resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
datastore_id = data.vsphere_datastore.datastore.id
# System
firmware = "efi"
guest_id = data.vsphere_virtual_machine.template.guest_id
scsi_type = data.vsphere_virtual_machine.template.scsi_type
# CPU
num_cpus = each.value.system_cores
num_cores_per_socket = each.value.system_cores_per_socket
cpu_hot_add_enabled = true
cpu_hot_remove_enabled = true
# Memory
memory = each.value.system_memory
memory_hot_add_enabled = true
# Network
network_interface {
network_id = data.vsphere_network.network.id
adapter_type = "e1000e"
}
# Storage
# Drive 0 (C)
disk {
label = "disk0"
unit_number = 0
size = data.vsphere_virtual_machine.template.disks.0.size
eagerly_scrub = data.vsphere_virtual_machine.template.disks.0.eagerly_scrub
thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
}
# Drive 1 (D)
disk {
label = "disk1"
unit_number = 1
size = each.value.system_disk1_size
eagerly_scrub = data.vsphere_virtual_machine.template.disks.1.eagerly_scrub
thin_provisioned = data.vsphere_virtual_machine.template.disks.1.thin_provisioned
}
# Template clone and OS settings
clone {
template_uuid = data.vsphere_virtual_machine.template.id
customize {
windows_options {
computer_name = each.value.system_name
admin_password = random_password.password.result
join_domain = each.value.system_domain
domain_admin_user = each.value.system_domain_admin_user
domain_admin_password = each.value.system_domain_admin_password
auto_logon = true
}
network_interface {
ipv4_address = each.value.system_ipv4_address
ipv4_netmask = each.value.system_ipv4_netmask
dns_server_list = each.value.system_dns_server_list
}
ipv4_gateway = each.value.system_ipv4_gateway
}
}
}
Run Code Online (Sandbox Code Playgroud)
同样,这与您的原始块基本相同resource,但我添加了for_each = var.virtual_machines,设置name为each.key使用映射键作为名称,并将对变量的所有其他引用替换为对属性的引用each.value,它表示当前的值地图上的元素。
在这种情况下,该资源块将声明以下资源实例:
vsphere_virtual_machine.server["server-0"]和name = "server-0"vsphere_virtual_machine.server["server-1"]和name = "server-1"请注意,Terraform 现在使用映射键来标识每个实例,因此如果您编辑与文件中现有键关联的值.tfvars并运行terraform plan,那么 Terraform 将理解您打算使用该键更新现有对象,但是如果您向地图添加一个全新的密钥,然后 Terraform 会在您打算创建新虚拟机时理解这一点。随着时间的推移,您可以通过更新、创建和删除虚拟机在 中的相应条目来更新、创建和删除虚拟机var.virtual_machines。
Terraform 期望每次运行它时,您都会向它提供其负责管理的系统部分的完整状态的描述,因此不存在可以让 Terraform 添加新虚拟机的使用模型也无需为所有现有配置提供未更改的配置。如果您忽略现有的,那么 Terraform 将理解您打算销毁它们。
| 归档时间: |
|
| 查看次数: |
4554 次 |
| 最近记录: |