[Terraform] Create Virtual Machines in ESXi Server

Terraform is one of the Infrastructure as code (IaC) tools to automate deployment in cloud / on premises. Compare with AWS and Azure, which has their own IaC language (e.g. AWS cloudformation), but Terraform is more general purpose on multiple cloud environment. Terraform wrote in HashiCorp Configuration Language (HCL), which similar to YAML; but compare with other IaC (e.g. Pulumi), it cannot present complex infrastructure environment in code level even it has limited function; Also it is inconvenience on configuration management so Terraform need to work with other CD solution (e.g. Ansible). Even so, Terraform has a number of providers still make it can be one of the common used IaC tools.This demo will show how to use Terraform to create Ubuntu 22.0.4 as guest OS in ESXi server. Even though VMWare has their own provider, but it required vsphere license for it API. So this case will use another provider josenk/esxi to implement changes via Terraform.

  1. Setup Terraform provider.
    In text editor create a file named versions.tf and input content below.

    terraform {
      required_version = ">= 1.2.5"
      required_providers {
        esxi = {
          source = "registry.terraform.io/josenk/esxi"
        }
      }
    }
  2. Setup variable.
    In text editor create a file named variables.tf and input content below.

    variable "esxi_hostname" {
      description = "ESXI server host name."
    }
    
    variable "esxi_hostport" {
      description = "ESXI server port."
      default     = "22"
    }
    
    variable "esxi_hostssl" {
      description = "ESXI server SSH port."
      default     = "443"
    }
    
    variable "esxi_username" {
      description = "ESXI server user name."
      default     = "root"
    }
    
    variable "esxi_password" { # Unspecified will prompt
      description = "ESXI server password."
      sensitive = true
    }
    
    variable "default_password" {
      type = string
      sensitive = true
    }
    
    variable "nodes" {
      type    = list(string)
      description = "Names of VMs to be create."
      # Example value.
      default = ["vm-k8s-sr01", "vm-k8s-sr02", "vm-k8s-sr03"]
    }
    
    variable "ssh_public_key_path" {
      type = string
      description = "ssh public key which will set in guest OS for remote execute command."
    }
    variable "ssh_private_key_path" {
      type = string
      description = "ssh private key which will use to remote execute command."
      sensitive = true
    }
    variable "default-ssh-user" {
      type = string
      default = "ubuntu"
    }
    provider "esxi" {
      esxi_hostname = var.esxi_hostname
      esxi_hostport = var.esxi_hostport
      esxi_hostssl  = var.esxi_hostssl
      esxi_username = var.esxi_username
      esxi_password = var.esxi_password
    }
    
  3. Setup resource.
    In text editor create a file named main.tf and input content below.

    resource "random_id" "instance_id" {
      byte_length = 8
    }
    
    resource "esxi_guest" "default" {
      count = length(var.node_list)
    
      guest_name     = var.node_list[count.index]
      numvcpus       = var.esxi_vm_guest_default_settings.numvcpus
      memsize        = var.esxi_vm_guest_default_settings.memsize
      boot_disk_size = var.esxi_vm_guest_default_settings.boot_disk_size
      disk_store     = var.esxi_vm_guest_default_settings.disk_store
      network_interfaces {
        virtual_network = var.esxi_vm_guest_default_settings.virtual_network
      }
      ovf_source = "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.ova"
      ovf_properties {
        key   = "instance-id"
        value = random_id.instance_id.hex
      }
      ovf_properties {
        key   = "hostname"
        value = var.node_list[count.index]
      }
      ovf_properties {
        key   = "password"
        value = var.default_password
      }
    
       ovf_properties {
        key   = "public-keys"
        value = var.ssh_public_key
      }
    
      provisioner "file" {
        source      = "c:\\scripts\.24.3\\common.sh"
        destination = "/tmp/common.sh"
        connection {
          type     = "ssh"
          host = self.ip_address
          user     = local.default-ssh-user
          timeout = "15s"
          private_key = var.ssh_private_key
          agent = false
        }
      }
    
      provisioner "remote-exec" {
        connection {
          type     = "ssh"
          host = self.ip_address
          user     = var.default-ssh-user
          timeout = "15s"
          private_key = var.ssh_private_key
          agent = false
        }
    
        inline = [
          "echo '${var.default_password}' | sudo -S hostnamectl set-hostname ${var.node_list[count.index]}",
          "echo '${var.default_password}' | sudo -S apt update",
          "echo '${var.default_password}' | sudo -S apt upgrade -y",
          "echo '${var.default_password}' | sudo -S apt clean"
        ]
      }
    }
  4. Implement in terraform.
    In command prompt, go to file directory and execute command below.

    terraform init
    terraform plan
    terraform approve -autoapprove
  5. Verify result.
    In target ESXi server, check created VM exists or not.

Terraform HCL has been push to GitHub repository. But it is pack as module and there has some optimization for my home lab use.

About C.H. Ling 262 Articles
a .net / Java developer from Hong Kong and currently located in United Kingdom. Thanks for Google because it solve many technical problems so I build this blog as return. Besides coding and trying advance technology, hiking and traveling is other favorite to me, so I will write down something what I see and what I feel during it. Happy reading!!!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.