PowerShell一键自动化部署ESXI及VSAN
脚本自动化部署vSphere和配置VSAN集群环境,可以完成以下一些操作:
1 部署嵌套的 ESXi 主机:通过 OVA 文件导入和配置多个嵌套 ESXi 主机,设置其网络信息、CPU、内存和磁盘大小,并将其加入到指定的集群中。
2 部署 vCenter Server Appliance(VCSA):根据预定义的 JSON 配置文件,部署 VCSA 并进行相应的配置,包括网络设置、存储、部署规模、主机名、SSO 配置等。
3 创建新的数据中心和集群:连接到新部署的 vCenter Server,创建新的数据中心和集群,并根据需要配置 vSAN 磁盘组。
4 添加 ESXi 主机到 vCenter:将嵌套的 ESXi 主机添加到新创建的集群中,也可以选择使用 DNS 名称来添加主机。
5 清除 vSAN 告警和进行最终配置:清除 vSAN 告警并进行额外的配置,例如开启 vMotion、退出维护模式等。
使用时需要注意以下几点:
脚本中使用了一些默认值和硬编码的路径,需要根据实际情况进行修改,比如 OVA 存储路径、vCenter 安装镜像解压后的文件夹路径等。
在执行脚本之前,需要确保目标环境已经满足一定的条件,比如网络设置、存储准备等。
需要对脚本中的用户名、密码等敏感信息进行适当的保护和管理,避免泄露。
在执行脚本时,建议先在测试环境进行验证,确保脚本的正确性和稳定性。
此脚本仅用于测试学习使用,代码如下:
####################################################################### # 函数列表 # ####################################################################### # 日志记录 Function logRecord(){ [cmdletbinding()] Param ( # 参数列表,参数属性 # 具体日志信息 [parameter(Mandatory=$True)] [string] $logString, # 日志存储路径,包括路径和文件名称全路径 [parameter(Mandatory=$False)] [string] $logPath="", [Parameter(Mandatory=$True)] [ValidateSet('INFO','ERROR')] [string] $logLevel ) $time = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' if($logPath){ echo "$time $logLevel $logString" >> $logPath }else{ if($logLevel -eq "INFO"){ write-host -ForegroundColor Green "$time $logLevel $logString" }else{ write-host -ForegroundColor red "$time $logLevel $logString" } } } ####################################################################### # 参数列表 # ####################################################################### # 第一层 vCenter Server 信息 $vCenterIp = "172.17.3.110" $vCenterUsername = "administrator@vsphere.local" $vCenterPassword = "P@ssw0rd" # 部署的组件 $deployNestedESXiVMs = 1 # 部署 ESXi $deployVCSA = 1 # 部署 VCSA $setupNewVC = 1 # 创建数据中心、集群 $configureVSANDiskGroup = 1 # 配置磁盘组 $addESXiHostsToVC = 1 # 添加主机到VC $addHostByDnsName = 0 # 添加主机到VC使用DNS名称 $clearVSANHealthCheckAlarm = 1 # 清除vSAN告警 # 嵌套ESXi############################################################# # 嵌套ESXi OVA存储路径 # $nestedESXiApplianceOVA = "D:\test-vm.ova" ESXI主机模板位置 # 嵌套ESXi网络信息,以及需要部署的嵌套ESXi数量 $nestedESXiHostnameToIPs = @{ "Lab-esxi-113" = "172.17.3.70" "Lab-esxi-114" = "172.17.3.71" "Lab-esxi-115" = "172.17.3.72" } # 嵌套ESXi资源配置 $NestedESXivCPU = "4" $NestedESXivMEM = "16" # GB $NestedESXiCachingvDisk = "8" # GB $NestedESXiCapacityvDisk = "100" # GB # VCSA################################################################# # vCenter安装镜像解压后的文件夹 $VCSAInstallerPath = "E:\ISO\VC" # VCSA部署规模 $vcsaSize2MemoryStorageMap = @{ "tiny"=@{"cpu"="2";"mem"="12";"disk"="415"}; "small"=@{"cpu"="4";"mem"="19";"disk"="480"}; "medium"=@{"cpu"="8";"mem"="28";"disk"="700"}; "large"=@{"cpu"="16";"mem"="37";"disk"="1065"}; "xlarge"=@{"cpu"="24";"mem"="56";"disk"="1805"} } # VCSA部署配置 $VCSADeploymentSize = "tiny" # 部署规模 $VCSADisplayName = "Lab-VCSA-112" # 虚拟机名称 $VCSAIPAddress = "172.17.3.80" # IP地址 $VCSAHostname = "172.17.3.80" # 主机名(如果没有DNS解析则使用IP地址) $VCSAPrefix = "24" # 掩码长度 $VCSASSODomainName = "vsphere.local" # SSO域 $VCSASSOPassword = "P@ssw0rd" # SSO密码 $VCSARootPassword = "P@ssw0rd" # ROOT密码 $VCSASSHEnable = "true" # SSH # 嵌套环境配置 $NewVCDatacenterName = "Datacenter" $NewVCVSANClusterName = "Cluster" # 公共配置############################################################# # 使用的存储、端口组等信息 $vmDatacenter = "Datacenter01" # 数据中心 $vmCluster = "cluster01" # 集群 $vmNetwork = "VM Network" # 端口组 $vmDatastore = "Datastore_new" # 存储 $vmNetmask = "255.255.255.0" # 掩码 $vmGateway = "172.17.3.254" # 网关 $vmDNS = "172.17.3.10" # DNS $vmNTP = "172.17.3.10" # NTP $vmPassword = "P@ssw0rd" # 密码 $vmDomain = "powershell.com" # 域 $vmSyslog = "172.17.3.90" # Syslog $vCenterConnection = $null try{ $vCenterConnection = Connect-VIServer $vCenterIp -User $vCenterUsername -Password $vCenterPassword -WarningAction SilentlyContinue logRecord -logLevel INFO -logString "连接 vCenter Server $vCenterIp 成功" }catch{ logRecord -logLevel ERROR -logString "连接 vCenter Server $vCenterIp 失败" return ; } # 获取存储、数据中心、ESXi主机 if(($deployNestedESXiVMs -eq 1) -or ($deployVCSA -eq 1)) { try{ $datastore = Get-Datastore -Server $vCenterConnection -Name $vmDatastore | Select -First 1 logRecord -logLevel INFO -logString "获取存储 $vmDatastore 成功" }catch{ logRecord -logLevel ERROR -logString "获取存储 $vmDatastore 失败" } try{ $cluster = Get-Cluster -Server $viConnection -Name $VMCluster logRecord -logLevel INFO -logString "获取集群 $VMCluster 成功" }catch{ logRecord -logLevel ERROR -logString "获取集群 $VMCluster 失败" } try{ $datacenter = $cluster | Get-Datacenter logRecord -logLevel INFO -logString "获取数据中心 $($datacenter.name) 成功" }catch{ logRecord -logLevel ERROR -logString "获取数据中心 $($datacenter.name) 失败" } try{ $vmHost = $cluster | Get-VMHost | Select -First 1 logRecord -logLevel INFO -logString "获取主机 $($vmHost.name) 成功" }catch{ logRecord -logLevel ERROR -logString "获取主机 $($vmHost.name) 失败" } } if($vCenterConnection){ if($deployNestedESXiVMs -eq 1) { # 遍历嵌套ESXi信息 foreach($nestedESXiHostKey in $nestedESXiHostnameToIPs.keys) { $vmName = $nestedESXiHostKey $vmIpAddress = $nestedESXiHostnameToIPs[$nestedESXiHostKey] # 获取OVA配置 # $ovfconfig = Get-OvfConfiguration $NestedESXiApplianceOVA $ovfconfig = Get-OvfConfiguration "D:\test-vm.ova" $networkMapLabel = ($ovfconfig.ToHashTable().keys | where {$_ -Match "NetworkMapping"}).replace("NetworkMapping.","").replace("-","_").replace(" ","_") # 虚拟机端口组 $ovfconfig.NetworkMapping.$networkMapLabel.value = $vmNetwork # 网络信息 $ovfconfig.common.guestinfo.hostname.value = $vmName $ovfconfig.common.guestinfo.ipaddress.value = $vmIpAddress $ovfconfig.common.guestinfo.netmask.value = $vmNetmask $ovfconfig.common.guestinfo.gateway.value = $vmGateway $ovfconfig.common.guestinfo.dns.value = $vmDNS $ovfconfig.common.guestinfo.domain.value = $vmDomain $ovfconfig.common.guestinfo.ntp.value = $vmNTP $ovfconfig.common.guestinfo.syslog.value = $vmSyslog $ovfconfig.common.guestinfo.password.value = $vmPassword # SSH if($VMSSH -eq "true") { $VMSSHVar = $true } else { $VMSSHVar = $false } $ovfconfig.common.guestinfo.ssh.value = $VMSSHVar # 自动创建datastore1 $ovfconfig.common.guestinfo.createvmfs.value = $false $isExsit = Get-VM -Name $vmName -ErrorAction SilentlyContinue if($isExsit){ logRecord -logLevel INFO -logString "虚拟机 $vmName 已存在,跳过该虚拟机导入" continue } # 导入OVA logRecord -logLevel INFO -logString "导入虚拟机 $vmName" $vm = Import-VApp -Source "D:\test-vm.ova" -OvfConfiguration $ovfconfig -Name $vmName -Location $cluster -VMHost $vmhost -Datastore $datastore -DiskStorageFormat thin # 添加网卡 New-NetworkAdapter -VM $vm -Type Vmxnet3 -NetworkName $vmNetwork -StartConnected -confirm:$false | Out-Null New-NetworkAdapter -VM $vm -Type Vmxnet3 -NetworkName $vmNetwork -StartConnected -confirm:$false | Out-Null New-NetworkAdapter -VM $vm -Type Vmxnet3 -NetworkName $vmNetwork -StartConnected -confirm:$false | Out-Null $vm | New-AdvancedSetting -name "ethernet2.filter4.name" -value "dvfilter-maclearn" -confirm:$false -ErrorAction SilentlyContinue | out-null $vm | New-AdvancedSetting -Name "ethernet2.filter4.onFailure" -value "failOpen" -confirm:$false -ErrorAction SilentlyContinue | out-null $vm | New-AdvancedSetting -name "ethernet3.filter4.name" -value "dvfilter-maclearn" -confirm:$false -ErrorAction SilentlyContinue | out-null $vm | New-AdvancedSetting -Name "ethernet3.filter4.onFailure" -value "failOpen" -confirm:$false -ErrorAction SilentlyContinue | out-null $vm | New-AdvancedSetting -name "ethernet4.filter4.name" -value "dvfilter-maclearn" -confirm:$false -ErrorAction SilentlyContinue | out-null $vm | New-AdvancedSetting -Name "ethernet4.filter4.onFailure" -value "failOpen" -confirm:$false -ErrorAction SilentlyContinue | out-null # 设置CPU和内存大小 Set-VM -Server $viConnection -VM $vm -NumCpu $NestedESXivCPU -MemoryGB $NestedESXivMEM -Confirm:$false | out-null # 设置磁盘大小 Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 2" | Set-HardDisk -CapacityGB $NestedESXiCachingvDisk -Confirm:$false | out-null Get-HardDisk -Server $viConnection -VM $vm -Name "Hard disk 3" | Set-HardDisk -CapacityGB $NestedESXiCapacityvDisk -Confirm:$false | out-null # 开机 $vm | Start-Vm -RunAsync | Out-Null } } if($deployVCSA -eq 1) { $isExsit = Get-VM -Name $VCSADisplayName -ErrorAction SilentlyContinue if($isExsit){ logRecord -logLevel INFO -logString "虚拟机 $VCSADisplayName 已存在,跳过该虚拟机导入" return ; } $config = (Get-Content -Raw "$($VCSAInstallerPath)\vcsa-cli-installer\templates\install\embedded_vCSA_on_VC.json") | convertfrom-json $config.'new_vcsa'.vc.hostname = $vCenterIp # 第一层vCenter IP $config.'new_vcsa'.vc.username = $vCenterUsername # 第一层vCenter 用户 $config.'new_vcsa'.vc.password = $vCenterPassword # 第一层vCenter 密码 $config.'new_vcsa'.vc.deployment_network = $vmNetwork # 端口组 $config.'new_vcsa'.vc.datastore = $datastore # 存储 $config.'new_vcsa'.vc.datacenter = $datacenter.name # 第一层数据中心名称 $config.'new_vcsa'.vc.target = $VMCluster # 第一层集群名称 $config.'new_vcsa'.appliance.thin_disk_mode = $true # 磁盘模式 $config.'new_vcsa'.appliance.deployment_option = $VCSADeploymentSize # 部署规模 $config.'new_vcsa'.appliance.name = $VCSADisplayName # 虚拟机名称 $config.'new_vcsa'.network.ip_family = "ipv4" # 网络栈 $config.'new_vcsa'.network.mode = "static" # 网络模式 $config.'new_vcsa'.network.ip = $VCSAIPAddress # IP地址 $config.'new_vcsa'.network.dns_servers[0] = $VMDNS # DNS $config.'new_vcsa'.network.prefix = $VCSAPrefix # 掩码长度 $config.'new_vcsa'.network.gateway = $VMGateway # 网关 $config.'new_vcsa'.os.ntp_servers = $VMNTP # NTP $config.'new_vcsa'.network.system_name = $VCSAHostname # 计算机名 $config.'new_vcsa'.os.password = $VCSARootPassword # ROOT密码 if($VCSASSHEnable -eq "true") { $VCSASSHEnableVar = $true } else { $VCSASSHEnableVar = $false } $config.'new_vcsa'.os.ssh_enable = $VCSASSHEnableVar # SSH $config.'new_vcsa'.sso.password = $VCSASSOPassword # SSO密码 $config.'new_vcsa'.sso.domain_name = $VCSASSODomainName # SSO域 logRecord -logLevel INFO -logString "创建VCSA JSON部署配置文件" $config | ConvertTo-Json | Set-Content -Path "$($ENV:Temp)\jsontemplate.json" logRecord -logLevel INFO -logString "部署VCSA..." # 部署VCSA(Invoke-Expression将字符串解析为命令并执行) Invoke-Expression "$($VCSAInstallerPath)\vcsa-cli-installer\win32\vcsa-deploy.exe install --no-esx-ssl-verify --accept-eula --acknowledge-ceip $($ENV:Temp)\jsontemplate.json" } if($setupNewVC -eq 1) { # 连接vCenter try{ $vc = Connect-VIServer $VCSAIPAddress -User "administrator@$VCSASSODomainName" -Password $VCSASSOPassword -WarningAction SilentlyContinue logRecord -logLevel INFO -logString "连接 vCenter Server $VCSAIPAddress 成功" }catch{ logRecord -logLevel ERROR -logString "连接 vCenter Server $VCSAIPAddress 失败" return ; } # 创建数据中心 $d = Get-Datacenter -Server $vc $NewVCDatacenterName -ErrorAction Ignore if( -Not $d) { logRecord -logLevel INFO -logString "创建数据中心 $NewVCDatacenterName" New-Datacenter -Server $vc -Name $NewVCDatacenterName -Location (Get-Folder -Type Datacenter -Server $vc) | out-null } # 创建集群 $c = Get-Cluster -Server $vc $NewVCVSANClusterName -ErrorAction Ignore if( -Not $c) { if($configureVSANDiskGroup -eq 1) { logRecord -logLevel INFO -logString "创建vSAN集群 $NewVCVSANClusterName" New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled -HAEnabled -VsanEnabled | out-null } else { logRecord -logLevel INFO -logString "创建vSphere集群 $NewVCVSANClusterName" New-Cluster -Server $vc -Name $NewVCVSANClusterName -Location (Get-Datacenter -Name $NewVCDatacenterName -Server $vc) -DrsEnabled -HAEnabled | out-null } (Get-Cluster $NewVCVSANClusterName) | New-AdvancedSetting -Name "das.ignoreRedundantNetWarning" -Type ClusterHA -Value $true -Confirm:$false | out-null } # 添加主机到vCenter if($addESXiHostsToVC -eq 1) { foreach($nestedESXiHostKey in $nestedESXiHostnameToIPs.keys) { $VMName = $nestedESXiHostKey $VMIPAddress = $nestedESXiHostnameToIPs[$nestedESXiHostKey] $targetVMHost = $VMIPAddress if($addHostByDnsName -eq 1) { $targetVMHost = $VMName } logRecord -logLevel INFO -logString "添加ESXi主机 $targetVMHost 到集群" Add-VMHost -Server $vc -Location (Get-Cluster -Name $NewVCVSANClusterName) -User "root" -Password $VMPassword -Name $targetVMHost -Force | out-null } } # 创建磁盘组 if($configureVSANDiskGroup -eq 1) { Get-VsanClusterConfiguration -Server $vc -Cluster $NewVCVSANClusterName | Set-VsanClusterConfiguration -HealthCheckIntervalMinutes 0 | out-null foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { $luns = $vmhost | Get-ScsiLun | select CanonicalName, CapacityGB logRecord -logLevel INFO -logString "主机 $vmhost 查询可用于创建磁盘组的磁盘" foreach ($lun in $luns) { if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCachingvDisk") { $vsanCacheDisk = $lun.CanonicalName } if(([int]($lun.CapacityGB)).toString() -eq "$NestedESXiCapacityvDisk") { $vsanCapacityDisk = $lun.CanonicalName } } logRecord -logLevel INFO -logString "主机 $vmhost 创建磁盘组" New-VsanDiskGroup -Server $vc -VMHost $vmhost -SsdCanonicalName $vsanCacheDisk -DataDiskCanonicalName $vsanCapacityDisk | out-null } } # 清除vSAN告警 if($clearVSANHealthCheckAlarm -eq 1) { logRecord -logLevel INFO -logString "清除vSAN集群健康检测告警" $alarmMgr = Get-View AlarmManager -Server $vc Get-Cluster -Server $vc | where {$_.ExtensionData.TriggeredAlarmState} | %{ $cluster = $_ $Cluster.ExtensionData.TriggeredAlarmState | %{ $alarmMgr.AcknowledgeAlarm($_.Alarm,$cluster.ExtensionData.MoRef) } } $alarmSpec = New-Object VMware.Vim.AlarmFilterSpec $alarmMgr.ClearTriggeredAlarms($alarmSpec) Set-VsanClusterConfiguration -Configuration $NewVCVSANClusterName -AddSilentHealthCheck controlleronhcl,vumconfig,vumrecommendation -PerformanceServiceEnabled $true } # 最终配置 foreach ($vmhost in Get-Cluster -Server $vc | Get-VMHost) { # 清除告警: 未配置任何 coredump 目标。无法保存主机核心转储 Get-AdvancedSetting -Entity $vmhost -Name UserVars.SuppressCoredumpWarning | Set-AdvancedSetting -Value 1 -Confirm:$false | out-null # 开启vMotion $vmhost | Get-VMHostNetworkAdapter -VMKernel | Set-VMHostNetworkAdapter -VMotionEnabled $true -Confirm:$false | out-null # 如果主机在维护模式,则退出维护模式 if($vmhost.ConnectionState -eq "Maintenance") { Set-VMHost -VMhost $vmhost -State Connected -RunAsync -Confirm:$false | out-null } } logRecord -logLevel INFO -logString "断开vCenter连接" Disconnect-VIServer $vc -Confirm:$false } }
1 如下图,是通过执行脚本后,在现有ESXI主机环境下,自动嵌套部署3台ESXI主机
2 如下是自动化部署第二层vCenter管理控制台界面,如图可见VSAN已按脚本要求配置完成,