当您重新运行它以创建新实例时,Terraform 会删除之前的实例

问题描述 投票:0回答:2

我是 terraform 新手,使用的是 v0.12.20 版本。我注意到,当我重新运行它以创建新资源时,它就会删除现有资源。例如,如果我在某个环境中创建 10 个虚拟机并想要创建 5 个新虚拟机,那么它应该简单地创建检测更改的新虚拟机,而不是删除以前的虚拟机并创建新虚拟机。

 resource "vsphere_virtual_machine" "test_vms" {
      name = "${var.environment_test}${count.index + 1}"
      resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
      datastore_id     = "${element(data.vsphere_datastore.datastore.*.id, count.index)}"

      num_cpus         = var.cpu
      count            = var.count
      memory           = var.memory
      guest_id         = "ubuntu64Guest"
      folder           = var.vmfolder
      cpu_hot_add_enabled    = var.cpu_hot_add_enabled
      memory_hot_add_enabled = var.memory_hot_add_enabled
      scsi_type        = data.vsphere_virtual_machine.template.scsi_type
      wait_for_guest_net_timeout = -1

      network_interface {
         network_id    = data.vsphere_network.network[1].id
        adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0]
      }


      disk {
        label            = "disk0"
         size            = "${var.disk_size}"
        thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
      }

      clone {
        template_uuid = data.vsphere_virtual_machine.template.id

        customize {
          linux_options {
            host_name     =  "${var.environment_test}${count.index + 1}"
            domain       = var.vmdomain
          }

          network_interface {
              ipv4_address =   "${var.ips_test}${var.test_index + count.index}"
               ipv4_netmask =  "${var.netmask_app}"
         }
     dns_server_list = "${var.dns_server_list}"
             dns_suffix_list = "${var.dns_suffix_list}"

             ipv4_gateway = "${var.gateway_app}"
        }

          }

    }

地形计划的输出 -

Terraform will perform the following actions:

  # vsphere_virtual_machine.small_vm[0] must be replaced
