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