Logo

Personal Ops Runbook

Personal runbook covering infrastructure operations for Cloud, Kubernetes, OpenStack, and Ceph environments. Includes deployment and teardown procedures, node management, cluster monitoring setup, and incident response workflows compiled from day-to-day operational work. Intended strictly for personal reference — configurations and scripts are environment-specific and not guaranteed to work as-is elsewhere.

[VMWare] Phần 14 – Thêm Disk cho máy ảo vSphere sử dụng Dynamic Blocks


Nếu như bạn đang muốn tạo các resource giống nhau ví dụ như một máy ảo nhưng sẽ có nhiều disk hoặc nhiều card mạng bạn nên xem xét sử dụng Dynamic Block Terraform.

image

Ví dụ dưới đây cho thấy nếu bạn tạo vsphere_virtual_machine với nhiều ổ đĩa thì dưới đây là đoạn code cho thấy bạn phải nhập thủ công 3 block thông tin về disk. Và rất tiếc bạn không thể sử dụng “for_each” hoặc “count” xử lý từ đoạn code dưới.

resource "vsphere_virtual_machine" "vm" {
name = "mytestvm1"

# first boot disk
disk {
  label       = "disk0"
  unit_number = 0
  size        = 40
}

# second and third data disk
disk {
  label = "disk1"
  unit_number = 1
  size = 10
}

disk {
  label = "disk2"
  unit_number = 2
  size=20
}

Các Dynamic Block cung cấp cú pháp cho phép bạn thể hiện một block có thể thay đổi trong một resource. Dưới đây là cách mà mình thể hiện số lượng đĩa với dung lượng và tên ổ đĩa khác nhau trên cùng một resource của VM.

locals {
  disks = [
    { "id":1, "dev":"sdb", "sizeGB":10 },
    { "id":2, "dev":"sdc", "sizeGB":20  }
  ]
}

resource "vsphere_virtual_machine" "vm" {
name = "mytestvm1"

disk {
  label = "disk0"
  unit_number = 0
  size = 40
}

dynamic "disk" {
  for_each = [ for disk in local.disks: disk ]

  content {
   label       = "disk${disk.value.id}"
   unit_number = disk.value.id
   size        = disk.value.sizeGB
  }
}

Mình đang sử dụng một cấu trúc locals để tạo danh sách để sử dụng for_each lặp lại chúng.

for_each = [ for disk in local.disks: disk ]

Sau đây mình sẽ demo cho bạn thấy điều kỳ diệu của nó. Mình có 1 file main.tf đầy đủ như dưới đây.

provider "vsphere" {
  user           = var.vsphere_env.user
  password       = var.vsphere_env.password
  vsphere_server = var.vsphere_env.server
  allow_unverified_ssl = true
}

locals {
  disks = [
    { "id":1, "dev":"sdb", "sizeGB":100 },
    { "id":2, "dev":"sdc", "sizeGB":100  },
    { "id":3, "dev":"sdd", "sizeGB":100  },
    { "id":4, "dev":"sde", "sizeGB":100  },
    { "id":5, "dev":"sdf", "sizeGB":100  },
  ]
}

resource vsphere_virtual_machine "allvms" {
  for_each = var.vms

  resource_pool_id = data.vsphere_compute_cluster.this[each.key].resource_pool_id
  datastore_id     = data.vsphere_datastore.this[each.key].id

  name = each.value.vmname
  num_cpus = each.value.vCPU
  memory   = each.value.vMEM

  guest_id = data.vsphere_virtual_machine.template[each.key].guest_id
  scsi_type = data.vsphere_virtual_machine.template[each.key].scsi_type

  cdrom {
    client_device = true
  }

  network_interface {
    network_id   = data.vsphere_network.this[each.key].id
    adapter_type = data.vsphere_virtual_machine.template[each.key].network_interface_types[0]
  }
  wait_for_guest_net_timeout = 0

  disk {
    label = "disk0"
    unit_number = 0
    size  = each.value.vDisk
  }

  dynamic "disk" {
    for_each = [ for disk in local.disks: disk ]

    content {
    label       = "disk${disk.value.id}"
    unit_number = disk.value.id
    size        = disk.value.sizeGB
    }
  }

  clone {
    template_uuid = data.vsphere_virtual_machine.template[each.key].id
  }

  extra_config = {
    "guestinfo.metadata"          = base64encode(data.template_file.metadataconfig[each.key].rendered)
    "guestinfo.metadata.encoding" = "base64"
    "guestinfo.userdata"          = base64encode(data.template_file.kickstartconfig[each.key].rendered)
    "guestinfo.userdata.encoding" = "base64"
  }

  connection {
    host     = each.value.ip
    type     = "ssh"
    user     = "root"
    private_key = "${file("./common/id_rsa")}"
    timeout     = "10m"
  }

  provisioner "file" {
    source      = "./scripts/packages.sh"
    destination = "/usr/local/bin/packages"
  }

  provisioner "remote-exec" {
    inline = [
      "sudo chmod -R 777 /usr/local/bin/packages",
      "sudo packages function",
      "sudo sed -i 's|#PermitRootLogin.*|PermitRootLogin yes|' /etc/ssh/sshd_config",
      "sudo sed -i 's|#PasswordAuthentication.*|PasswordAuthentication yes|' /etc/ssh/sshd_config",
      "sudo sed -i 's|#   PasswordAuthentication.*|PasswordAuthentication yes|' /etc/ssh/ssh_config",
      "sudo service ssh restart || sudo systemctl restart sshd",
      "sudo echo 'root:Hoanghd164' | chpasswd"
    ]
  }
}

Bạn đừng quan tâm nhiều file trên, hãy chú ý đến 2 thành phần chính như sau:

Ở block locals mình sẽ tạo ra 1 list tên disks có chứa các thông tin các disk sẽ được tạo, ví dụ size, id, tên device,…

locals {
  disks = [
    { "id":1, "dev":"sdb", "sizeGB":100 },
    { "id":2, "dev":"sdc", "sizeGB":100  },
    { "id":3, "dev":"sdd", "sizeGB":100  },
    { "id":4, "dev":"sde", "sizeGB":100  },
    { "id":5, "dev":"sdf", "sizeGB":100  },
  ]
}

Ở block tiếp theo mình sẽ khai báo một block disk có lable là disk0 dùng để chạy OS.

Block dynamic disk mình sẽ dùng vòng lặp for để lấy các data ở block locals gán thông tin cho các disk chứa data.

disk {
    label = "disk0"
    unit_number = 0
    size  = each.value.vDisk
}

dynamic "disk" {
    for_each = [ for disk in local.disks: disk ]

    content {
        label       = "disk${disk.value.id}"
        unit_number = disk.value.id
        size        = disk.value.sizeGB
    }
}

Sau khi chạy terraform apply thì mình sẽ có 1 máy ảo như hình dưới, với disk 1 có 50GB để chứa OS và các disk còn lại mỗi disk là 100GB như chúng ta đã khai báo trong file main.tf

image

Hãy ssh vào server là list các disk lên, ta có kết quả như hình dưới.

$ lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
fd0       2:0    1    4K  0 disk
sda       8:0    0   50G  0 disk
├─sda1    8:1    0 49.9G  0 part /
├─sda14   8:14   0    4M  0 part
└─sda15   8:15   0  106M  0 part /boot/efi
sdb       8:16   0  100G  0 disk
sdc       8:32   0  100G  0 disk
sdd       8:48   0  100G  0 disk
sde       8:64   0  100G  0 disk
sdf       8:80   0  100G  0 disk
sr0      11:0    1   44K  0 rom

Việc sử dụng các Dynamic Block có thể rất đơn giản nó giúp thay đổi tài nguyên một cách đơn giản.

Đây là liên kết đến một ví dụ đầy đủ về việc tạo vsphere vm với một số lượng đĩa dữ liệu thay đổi bằng cách sử dụng các Dynamic Block.

Chúc các bạn thành công.