-/+ resource "vsphere_virtual_machine" "test_vm" {

      ~ memory_share_count                      = 81920 -> (known after apply)
        memory_share_level                      = "normal"
        migrate_wait_timeout                    = 30
      ~ name                                    = "tests01" -> "testm01

      ~ clone {


              ~ linux_options {
                    domain       = "X.X.X.X."
                  ~ host_name    = "tests01" -> "testm01" # forces replacement
                    hw_clock_utc = true
                }

              ~ network_interface {
                  - dns_server_list = [] -> null
                  ~ ipv4_address    = "X.X.X.X" -> "X.X.X.X" # forces replacement
                    ipv4_netmask    = 24
                  - ipv6_netmask    = 0 -> null


terraform vsphere
2个回答
2
投票

不幸的是,Terraform 并不是为这种用例而设计的,在这种用例中,您只想创建新事物,然后将它们留给其他地方进行管理。相反,Terraform 的模型是对长期存在的对象的管理,随着时间的推移,您可能需要在 Terraform 中对它们进行更改。

在内部,Terraform 将配置中声明的每个资源实例与供应商远程 API 中的远程对象相关联。在您的情况下,每个

vsphere_virtual_machine.test_vm
实例(Terraform 调用
vsphere_virtual_machine.small_vm[0]
vsphere_virtual_machine.small_vm[1]
等,具体取决于您的
count
值)都与 vSphere 中的一个真实虚拟机相关联,当您稍后进行更改时Terraform 将计划更新或替换远程对象,以使远程系统匹配配置中的更改。

我认为最接近您想要实现的使用模式是定义一个输入变量,它是应该存在的虚拟机的描述映射,如下所示:

variable "virtual_machines" {
  type = map(object({
    num_cpus = number
  }))

  default = {
    tests01 = {
      num_cpus = 2
    }
    testm01 = {
      num_cpus = 1
    }
  }
}

我在对象中包含此

num_cpus
属性只是为了说明如何定义属性来表示除虚拟机之间可能需要不同的名称之外的值。 (如果您当前不需要这些虚拟机除了名称之外有任何不同,您可以将类型设置为 map(object({})) 以暂时使用空对象,以便以后有扩展空间。)

使用此变量,您可以使用

for_each

而不是

count
来告诉 Terraform 为
var.virtual_machines
地图中的每个元素创建一个虚拟机实例:

resource "vsphere_virtual_machine" "test_vms" { for_each = var.virtual_machines name = each.key resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id datastore_id = data.vsphere_datastore.datastore.id num_cpus = each.value.num_cpus memory = var.memory guest_id = "ubuntu64Guest" folder = var.vmfolder cpu_hot_add_enabled = var.cpu_hot_add_enabled memory_hot_add_enabled = var.memory_hot_add_enabled scsi_type = data.vsphere_virtual_machine.template.scsi_type wait_for_guest_net_timeout = -1 network_interface { network_id = data.vsphere_network.network[1].id adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0] } disk { label = "disk0" size = var.disk_size thin_provisioned = data.vsphere_virtual_machine.template.disks[0].thin_provisioned } clone { template_uuid = data.vsphere_virtual_machine.template.id customize { dns_server_list = var.dns_server_list dns_suffix_list = var.dns_suffix_list ipv4_gateway = var.gateway_app linux_options { host_name = each.key domain = var.vmdomain } network_interface { ipv4_address = "${var.ips_test}${var.test_index + count.index}" ipv4_netmask = var.netmask_app } } } }

resource "vsphere_virtual_machine" "test_vms"

块内,我使用

each.key
访问
var.virtual_machines
(在本例中为虚拟机名称)中的每个键,并使用
each.value
访问包含
num_cpus
属性的相应对象。

鉴于我上面声明的默认值

var.virtual_machines

,Terraform 会将其解释为创建两个具有以下跟踪地址的虚拟机的请求:


    vsphere_virtual_machine.test_vms["tests01"]
  • (有两个CPU)
  • vsphere_virtual_machine.test_vms["testm01"]
  • (使用一个CPU)
    
    
    
  • 请注意,Terraform 使用地图中的键来跟踪此资源的每个单独实例。当您想要添加新虚拟机而不打扰其他虚拟机时,可以向
var.virtual_machines

的值添加新条目,

保留所有现有元素
。每次您向该地图添加新元素并再次运行 terraform apply 时,Terraform 都会计划创建一个新的虚拟机实例。同样,如果您删除或编辑该地图中的条目,那么 Terraform 将计划销毁或更新/替换相应的虚拟机。

特别是对于
环境

的问题,而不是单个虚拟机的问题,请注意,通常最好为每个环境创建一个单独的 Terraform 配置,以便您可以单独更新每个环境,而不会冒更新一个环境对另一个环境进行意外更改的风险。 常见的方法是使用您已经编写的配置作为

共享模块

,然后对于您想要创建的每个新环境,您可以编写一个小的新配置,其中仅包含对该模块的单个调用适用于该特定环境的设置: module "environment1" { # This is a relative path to whatever directory contains # the module whose configuration we've been discussing so far. source = "../../modules/environment" virtual_machines = { env1foo = { num_cpus = 2 } env1bar = { num_cpus = 2 } } vmfolder = "example" cpu_hot_add_enabled = false # (and so on, for all of the other environment-specific variables # you need to override) }

每个单独的 Terraform 模块都是一个单独的目录,因此您可以将目录结构调整为如下所示,例如:

- environments/ - environment1/ - environment.tf - environment2/ - environment.tf - modules - environment - variables.tf - main.tf - (etc)

要创建一个新环境,您需要创建一个新的 
environments

子目录并在其中写入一个新的

environment.tf
,然后切换到该目录并运行 Terraform:

cd environments/environment1 terraform init terraform apply

Terraform 在单独的 
state

快照中单独跟踪每个配置的对象,因此通过为每个配置拥有单独的配置目录,您可以单独处理每个环境,而无需涉及其他环境的任何配置。但是,它们中的每一个都将共享相同的“环境”模块,因此它们都将根据相同的定义构建,并且您可以随时更新该共享的“环境”模块,以进行应适用于所有模块的更改。您的环境。


0
投票

© www.soinside.com 2019 - 2024. All rights reserved.