TERRAFORM dla aministratorów vSphere | “Sekretny” przykład użycia

Wprowadzenie

Jest to trzeci post z serii przygód VMwarowego świata, dla osób które poznają świat terraforma. Poprzednie publikacje:

Słów kilka…

Co warto wiedzieć o providerze, na którym będziemy pracować. Historia tego providera rozpoczęła się w czerwcu 2017 roku a informację o zmianach i ich częstotliwościach można śledzić poprzez plik CHANGELOG.md umieszczony na GIThubie providera.

Może się powtórzę, ale dobre pozycję, zanim wystartujemy do zapoznania się:

 

Architektura w scenariuszu:

 

Przykładowe zastosowanie:
  • laboratoria vSphere na żądanie wg. przygotowanej konfiguracji
  • POC vSphere na żądanie wg, przygotowanej konfiguracji (można mieć różne wersje przygotowane do zaprezentowania klientowi)
  • część rozwiązania do wdrażania całej infrastruktury SDDC. Po połączeniu z ansiblem widzę wielkie możliwości. Niedługo więcej opowiem Tobie o ansiblu własnie 🙂 w zastosowaniach VMwarowych.

 

Naszym celem w tym scenariuszy będzie:
  • stworzenie klastra hostów
  • stworzenie lokalnego datastore ze znalezionych lokalnie dysków
  • stworzenie NFSv3 datastora z wystawionego NFSa
  • stworzenie VDSa i wrzucenie do niego określonych hostów
  • stworzenie i konfiguracja portgrup na VDSie
  • stworzenie 3 resource pooli
  • stworzenie folderów i subfolderów na maszyny wirtualne
  • stworzenie testowo pustych maszyn
  • stworzenie maszyny (Centos) z template i skonfigurowanie jej adresu IP aby mieć z nią komunikację

 

Docelowo wyglądać to będzie tak:

 

 

Wymagania do scenariusza:

  • działające VCSA (vCenter)
  • podpięte hosty do vCenter inventory (na dzień dzisiejszy provider terraforma nie skonfiguruje jeszcze nam samego hosta)
  • utworzony obiekt w inventory “Datacenter”
  • w moim scenariuszu będę korzystał z template maszyny wirtualnej, który wcześniej wrzuciłem już na tymczasowy datastor NFS, który podpiąłem do jednego z ESXi
  • Terraform w wersji 0.12 (link do archiwum wersji) na której testowałem scenariusz. W nowszychwersjach nie mogę zagwarantować iż będzie działało tak samo
  • Narzędzie do pisania kodu to w moim przypadku Visual Studio Code + plugin instalowany z edytora do kolorowania kodu itp. o nazwie “Terraform” autorstwa Mikael Olenfalk

 

U mnie to wygląda tak jako stan początkowy (alerty nie mają znaczenia):

 

