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ę:
- Introduction to the Terraform vSphere Provider
- Using Infrastructure as Code to Automate VMware Deployments
- Infrastructure as Code for VMware with HashiCorp Terraform
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”:
|
|
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 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



















