For the purpose of todays post we will be using the free load balancer that Kemp offers for evaluating products and functionalities. Today we are going to ensure our web application is highly available and behind two LoadMasters in a high availability configuration so that we can easily manage all the server nodes if required, spread the total number of connections across all of them, monitor traffic etc. We will achieve this by automating the entire process of deployment, licensing, and configuration, using PowerShell.
A little note on HA configuration (from website)
The High Availability (HA) feature of the LoadMaster guarantees the availability of your server farm. HA is achieved by a hot-standby, failover mechanism. Two identical LoadMaster units are integrated into the network as a cluster. One machine serves as the active LoadMaster and the second one remains in a standby, idle state – always prepared to take over the activities from the active server. This cluster appears as a single logical unit to the internet side and to the server farm side connections.
With a HA cluster, each network interface has an individual IP address and one shared IP address which is shared with the partner unit. The shared IP address is identical for both LoadMaster appliances, though it is associated with only the active LoadMaster at any given time.
The goal of redundant LoadMasters is to provide reliable traffic management, even if one LoadMaster becomes unavailable. The advantages of HA are as follows:
Disclaimer: the code and techniques explained below are free to use and distribute, however they came without any particular error handling in place. The reason of this is to prevent any additional complexity in the logic that we are going to implement and go straight to the point. All the validation and error handling can be implemented at second stage once the main flow and concepts are understood.
The image below shows the starting environment we are going to use for being converted in what we can see in the second image.
Let’s start with downloading all the necessary tools and librariesDownload Central and the LoadMaster VLM Deployment files
1 – Create a free kemp account if needed and download Kemp360Central for VMware and the LoadMaster VLM from here Extract all the content in a folder that will be used for testing i.e. C:\PowershellAutomationTest\VLM_Images. Please Note the zip file that will be downloaded for Central will contain both Central and the LoadMaster deployment files. Keep that LoadMaster deployment file aside for now since will not be used in these examples.
2 – Download the Kemp LoadMaster Powershell API wrapper from here
extract the content into a folder that can be easily accessible i.e. C:\PowershellAutomationTest\PowerShellWrapper
3 – Download the Kemp 360 Central Powershell API wrapper from here
4 – Download and install VMware PowerCLI Once we have everything setup and configured on the local machine let’s open Microsoft Powershell ISE. From the console navigate to the folder where we extracted all the materials i.e. C:\PowershellAutomationTest\
At this stage we should have in this folder
The script I’m going to show you will follow these steps (approach 1)
Change the values of the variables based on your needs and run the script
# # $Id: HA LM Deployment in vSphere afabiano $ # ### ### Importing Modules ### Import-Module ".\Powershell-7.2.49.1.1562\Kemp.LoadBalancer.Powershell.psm1" Import-Module ".\Kemp.K360Central.Powershell\Kemp.K360Central.Powershell.psm1" ### ### Declaring Params Needed for logging in the LM ### bal is the default super user ### kempPassword must be decided by yuou ### $KempAdmin = "bal" $KempPassword = "YOUR_PASSWORD" $LoadMasterPort = "443" # LoadMaster HA1 Params $LMHA1_Name = "PWS_DeviceHA1" # LoadMaster HA2 Params $LMHA2_Name = "PWS_DeviceHA2" # Shared IP Params $LMHA_TAG = "133" $LMHA_SIP = "10.35.44.$($LMHA_TAG)" # vSphere Params $HypervisorIp = "10.35.0.16" $HypervisorUser = " YOUR_VMWARE_USER " $HypervisorPassword = "YOUR_VMWARE_PASSWORD" $HypervisorResourcePool = "YOUR_RESOURCE_POOL" # LoadMaster OVF Image Path $VLMImagePath = "C:\Users\afabiano\Documents\PS\VLM_IMAGES\LoadMaster-VLM-7.2.49.1.18450.RELEASE-VMware-VBox-OVF.ovf" # Kemp Account Credentials $KempIDACcount = 'YOUR_KEMP_ID' $KempIDPassword = 'YOUR_PASSWORD' # Connecting to the Hypervisor $HypervisorConnectionParams = @{ 'Server' = $hypervisorIp 'User' = $hypervisorUser 'Password' = $hypervisorPassword } $hypervisorConnection = Connect-VIServer -Server $hypervisorIp -User $hypervisorUser -Password $hypervisorPassword $VMHost = Get-VMHost $HypervisorResourcePool = Get-ResourcePool -Name $HypervisorResourcePool $params = @{ 'ImagePath' = $VLMImagePath 'VLMName' = "" 'VMhost' = $VMHost 'VMport' = $LoadMasterPort 'ResourcePool' = $HypervisorResourcePool 'KempIDAccount' = $KempIDACcount 'KempIDPassword' = $KempIDPassword 'KempAdminPassword' = $KempPassword } ### ### Deploy Machine 1 ### $params['VLMName'] = $LMHA1_Name Deploy-Machine @params ### ### Deploy Machine 2 ### $params['VLMName'] = $LMHA2_Name Deploy-Machine @params Start-Sleep 10 ### ### Get the VM Details ### $LoadMasterHa1 = Get-VM -Name $LMHA1_Name $LoadMasterHa2 = Get-VM -Name $LMHA2_Name $LoadMasterHaFirstIP = $LoadMasterHa1.Guest.IPAddress[0] $LoadMasterHaSecondIP = $LoadMasterHa2.Guest.IPAddress[0] ### ### Configure HA1 ### $HA1Params = @{ 'KempAdmin' = $KempAdmin 'KempAdminPassword' = $KempPassword 'VMIP' = $LoadMasterHaFirstIP 'VMport' = $LoadMasterPort 'HAMode' = 'HA First' 'SharedIP' = $LMHA_SIP 'PartnerIP' = $LoadMasterHaSecondIP } Configure-HA @HA1Params ### ### Configure HA2 ### $HA2Params = @{ 'KempAdmin' = $KempAdmin 'KempAdminPassword' = $KempPassword 'VMIP' = $LoadMasterHaSecondIP 'VMport' = $LoadMasterPort 'HAMode' = 'HA Second' 'SharedIP' = $LMHA_SIP 'PartnerIP' = $LoadMasterHaFirstIP } Configure-HA @HA2Params ### ### Restarting the machines for getting the Configuration working ### Write-Output "Restarting Machines" Restart-VMGuest -VM $LoadMasterHa1 Restart-VMGuest -VM $LoadMasterHa2 Start-Sleep 40 Write-Output "Machines ready" ### ### Deploy-Machine function ### Function Deploy-Machine() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$ImagePath, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VLMName, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMhost, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMport, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$ResourcePool, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempIDAccount, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempIDPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdminPassword ) Write-Output "Deploying Machine [$VLMName]" Import-VApp -Source $ImagePath -Name $VLMName -VMHost $VMhost Write-Output "Moving the device to Destination resource [$($ResourcePool)]" Move-VM -VM $VLMName -Destination $ResourcePool Start-VM -VM $VLMName ### ### At this stage the machine is starting we have to wait approx 20 secs ### $VMDetails = Get-VM -Name $VLMName while (!$VMDetails.Guest.IPAddress) { Write-Output "-" Start-Sleep -s 5 $VMDetails = Get-VM -Name $VLMName } $VMIPDetials = $VMDetails.Guest.IPAddress $VMIP = $VMIPDetials[0] ### ### Accepting the EULA ### Write-Output "Accepting the EULA" $LMResponse = Read-LicenseEULA -LoadBalancer $VMIP -LBPort $VMport $MagicString = $LMResponse.Data.Eula.MagicString $LMResponse = Confirm-LicenseEULA -LoadBalancer $VMIP -LBPort $VMport -Magic $MagicString $MagicString = $LMResponse.Data.Eula2.MagicString ### ### Licensing the device Against the Kemp web services ### Write-Output "Licensing" $LMResponse = Request-LicenseOnline -LoadBalancer $VMIP -LBPort $VMport -KempId $KempIDAccount -Password $KempIDPassword ### ### Accepting the Kemp analytics reports (or we will never be able to improve our amazing products:) ) ### Write-Output "Analytics" $LMResponse = Confirm-LicenseEULA2 -LoadBalancer $VMIP -LBPort $VMport -Magic $MagicString -Accept yes ### ### Set the initial password ### Write-Output "Initial password" $LMResponse = Set-LicenseInitialPassword -LoadBalancer $VMIP -LBPort $VMport -Passwd $KempAdminPassword } Function Configure-HA() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdminPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMport, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$HAMode, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$SharedIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$PartnerIP ) $SecureString = ConvertTo-SecureString -String $KempAdminPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Write-Output "Connecting to the device [$LMIP]:$LMPort" Write-Output "------------------------------" Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMport -Credential $LMCredentials Write-Output "Setting HA Mode [$HAMode]" Write-Output "------------------------------" Set-LmHAMode -HaMode $HAMode Set-NetworkInterface -InterfaceID 0 -Shared $SharedIP # Waith 15 secs Write-Output "Wait after setting the Shared ip on [$LMIP] -> $($SharedIP)" Write-Output "------------------------------" Start-Sleep -s 15 # Configuring the Partner IP Write-Output "Setting the Partner IP on [$LMIP] -> $PartnerIP" Write-Output "------------------------------" Set-NetworkInterface -InterfaceID 0 -Partner $PartnerIP Write-Output "configured the partner on device 2" + $PartnerIP Write-Output "------------------------------" #Write-Output "=========================================================" Start-Sleep -s 10 #Set-LMHAConfiguration -havhid $HAID Write-Output "Device Configured" }
At the end of the execution of this script we should have the two LoadMaster configured in HA. As we can see from the image below the top one is the Active Master, the middle one is the Standby unit and the last one is the Shared IP UI.
What is left is at this stage is the web application connection part that will have these steps:
Upload a template can be executed by this command
Install-Template -Path file_path Credentials
In our script we will have this piece of code that is dealing with that, and personally, I prefer to use a function so that can be reused later. Instead of calling this function against the SharedIP device, we can leverage the LoadMaster HA functionality and apply a small change to our flow. What we can do is to split the flow in 2, where the first part will configure the first device with all we need (Template for the web application, create the VirtualServices and add one or more Real Servers). The second step is to create the second machine and start the HA configuration so that the entire VS configuration will be replicated as soon the two machines are in sync.
The new flow will then be as follow:
For doing that we had to slightly change the previous script that now will looks like this
# # $Id: HA LM Deployment in vSphere afabiano $ # ### ### Importing Modules ### Import-Module ".\Powershell-7.2.49.1.1562\Kemp.LoadBalancer.Powershell.psm1" Import-Module ".\Kemp.K360Central.Powershell\Kemp.K360Central.Powershell.psm1" ### ### Declaring Params Needed ### $KempAdmin = "bal" $KempPassword = " YOUR_PASSWORD " $LoadMasterPort = "443" # LoadMaster HA1 Params $LMHA1_Name = "PWS_DeviceHA1" # LoadMaster HA2 Params $LMHA2_Name = "PWS_DeviceHA2" # Shared IP Params $LMHA_TAG = "133" $LMHA_SIP = "10.35.34.$($LMHA_TAG)" # vSphere Params $HypervisorIp = "YOUR_HYPERVISOR_IP" $HypervisorUser = " YOUR_HYPERVISOR_USER" $HypervisorPassword = "YOUR_HYPERVISOR_USER_PASSWORD" $HypervisorResourcePool = "YOUR_RESOURCE_POOL" $NetworkPool = "YOUR_NETWORK_POOL" # LoadMaster OVF Image Path $VLMImagePath = "OVF IMAGE LOCATION\filename.ovf" # Template Path $TemplatePath = "TEMPLATE_PATH\apache-http.tmpl" # Kemp Account Credentials $KempIDACcount = 'KEMPID' $KempIDPassword = 'KEMPID_PASSWORD' # VS Parameter ## to be changed based on your needs $VSIP = '10.35.34.12' $VSPort = '443' $VSProtocol = 'tcp' $TemplateName = 'Apache HTTPS Offloaded' # RS Parameter ## to be changed based on your needs $RS1IP = '10.35.34.11' $RS1Port = '80' $RS2IP = '10.35.34.13' $RS2Port = '80' ### ### Deploy-Machine function ### Function Deploy-Machine() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$ImagePath, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VLMName, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMhost, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMport, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$ResourcePool, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempIDAccount, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempIDPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdminPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$NetworkPool ) Write-Output "Deploying Machine [$VLMName]" Import-VApp -Source $ImagePath -Name $VLMName -VMHost $VMhost Write-Output "Moving the device to Destination resource [$($ResourcePool)]" Move-VM -VM $VLMName -Destination $ResourcePool ### ### Change the network ### Get-vm $VLMName | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $NetworkPool -Confirm:$false Start-VM -VM $VLMName ### ### At this stage the machine is starting we have to wait approx 20 secs ### $VMDetails = Get-VM -Name $VLMName while (!$VMDetails.Guest.IPAddress) { Write-Output "-" Start-Sleep -s 5 $VMDetails = Get-VM -Name $VLMName } $VMIPDetials = $VMDetails.Guest.IPAddress $VMIP = $VMIPDetials[0] ### ### Accepting the EULA ### Write-Output "Accepting the EULA" $LMResponse = Read-LicenseEULA -LoadBalancer $VMIP -LBPort $VMport $MagicString = $LMResponse.Data.Eula.MagicString $LMResponse = Confirm-LicenseEULA -LoadBalancer $VMIP -LBPort $VMport -Magic $MagicString $MagicString = $LMResponse.Data.Eula2.MagicString ### ### Licensing the device Against the Kemp web services ### Write-Output "Licensing" $LMResponse = Request-LicenseOnline -LoadBalancer $VMIP -LBPort $VMport -KempId $KempIDAccount -Password $KempIDPassword ### ### Accepting the Kemp analytics reports (or we will never be able to improve our amazing products:) ) ### Write-Output "Analytics" $LMResponse = Confirm-LicenseEULA2 -LoadBalancer $VMIP -LBPort $VMport -Magic $MagicString -Accept yes ### ### Set the initial password ### Write-Output "Initial password" $LMResponse = Set-LicenseInitialPassword -LoadBalancer $VMIP -LBPort $VMport -Passwd $KempAdminPassword } Function Configure-HA() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdminPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMport, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$HAMode, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$SharedIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$PartnerIP ) $SecureString = ConvertTo-SecureString -String $KempAdminPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Write-Output "Connecting to the device [$LMIP]:$LMPort" Write-Output "------------------------------" Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMport -Credential $LMCredentials Write-Output "Setting HA Mode [$HAMode]" Write-Output "------------------------------" Set-LmHAMode -HaMode $HAMode Set-NetworkInterface -InterfaceID 0 -Shared $SharedIP # Waith 15 secs Write-Output "Wait after setting the Shared ip on [$LMIP] -> $($SharedIP)" Write-Output "------------------------------" Start-Sleep -s 15 # Configuring the Partner IP Write-Output "Setting the Partner IP on [$LMIP] -> $PartnerIP" Write-Output "------------------------------" Set-NetworkInterface -InterfaceID 0 -Partner $PartnerIP Write-Output "configured the partner on device 2" + $PartnerIP Write-Output "------------------------------" #Write-Output "=========================================================" Start-Sleep -s 10 #Set-LMHAConfiguration -havhid $HAID Write-Output "Device Configured" } Function Upload-Template-To-LM() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$TemplateLocation, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMport, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdminPassword ) $SecureString = ConvertTo-SecureString -String $KempAdminPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMport -Credential $LMCredentials Install-Template -Path $TemplateLocation } Function Create-VS() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSProtocol, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$TemplateName ) $SecureString = ConvertTo-SecureString -String $KempPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMPort -Credential $LMCredentials ### ### Add VS ### New-AdcVirtualService -VirtualService $VSIP -VSPort $VSPort -VSProtocol $VSProtocol -Template $TemplateName } Function Create-RS() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSProtocol, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$RSIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$RSPort ) $SecureString = ConvertTo-SecureString -String $KempPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMPort -Credential $LMCredentials ### ### Add the RealServers ### New-AdcRealServer -VirtualService $VSIP -VSPort $VSPort -VSProtocol $VSProtocol -RealServer $RSIP -RealServerPort $RSPort -Non_Local $true } # Connecting to the Hypervisor $HypervisorConnectionParams = @{ 'Server' = $hypervisorIp 'User' = $hypervisorUser 'Password' = $hypervisorPassword } $hypervisorConnection = Connect-VIServer -Server $hypervisorIp -User $hypervisorUser -Password $hypervisorPassword $VMHost = Get-VMHost $HypervisorResourcePool = Get-ResourcePool -Name $HypervisorResourcePool ### ### Deploy Machine 1 ### $params = @{ 'ImagePath' = $VLMImagePath 'VLMName' = "" 'VMhost' = $VMHost 'VMport' = $LoadMasterPort 'ResourcePool' = $HypervisorResourcePool 'KempIDAccount' = $KempIDACcount 'KempIDPassword' = $KempIDPassword 'KempAdminPassword' = $KempPassword 'NetworkPool' = $NetworkPool } $params['VLMName'] = $LMHA1_Name Deploy-Machine @params ### ### Get the VM Details ### $LoadMasterHa1 = Get-VM -Name $LMHA1_Name ### create a snapshot New-Snapshot -VM $LoadMasterHa1 -Name "TestSnapshotForHA1" -Description "Automated Snapshot" -Quiesce -Memory $LoadMasterHaFirstIP = $LoadMasterHa1.Guest.IPAddress[0] ### ### Configure ### $TemplateParams = @{ 'TemplateLocation' = $TemplatePath 'VMIP' = $LoadMasterHaFirstIP 'VMport' = $LoadMasterPort 'KempAdmin' = $KempAdmin 'KempAdminPassword' = $KempPassword } Upload-Template-To-LM @TemplateParams ### ### Add the VS and the RealServers ### $VSPArams = @{ 'VMIP' = $LoadMasterHaFirstIP 'VMPort' = $VMport 'KempAdmin' = $KempAdmin 'KempPassword' = $KempPassword 'VSIP' = $VSIP 'VSPort' = $VSPort 'VSProtocol' = $VSProtocol 'TemplateName' = $TemplateName } Create-VS @VSPArams ### ### Add the RS to the Virtual Service created ### $RSPArams = @{ 'VMIP' = $LoadMasterHaFirstIP 'VMPort' = $VMport 'KempAdmin' = $KempAdmin 'KempPassword' = $KempPassword 'VSIP' = $VSIP 'VSPort' = $VSPort 'VSProtocol' = $VSProtocol 'RSIP' = $RS1IP 'RSPort' = $RS1Port } Create-RS @RSParams ### Add second Real Server $RSPArams = @{ 'VMIP' = $LoadMasterHaFirstIP 'VMPort' = $VMport 'KempAdmin' = $KempAdmin 'KempPassword' = $KempPassword 'VSIP' = $VSIP 'VSPort' = $VSPort 'VSProtocol' = $VSProtocol 'RSIP' = $RS2IP 'RSPort' = $RS2Port } Create-RS @RSParams ### ### Deploy Machine 2 ### $params['VLMName'] = $LMHA2_Name Deploy-Machine @params Start-Sleep 10 ### ### Get the VM Details ### $LoadMasterHa2 = Get-VM -Name $LMHA2_Name ### create a snapshot New-Snapshot -VM $LoadMasterHa2 -Name "TestSnapshotForHA2" -Description "Automated Snapshot" -Quiesce -Memory $LoadMasterHaSecondIP = $LoadMasterHa2.Guest.IPAddress[0] ### ### Configure HA1 ### $HA1Params = @{ 'KempAdmin' = $KempAdmin 'KempAdminPassword' = $KempPassword 'VMIP' = $LoadMasterHaFirstIP 'VMport' = $LoadMasterPort 'HAMode' = 'HA First' 'SharedIP' = $LMHA_SIP 'PartnerIP' = $LoadMasterHaSecondIP } Configure-HA @HA1Params ### ### Configure HA2 ### $HA2Params = @{ 'KempAdmin' = $KempAdmin 'KempAdminPassword' = $KempPassword 'VMIP' = $LoadMasterHaSecondIP 'VMport' = $LoadMasterPort 'HAMode' = 'HA Second' 'SharedIP' = $LMHA_SIP 'PartnerIP' = $LoadMasterHaFirstIP } Configure-HA @HA2Params ### ### Restarting the machines for getting the Configuration working ### Write-Output "Restarting Machines" Restart-VMGuest -VM $LoadMasterHa1 Restart-VMGuest -VM $LoadMasterHa2 Start-Sleep 40 Write-Output "Machines ready"
At the end of this script execution we will have this
If we try to reach the VS IP 10.35.34.12 we will see our web app
For testing, you can do this manually just to verify that everything is working as expected, but you can also use Apache bench to verify and check how the system behaves under stress. Let’s give it a quick run
I executed Apache Bench with these parameters
-n 10000 -c 500 while executing the RS page looked like this
Virtual Service Stats
As you can see from above, in the image 8 all the connections were spread over the 2 RSs
At this stage we have our application up and running in an HA environment in VMware using PowerShell for automating the entire deployment.
Now that we understand what is really involved in such a deployment there is yet another method for doing this deployment that actually, will consists in less steps and will allow us to get more control in some cases prior to the machine deployment i.e. assign in advance IP address so that will not conflict, assign Gateway etc.
This method is using the Kemp360 Central functionality for autolicense and deploy machines in VMware, KVM, XEN. Assuming that your Central is up and running and was activated with the MELA Trial license, the steps we are going to follow will be a little different. What we want to achieve is to have the same configuration of our previous example but this time using Kemp360 Central, that will consist in less steps and less complexity because Central will take care of the VLM image import , instantiation and activation, this means that all that “complexity” is removed from our scripts because Central will do that for us. Therefore, the steps will be:
The feature we are going to leverage is the LoadMaster Deployment and if you want, you can go through the steps using the UI first that will drive you through the process of creating one or more devices and decide how to deploy (manual approach – download and instantiate, automatic – Central will do everything for us), this will help you in getting familiar with what is happening. There is only one prerequisite that must be met for this flow and is that we should login to Central and create at least one target environment. For doing that, login to Central, navigate to the Target Environments section (see image 10 below), click on the Create new and start filling the required parameters (see image 11). The save button will became available only if the check of the credentials has been successfully accomplished. Once we have the target environment correctly created we can move back to PowerShell.
Our Powershell script will initially consist in three functions
For being able to do that we will need to know some details prior to the deployment that are:
Kemp360 Central will map to the correct VMWare IDs and schedule the VMs for deployment with the right parameters.
The script below is a quick test to verify that everything is working as expected with a single machine. The initial import section and variable declaration is the same of our previous examples, below you will find only the call to the function that are responsible for creating the profile and deploy. Please note that creation of profile and deployment are two separate steps so that you can, for example, create first 10 profiles and then decide to deploy with calm at later stage.
### ### Connect and authenticate against central ### Initialize-K360Central -Address $CentralIP -User $CentralAdmin -Password $CentralPassword -Port 443 ### ### Create a LoadMaster deployment instance in Central ### assigning in advance network parameters ### $LMDeploymentParams = @{ 'HAMode' = "SA" 'DeploymentName' = "TestDeploymentFromPWS6" 'DeploymentDescription' = "Test" 'Gateway' = "10.35.34.1" 'Eth0Device1IP' = "10.35.34.120/24" 'WUIPort' = "443" 'Nameserver' = "" } $obj = Create-LoadMaster-Deployment @LMDeploymentParams $DeviceProfileID = $obj.Data.id ### ### Deploy the profile created ### $params = @{ 'TargetEnvironmentName' = 'vCenterPWS' 'ResourcePool'='afabiano' 'NetworkName'='Antonio_34' 'DataStore'='THEALLSPARK' 'AutoPowerOn'='no' 'DeviceProfileId' = $DeviceProfileID } $InstanceID = LMInstance-Prepare @params LMInstance-Deploy -InstanceID $InstanceID -Verbose
After few minutes the machine will be in your environment, turned on/off depending on your preferences and automatically connected to Central as the image below
Now is time to make things spicier, let’s automate our previous LoadMaster HA configuration with the template instantiation, connect to Central, and start monitoring the traffic spikes. Our script will be as simple as:
At the end of the execution of this script (in a matter of minutes) we will have our entire environment up and running and fault tolerant. All I had to do is to merge our two scripts and apply some minor adjustments. In particular I had to add a function that is looking for the Virtual Machines to be up a running with the IP accessible. This is because the deployment of the virtual device from Central happen in an asynchronous way to avoid having the user locked on the deployment page for few minutes. The other small adjustment is related to the virtual device names. When we deploy HA pairs with Central in any hypervisor, it will automatically attach the “-1” and “-2” labels at the end of the device name, so that can be distinguished in the hypervisor. For example, if I decide to call my deployment as “superTest” and is an HA configuration, Central will create in the hypervisor superTest-1 and superTest-2. I had to take this in consideration for the function that is waiting the machines to be deployed and ready. This is then the end result (I’m leaving the IP of the interfaces and Devices, everything else should be replaced with your configuration):
# # $Id: HA LM Deployment in vSphere afabiano $ # ### ### Importing Modules ### Import-Module ".\Powershell-7.2.49.1.1562\Kemp.LoadBalancer.Powershell.psm1" Import-Module ".\Kemp.K360Central.Powershell\Kemp.K360Central.Powershell.psm1" -Force ### ### Declaring Params Needed ### $KempAdmin = "bal" $KempPassword = "Admin1234" ### ### Central Parameters ### $CentralAdmin = "admin" $CentralPassword = "YOUR_CENTRAL_PASSWORD" $CentralIP = " YOUR_CENTRAL_IP" $TargetEnvironmentName = "TARGET_ENVIRONMENT_NAME" $LoadMasterPort = "LOADMASTER_UI_PORT" $DeploymentName = "DEPLOYMENT_NAME" $DefaultGateway = "YOUR_DEFAULT_GATEWAY" $LicenseName = "VLM-MAX" # LoadMaster HA1 Params in the format ip/cidr $Eth0Device1IP = "10.35.34.111/24" # LoadMaster HA2 Params in the format ip/cidr $Eth0Device2IP = "10.35.34.112/24" # Shared IP Params $LMHA_TAG = "143" $LMHA_SIP = "10.35.34.$($LMHA_TAG)" # vSphere Params $HypervisorIp = "YOUR_HYPERVISOR_IP" $HypervisorUser = " YOUR_HYPERVISOR_USER" $HypervisorPassword = "YOUR_PASSWORD" $HypervisorResourcePool = "YOUR_RESOURCE_POOL" $NetworkPool = "YOUR_NETWORK_POOL" $DataStore = "YOUR_DATASTORE" $AutoPowerOn = 'yes' # Template Path $TemplatePath = "ABSOLUTE_PATH\TO\THE\TEMPLATE\apache-http.tmpl" # VS Parameter $VSIP = '10.35.34.12' $VSPort = '443' $VSProtocol = 'tcp' $TemplateName = 'Apache HTTPS Offloaded' # RS Parameter $RS1IP = '10.35.34.11' $RS1Port = '80' $RS2IP = '10.35.34.13' $RS2Port = '80' Function Upload-Template-To-LM() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$TemplateLocation, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMport, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdminPassword ) $SecureString = ConvertTo-SecureString -String $KempAdminPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMport -Credential $LMCredentials Install-Template -Path $TemplateLocation } Function Create-VS() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSProtocol, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$TemplateName ) $SecureString = ConvertTo-SecureString -String $KempPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMPort -Credential $LMCredentials ### ### Add VS ### New-AdcVirtualService -VirtualService $VSIP -VSPort $VSPort -VSProtocol $VSProtocol -Template $TemplateName } Function Create-RS() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VMPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempAdmin, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$KempPassword, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSPort, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VSProtocol, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$RSIP, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$RSPort ) $SecureString = ConvertTo-SecureString -String $KempPassword -AsPlainText -Force $LMCredentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $KempAdmin, $SecureString Initialize-LmConnectionParameters -Address $VMIP -LBPort $VMPort -Credential $LMCredentials ### ### Add the RealServers ### New-AdcRealServer -VirtualService $VSIP -VSPort $VSPort -VSProtocol $VSProtocol -RealServer $RSIP -RealServerPort $RSPort -Non_Local $true } Function Wait-Machines() { Param( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VLMName1, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$VLMName2, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$hypervisorIp, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$hypervisorUser, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [string]$hypervisorPassword ) $hypervisorConnection = Connect-VIServer -Server $hypervisorIp -User $hypervisorUser -Password $hypervisorPassword $VMHost = Get-VMHost ### ### At this stage the machine is starting we have to wait approx 20 secs ### Write-Output $VLMName1 $VMDetails1 = Get-VM -Name $VLMName1 $VMDetails2 = Get-VM -Name $VLMName2 while (!$VMDetails1.Guest.IPAddress -and !$VMDetails2.Guest.IPAddress) { Write-Output "-" Write-Output "waiting machine $($VLMName1)" Start-Sleep -s 10 $VMDetails1 = Get-VM -Name $VLMName1 $VMDetails2 = Get-VM -Name $VLMName2 if ($VMDetails1.PowerState -ne "PoweredOn") { $v1 = Start-VM $VLMName1 } if ($VMDetails2.PowerState -ne "PoweredOn") { $v2 = Start-VM $VLMName2 } } Start-Sleep -s 5 } ### ### Connect and authenticate against Central ### Initialize-K360Central -Address $CentralIP -User $CentralAdmin -Password $CentralPassword -Port 443 ### ### Create a LoadMaster deployment instance in Central ### assigning in advance network parameters ### $LMDeploymentParams = @{ 'HAMode' = "HA" 'DeploymentName' = $DeploymentName 'DeploymentDescription' = "HA Test" 'Gateway' = $DefaultGateway 'Eth0Device1IP' = $Eth0Device1IP 'Eth0Device2IP' = $Eth0Device2IP 'SharedIP1' = $LMHA_SIP 'WUIPort' = $LoadMasterPort 'Nameserver' = "" 'LicenseName' = $LicenseName } $obj = Create-LoadMaster-Deployment @LMDeploymentParams $DeviceProfileID = $obj.Data.id ### ### Prepare the Deployment ### $params = @{ 'TargetEnvironmentName' = $TargetEnvironmentName 'ResourcePool' = $HypervisorResourcePool 'NetworkName' = $NetworkPool 'DataStore' = $DataStore 'AutoPowerOn' = $AutoPowerOn 'DeviceProfileId' = $DeviceProfileID } $InstanceID = LMInstance-Prepare @params ### ### Deploy the machine ### And wait 2 mins for the images to be uploaded ### LMInstance-Deploy -InstanceID $InstanceID Start-Sleep -s 240 ### ### Prepare the Deployment ### $params = @{ 'VLMName1' = "$($DeploymentName)-1" 'VLMName2' = "$($DeploymentName)-2" 'hypervisorIp' = $HypervisorIp 'hypervisorUser' = $HypervisorUser 'hypervisorPassword' = $HypervisorPassword } Wait-Machines @params ### ### Configure ### $TemplateParams = @{ 'TemplateLocation' = $TemplatePath 'VMIP' = $LMHA_SIP 'VMport' = $LoadMasterPort 'KempAdmin' = $KempAdmin 'KempAdminPassword' = $KempPassword } Upload-Template-To-LM @TemplateParams ### ### Add the VS and the RealServers ### $VSPArams = @{ 'VMIP' = $LMHA_SIP 'VMPort' = $LoadMasterPort 'KempAdmin' = $KempAdmin 'KempPassword' = $KempPassword 'VSIP' = $VSIP 'VSPort' = $VSPort 'VSProtocol' = $VSProtocol 'TemplateName' = $TemplateName } Create-VS @VSPArams ### ### Add the RS to the Virtual Service created ### $RSPArams = @{ 'VMIP' = $LMHA_SIP 'VMPort' = $LoadMasterPort 'KempAdmin' = $KempAdmin 'KempPassword' = $KempPassword 'VSIP' = $VSIP 'VSPort' = $VSPort 'VSProtocol' = $VSProtocol 'RSIP' = $RS1IP 'RSPort' = $RS1Port } Create-RS @RSParams ### Add second Real Server $RSPArams = @{ 'VMIP' = $LMHA_SIP 'VMPort' = $LoadMasterPort 'KempAdmin' = $KempAdmin 'KempPassword' = $KempPassword 'VSIP' = $VSIP 'VSPort' = $VSPort 'VSProtocol' = $VSProtocol 'RSIP' = $RS2IP 'RSPort' = $RS2Port } Create-RS @RSParams
Below instead is the LoadMaster UI after accessing the Shared IP (10.35.34.143)
Now is time to re-run the Apache bench but with the value a bit increased since we need some sort of steady traffic. Below is how the Kemp360 Central Dashboard looked like during the test execution
I hope you enjoyed this article!