Dalej ja (nie jest to konieczne) przygotowuję sobie też odpowiednią strukturę katalogów w projekcie terraforma w Visual Studio Code. Moja sugerowana struktura na dzień dzisiejszy jeśli będziemy nasz kod testować w 2 środowiskach (w moim przypadku będę pracował tylko na konfiguracji przygotowanej dla środowiska developerskiego “EXEA-DC-DEV”:

 

  • vsphere_example1
    • environments
      • EXEA-DC-DEV
        • provider.tf
        • variables.tf
        • vsphere_module_call.tf
      • EXEA-DC-PROD
        • provider.tf
        • variables.tf
        • vsphere_module_call.tf
    • modules
      • variables.tf
      • vsphere_resources.tf
    • readme.md
    • terraform.tfvars
    • .gitignore

 

Pliki readme.md, .gitignore nie są wymagane ale mogą by dodatkiem jeśli będziesz chciał wysyłać swój kod gdzies na GITa wówczas w pliku .gitignore umieszcza sie pliki, które nie maja tam być wysyłane. Szczególnie jesli masz jakies dane w plikach, które nie powinny zostać gdzies dalej przesyłane.

 

Inicjalizacja providera – od tego zacznij

Zanim oczywiście wykonamy pierwsze wdrożenie za pomocą terraforma najpierw należy zainicjować providera jakiego zadeklarowaliśmy w pliku konfiguracyjnym “vsphere_example1\environments\EXEA-DC-DEV\provider.tf”

Rozpoczynamy od deklaracji vCenter na którym będziemy chcieli pracować.

// Blok odpowiedzialny za łączenie z vCenter
provider "vsphere" {
  user                 = "${var.vc_user}"
  password             = "${var.vc_pass}"
  vsphere_server = "${var.vc_vsphere_server}"
  allow_unverified_ssl = "${var.vc_allow_unverified_ssl}"
  }

 

Inicjalizacja providera:

 

 

Wywołanie terraforma

W związku z tym iż w scenariuszu będę używał czegoś takiego jak moduły terraforma wymagane jest aby przekazywać do takiego modułu wartości zmiennych, które mogą być różne zależnie od środowiska, w którym ten moduł będziemy chcieli zastosować.

Robię to używając pliku “vsphere_example1\environments\EXEA-DC-DEV\vsphere_module_call.tf” wywołującego moduł do którego podawane są wartości jakie podać mogę ręcznie:


module "dev_environment" {
  source                = "../../modules"
  hosts                 = ["sg-esxi01.exea.dev", "sg-esxi02.exea.dev"]
  environment           = "DEV"
  network_interfaces    = ["vmnic1"]
  company               = "EXEA"
  nfs_server_ip         = ["10.1.1.99"]
  template_linux_centos = "centos_template"
  virtual_machines_dns_servers = ["8.8.8.8"]
  vm_mgt_ip = "10.1.1.88"
  vm_gw = "10.1.1.1"
  vm_dns = ["8.8.8.8"]
  hostname = "managementvm"
  host_domain = "dev.local"
}

 

Terraforma uruchamiamy wywołaniem w katalogu “vsphere_example1\environments\EXEA-DC-DEV” z referencją do pliku terraform.tfvars, który lokalnie przechowuje “credentiale” do środowiska vSphere

 

Informacyjnie:

Poniższe wpisy dokonać możesz w module “modules/vsphere_resources.tf”. Mógłbyś także umieścić plik z referencyjnym modułem przykładowo “modules/przykladowakonfiguracja/vsphere_resources.tf”. Wówczas jednak trzeba by zmodyfikować parametr “source” w pliku inicjującym na “../../modules/przykladowakonfiguracja/”

Tworzenie klastra hostów

Etap 1 – pobieranie istniejących danych ze środowiska

// Pobranie informacji o istniejących hostach
data "vsphere_host" "hosts" {
  count         = "${length(var.hosts)}"
  name          = "${var.hosts[count.index]}"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
  }

// Pobranie informacji o istniejącym datacenter
data "vsphere_datacenter" "old_datacenter" {
  name = "${var.company}-DC-${var.environment}"
  }


Etap 2  – tworzenie przykładowego klastra z hostami

W tym przykładzie parametr “ha_enabled” jest “false” ponieważ wyeliminowało to losowe występowania błędów przy opcji “destroy”:


resource "vsphere_compute_cluster" "compute_cluster" {
  name            = "Terraform${var.company}_Cluster-VMUG_${var.environment}"
   datacenter_id   = "${data.vsphere_datacenter.old_datacenter.id}"
  host_system_ids = ["${data.vsphere_host.hosts.*.id}"]
  drs_enabled          = true
  drs_automation_level = "fullyAutomated"
  ha_enabled = false
  force_evacuate_on_destroy = true
}

Tworzenie NFSv3 datastora z wystawionego NFSa


resource "vsphere_nas_datastore" "nfsdatastore" {
  name            = "Datastore-${var.environment}-NFS"
  host_system_ids = ["${data.vsphere_host.hosts.*.id}"]
  type         = "NFS"
  remote_hosts = ["${var.nfs_server_ip}"]
     remote_path  = "/mnt/nfs/nfs1"
  depends_on = ["vsphere_compute_cluster.compute_cluster"]
}

Tworzenie VDSa i wrzecenie do niego określonych hostów


resource "vsphere_distributed_virtual_switch" "dvs" {
  name          = "VDS-${var.company}-${var.environment}-MGMT"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
  uplinks         = ["uplink1"]
  
  host {
   
   host_system_id = "${data.vsphere_host.hosts.0.id}"
  devices        = ["${var.network_interfaces}"]
  }

  host {
    host_system_id = "${data.vsphere_host.hosts.1.id}"
    devices        = ["${var.network_interfaces}"]
  }
  depends_on = ["vsphere_compute_cluster.compute_cluster"]
}

resource "vsphere_distributed_virtual_switch" "dvs_nsx" {
  name          = "VDS-${var.company}-${var.environment}-NSX"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
  depends_on = ["vsphere_compute_cluster.compute_cluster"]
}

Tworzenie i konfiguracja portgrup na VDSie


resource "vsphere_distributed_port_group" "pg_mgmt" {
  name = "PG-${var.company}-${var.environment}-MGT"
  distributed_virtual_switch_uuid = "${vsphere_distributed_virtual_switch.dvs.id}"
  vlan_id = 0
  }
 resource "vsphere_distributed_port_group" "pg_backup" {
  name = "PG-${var.company}-${var.environment}-BACKUP"
  distributed_virtual_switch_uuid = "${vsphere_distributed_virtual_switch.dvs.id}"
  vlan_id = 1002
    
}
resource "vsphere_distributed_port_group" "pg_repl" {
  name = "PG-${var.company}-${var.environment}-REPLICATION"
  distributed_virtual_switch_uuid = "${vsphere_distributed_virtual_switch.dvs.id}"
  vlan_id = 1003
}
resource "vsphere_distributed_port_group" "pg_vmotion" {
  name = "PG-${var.company}-${var.environment}-vMOTION"
  distributed_virtual_switch_uuid = "${vsphere_distributed_virtual_switch.dvs.id}"
  vlan_id = 1004
}
resource "vsphere_distributed_port_group" "pg_vsan" {
  name = "PG-${var.company}-${var.environment}-VSAN"
  distributed_virtual_switch_uuid = "${vsphere_distributed_virtual_switch.dvs.id}"
  vlan_id = 1005
}

Tworzenie przykładowych resource pool


resource "vsphere_resource_pool" "resource_pool_priority" {
  name = "Mission Critical VMs - ${var.environment}"
  parent_resource_pool_id = "${vsphere_compute_cluster.compute_cluster.resource_pool_id}"
    depends_on = ["vsphere_compute_cluster.compute_cluster"]
}
resource "vsphere_resource_pool" "resource_pool_regular" {
  name = "Regular VMs - ${var.environment}"
  parent_resource_pool_id = "${vsphere_compute_cluster.compute_cluster.resource_pool_id}"
    depends_on = ["vsphere_compute_cluster.compute_cluster"]
}
resource "vsphere_resource_pool" "resource_pool_mgmt" {
  name = "Management - ${var.environment}"
  parent_resource_pool_id = "${vsphere_compute_cluster.compute_cluster.resource_pool_id}"
    depends_on = ["vsphere_compute_cluster.compute_cluster"]
}

Tworzenie folderów i subfolderów na maszyny wirtualne


//Tworzenie folderów pod kategorie maszyn
resource "vsphere_folder" "mgmt" {
  type = "vm"
  path = "Management"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
}

//Tworzenie subfolderów pod kategorie maszyn
resource "vsphere_folder" "ActiveDirectory" {
  type = "vm"
  path = "${vsphere_folder.mgmt.path}/ActiveDirectory"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
}

//Tworzenie subfolderów pod kategorie maszyn
resource "vsphere_folder" "Monitoring" {
  type = "vm"
  path = "${vsphere_folder.mgmt.path}/Monitoring"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
}

//Tworzenie subfolderów pod kategorie maszyn
resource "vsphere_folder" "backup" {
  type = "vm"
  path = "${vsphere_folder.mgmt.path}/Backup MGMT"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
}

//Tworzenie subfolderów pod kategorie maszyn
resource "vsphere_folder" "automation" {
  type = "vm"
  path = "${vsphere_folder.mgmt.path}/Automation"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
}

//Tworzenie folderu dedykowane dla zespołów
resource "vsphere_folder" "teams" {
  type = "vm"
  path = "Teams"
  datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
}

//Automatyczne generowanie subfolderów dla pierwszych 5 zespołów
resource "vsphere_folder" "teamfolder" {
  type = "vm"
  path = "${vsphere_folder.teams.path}/Team-${count.index + 1}"
datacenter_id = "${data.vsphere_datacenter.old_datacenter.id}"
count = 5
}

Stworzenie testowo pustych maszyn


resource "vsphere_virtual_machine" "vm" {
  name             = "VM-${var.company}-${var.environment}-${count.index + 1}"
  # resource_pool_id = "${vsphere_compute_cluster.compute_cluster.resource_pool_id}" # lokalizacja w klastrze poza resource pool
  resource_pool_id = "${vsphere_resource_pool.resource_pool_mgmt.id}"
  datastore_id     = "${vsphere_nas_datastore.nfsdatastore.id}"

  num_cpus = 2
  memory   = 256
  guest_id = "other3xLinux64Guest"
  count = 2
  
  wait_for_guest_ip_timeout = 0
  wait_for_guest_net_timeout = 0
  
  network_interface {
    network_id = "${vsphere_distributed_port_group.pg_mgmt.id}"
  }

  disk {
    label = "disk0"
    size  = 5
  }
  depends_on = ["vsphere_nas_datastore.nfsdatastore"]
}


Tworzenie maszyny (Centos) z template + konfiguracja sieci

Uwagi: Obraz musi mieć zainstalowane vmware toolsy + perl.


resource "vsphere_virtual_machine" "vm_template" {
count = 1
name             = "VM-template_${var.company}-${var.environment}-${count.index + 1}"
resource_pool_id = "${vsphere_compute_cluster.compute_cluster.resource_pool_id}"
datastore_id     = "${vsphere_nas_datastore.nfsdatastore.id}"

num_cpus = 2
memory   = 1024
guest_id = "${data.vsphere_virtual_machine.template_linux_1.guest_id}"

network_interface {
    network_id   = "${vsphere_distributed_port_group.pg_mgmt.id}"
    //adapter_type = "${data.vsphere_virtual_machine.template_linux_1.network_interface_types[0]}"
    adapter_type = "vmxnet3"
  }

disk {
    label = "disk0"
    size  = "${data.vsphere_virtual_machine.template_linux_1.disks.0.size}"
  }
# Additional disk
  disk {
    label = "disk1"
    size  = "5"
    unit_number = 1
  }

clone {
    template_uuid = "${data.vsphere_virtual_machine.template_linux_1.id}"


customize {
      linux_options {
        host_name = "${var.hostname}"
        domain    = "${var.host_domain}"
             }

         network_interface {
        ipv4_address = "${var.vm_mgt_ip}"
        ipv4_netmask = 24
      }     
      ipv4_gateway = "${var.vm_gw}"
      dns_server_list = ["${var.vm_dns}"]
      
    }
}
wait_for_guest_ip_timeout = 0
wait_for_guest_net_timeout = 0
}

 

Co dalej…

 

Po zakodowaniu założonego bloku kodu infrastruktury wykonujemy dwie przykładowe komendy:

terraform plan

Komendą tą sprawdzamy jakie zmiany będą wykonane na podstawie kodu. W ten sposób można także zweryfikować czy konfiguracja w pliku terraforma (która jest naszą wzorcową) odpowiada stanowi środowiska.

 

Poprzez komendę:

terraform apply

ponownie potwierdzamy zmiany jakie zostaną wprowadzone w środowisku oraz potwierdzamy ją słowem “yes”

 

Napotkane problemy:

  • Brak ma komunikacji z maszyną pomimo skonfigurowanego IP w maszynie ==> MGMT portgrupa musiała mieć VLAN 0
  • Przy przygotowywaniu template dla Linuxa (CentOS) trzeba pamiętać o instalowaniu oprócz vmware toolsów także perla. Co ciekawe bez tego “customizacja” nie działa.

Podsumowanie

Myślę, że nie wyczerpałem tematu, bo możliwości tego providera każdego miesiąca powiększają się i warto zaglądać na stronę providera aby zweryfikować czy nie pojawiło się coś nowego. Moim celem był prosty deployment przykładowego środowiska vSphere i podczas moich testów działało to bezproblemowo. Zachęcam też do zapisania sie do listy mailowej bloga aby być na bieżąco z kolejnymi artykułami, które będę komunikował w podobnych tematach.

 

Informacje o nowych artykułach, świecie wirtualizacji i "cloud computingu" prosto na Twojego maila:

Dodam Cię do listy mailowej, z której możesz wypisać się w dowolnym momencie (jeden klik.) | Polityka Prywatności