Fügen Sie automatisch virtuellen Serverplatz hinzu

Hallo allerseits!


In diesem Artikel werden wir darüber sprechen, wie wir die Aufgabe der Erweiterung des Speicherplatzes auf einem unserer Server automatisiert haben. Und was ist bei einer so einfachen Aufgabe so schwierig, dass ich sie automatisieren musste - fragen Sie? Nichts, wenn Sie keine kaskadierten, zusammengeführten Mounts verwenden. Ich habe das Gefühl, es gibt noch mehr Fragen !? Na dann, lass uns unter die Katze gehen.

Zunächst möchte ich Ihnen erklären, warum wir eine kaskadenintegrierte Montage verwenden.

Wir haben ein System, das Speicher für kleine Dateien (Dokumentenscans usw.) benötigt. Die durchschnittliche Dateigröße liegt zwischen 200 KB und 1 Megabyte, die Daten sind statisch und ändern sich nicht. Es sind Milliarden von Dateien darin und die Anzahl wächst von Tag zu Tag. Einmal, als das Volumen bereits mehr als 6 TB betrug, wurde uns klar, dass bald Probleme auftreten würden. Eines davon war die Zeit der Sicherung und Wiederherstellung. Dann beschlossen wir, die Daten in Festplatten aufzuteilen, und UnionFS wurde gerufen, um uns dabei zu helfen.

Der Algorithmus wurde wie folgt bestimmt: Die Daten werden nicht mehr als 2 TB auf die Festplatte geschrieben. Am Ende fügen wir der virtuellen Maschine eine neue Festplatte hinzu, markieren sie, fügen sie UnionFS hinzu, übertragen die alte auf ReadOnly, entfernen eine Kopie von ihr, schreiben auf Band und entfernen sie aus der Online-Sicherung.

Wie Sie bereits verstanden haben, stellt dieser Algorithmus hohe Anforderungen an den Administrator - unangenehme Bewegungen und Speicher sind nicht verfügbar. Aus diesem Grund haben wir uns entschlossen, den Faktor Mensch vollständig auszuschließen, und uns daran erinnert, dass wir ZABBIX haben, das dies sehr gut selbst handhaben kann, wenn wir dem Algorithmus ein wenig PowerShell- und Bash-Magie hinzufügen.

Nun dazu, wie das gemacht wird.

In Zabbix wird ein Trigger für freien Speicherplatz konfiguriert und eine Schaltfläche für den manuellen Modus erstellt:

Bild

Wenn der Trigger ausgelöst wird, wird im Server-Roboter-Sheduler eine Aufgabe gebildet, auf der sich alle unsere Automatisierungsskripte befinden:

Powershell.exe "Enable-ScheduledTask \PROD_TASKS\Add_HDD_OS0226” 

Zum festgelegten Zeitpunkt wird auf dem Server ein Skript gestartet, das:

Fügt die Festplatte der gewünschten VM hinzu:
(Gleichzeitig wählt er das freieste Volumen)

 $vm = Get-VM -Name $vmName New-HardDisk -VM $vm -CapacityGB $newHDDCapacity -Datastore $datastoreName –ThinProvisioned 

Sucht nach Serverzugriffsdetails:
OFFTop
Wir verwenden ein angepasstes Repository mit Zugriffsdetails basierend auf TeamPass, sodass das Skript den gewünschten Server im System findet und seine Details automatisch empfängt. Dies geschieht, weil wir jeden Monat automatisch alle Passwörter ändern. Dies ist jedoch das Thema eines separaten Artikels

 #Generate TeamPass API request string $vmTPReq = "   TeamPass" #Send request to TeamPass $vmCreds = Invoke-WebRequest($vmTPReq) -UseBasicParsing | ConvertFrom-Json #Convert credentials $credential = New-Object System.Management.Automation.PSCredential($vmCreds.login,(ConvertTo-SecureString $vmCreds.pw -asPlainText -Force)) 

Kommt auf SSH:
 #Create partition & FS, mount disk to directory, edit fstab...etc. New-SSHSession -ComputerName $vmCreds.url -Credential $credential -Verbose -AcceptKey:$true $results = Invoke-SSHCommand -SessionId 0 -Command "/mnt/autodoit.sh" Remove-SSHSession -Index 0 -Verbose 

Markiert es und fügt es dem UnionFS-Mount hinzu:
(autodoit.sh)
 #!/bin/bash fstab="/etc/fstab" newdisk=$(( ( parted -lm >&1 ) 1>/tmp/gethddlog ) 2>&1) newdisk=$(echo $newdisk | cut -d ':' -f 2) if [[ $newdisk == "" ]] ; then printf "New disk not found! Exit\n". exit fi printf "New disk found: $newdisk\n" echo #Create new partition echo Create new partition ... parted $newdisk mklabel gpt unit TB mkpart primary 0.00TB 2.00TB print sleep 10 #Create filesystem echo Create filesystem xfs ... newdisk="$newdisk$((1))" mkfs.xfs $newdisk #Create new DATA directory lastdata=$(ls /mnt/ | grep 'data[0-9]\+$' | cut -c5- | sort -n | tail -n1) lastdatamount="/mnt/data$((lastdata))" newdata="/mnt/data$((lastdata+1))" printf "Create new direcory: $newdata\n" mkdir $newdata chown -R nobody:nobody $newdata chmod -R 755 $newdata #Mount new partition to new directory printf "Mount new partition to $newdata...\n" mount -t xfs ${newdisk} ${newdata} #Get UUID of new partition uuid=$(blkid $newdisk -o value -s UUID) printf "New disk UUID: $uuid\n" #Add mountpoint for new partition printf "Add mountpoint for new disk to fstab...\n" lastdatamount=$(cat $fstab | grep "$lastdatamount\s") newdatamount="UUID=$uuid $newdata xfs defaults,nofail 0 0" ldm=$(echo $lastdatamount | sed -r 's/[\/]/\\\//g') ndm=$(echo $newdatamount | sed -r 's/[\/]/\\\//g') sed -i "/$ldm/a $ndm" $fstab #Change UnionFS mountpoint string printf "Modify mountpoint for UnionFS in fstab...\n" prevunion=$(cat $fstab | grep fuse.unionfs) newunion=$(echo $prevunion | sed -e "s/=rw/=ro/") newunion=$(echo $newdata=rw:$newunion) sed -i "s|$prevunion|$newunion|" $fstab #Remount UnionFS printf "Remount UnionFS...\n" service smb stop sleep 0.6 umount /mnt/unionfs mount /mnt/unionfs service smb start printf "Done!\n\n" rm /tmp/gethddlog 


Leider haben wir zum Zeitpunkt dieses Schreibens einige Probleme im Zusammenhang mit der automatischen Erstellung von Aufgaben in VEEAM zum Archivieren der alten Festplatte und zum Schreiben auf Band nicht gelöst, sodass dies immer noch manuell erfolgt. Aber wir werden das Skript definitiv aktualisieren, sobald wir ein paar Probleme gelöst haben.

Gepostet von Vitaliy Rosman ( PBCVIT ).

Ein Stück Code zum Kleben von Arrays wurde ehrlich ausgeliehen, Links zum Autor wurden im Code gespeichert.

Vollständiges Skript
 #Set VM name $vmName = "OS0226" #Set TeamPass ID of linux server $vmTPId = "1161" #Set capacity of new HDD in GB $newHDDCapacity = 2048 #Set Log file $logFile = "C:\SCRIPTS\Log\NewHardDisk-OS0226.log" #Import module for SSH connections Import-Module Posh-SSH #Add VEEAM Snap-In Add-PSSnapin VeeamPSSnapin #Initialize VMWare PowerCLI & 'C:\Program Files (x86)\VMware\Infrastructure\PowerCLI\Scripts\Initialize-PowerCLIEnvironment.ps1' #Add function for array join Function Join-Object { # https://powersnippets.com/join-object/ [CmdletBinding()]Param ( # Version 02.02.00, by iRon [Object[]]$RightTable, [Alias("Using")]$On, $Merge = @{}, [Parameter(ValueFromPipeLine = $True)][Object[]]$LeftTable, [String]$Equals ) $Type = ($MyInvocation.InvocationName -Split "-")[0] $PipeLine = $Input | ForEach {$_}; If ($PipeLine) {$LeftTable = $PipeLine} If ($LeftTable -eq $Null) {If ($RightTable[0] -is [Array]) {$LeftTable = $RightTable[0]; $RightTable = $RightTable[-1]} Else {$LeftTable = $RightTable}} $DefaultMerge = If ($Merge -is [ScriptBlock]) {$Merge; $Merge = @{}} ElseIf ($Merge."") {$Merge.""} Else {{$Left.$_, $Right.$_}} If ($Equals) {$Merge.$Equals = {If ($Left.$Equals -ne $Null) {$Left.$Equals} Else {$Right.$Equals}}} ElseIf ($On -is [String] -or $On -is [Array]) {@($On) | ForEach {If (!$Merge.$_) {$Merge.$_ = {$Left.$_}}}} $LeftKeys = @($LeftTable[0].PSObject.Properties | ForEach {$_.Name}) $RightKeys = @($RightTable[0].PSObject.Properties | ForEach {$_.Name}) $Keys = $LeftKeys + $RightKeys | Select -Unique $Keys | Where {!$Merge.$_} | ForEach {$Merge.$_ = $DefaultMerge} $Properties = @{}; $LeftOut = @($True) * @($LeftTable).Length; $RightOut = @($True) * @($RightTable).Length For ($LeftIndex = 0; $LeftIndex -lt $LeftOut.Length; $LeftIndex++) {$Left = $LeftTable[$LeftIndex] For ($RightIndex = 0; $RightIndex -lt $RightOut.Length; $RightIndex++) {$Right = $RightTable[$RightIndex] $Select = If ($On -is [String]) {If ($Equals) {$Left.$On -eq $Right.$Equals} Else {$Left.$On -eq $Right.$On}} ElseIf ($On -is [Array]) {($On | Where {!($Left.$_ -eq $Right.$_)}) -eq $Null} ElseIf ($On -is [ScriptBlock]) {&$On} Else {$True} If ($Select) {$Keys | ForEach {$Properties.$_ = If ($LeftKeys -NotContains $_) {$Right.$_} ElseIf ($RightKeys -NotContains $_) {$Left.$_} Else {&$Merge.$_} }; New-Object PSObject -Property $Properties; $LeftOut[$LeftIndex], $RightOut[$RightIndex] = $Null } } } If ("LeftJoin", "FullJoin" -Contains $Type) { For ($LeftIndex = 0; $LeftIndex -lt $LeftOut.Length; $LeftIndex++) { If ($LeftOut[$LeftIndex]) {$Keys | ForEach {$Properties.$_ = $LeftTable[$LeftIndex].$_}; New-Object PSObject -Property $Properties} } } If ("RightJoin", "FullJoin" -Contains $Type) { For ($RightIndex = 0; $RightIndex -lt $RightOut.Length; $RightIndex++) { If ($RightOut[$RightIndex]) {$Keys | ForEach {$Properties.$_ = $RightTable[$RightIndex].$_}; New-Object PSObject -Property $Properties} } } }; Set-Alias Join Join-Object Set-Alias InnerJoin Join-Object; Set-Alias InnerJoin-Object Join-Object -Description "Returns records that have matching values in both tables" Set-Alias LeftJoin Join-Object; Set-Alias LeftJoin-Object Join-Object -Description "Returns all records from the left table and the matched records from the right table" Set-Alias RightJoin Join-Object; Set-Alias RightJoin-Object Join-Object -Description "Returns all records from the right table and the matched records from the left table" Set-Alias FullJoin Join-Object; Set-Alias FullJoin-Object Join-Object -Description "Returns all records when there is a match in either left or right table" #Connect to vCenter Connect-VIServer vcenter.mmc.local #Get datastore $datastores = get-datastore | where-object Name -like "*TIERED_VM_PROD*" if ($datastores.Count -gt 0) { if (($datastores | Sort -Descending {$_.FreeSpaceGB})[0].FreeSpaceGB -gt 2048) { $datastoreName = ($datastores | Sort -Descending {$_.FreeSpaceGB})[0].Name } else { Write-Host("ERROR: No enought space on datastore for new HDD!") break } } else { Write-Host("ERROR: No Datastores found!") break } #Generate TeamPass API request string $vmTPReq = "   TeamPass" #Send request to TeamPass $vmCreds = Invoke-WebRequest($vmTPReq) -UseBasicParsing | ConvertFrom-Json #Convert credentials $credential = New-Object System.Management.Automation.PSCredential($vmCreds.login,(ConvertTo-SecureString $vmCreds.pw -asPlainText -Force)) if ((Test-Connection $vmCreds.url -Count 1 -Quiet) -eq $false) { $err = $error[0].FullyQualifiedErrorId } try { # Get disks information from Linux New-SSHSession -ComputerName $vmCreds.url -Credential $credential -Verbose -AcceptKey:$true $linuxCommand1 = 'ls -dl /sys/block/sd*/device/scsi_device/*' $linuxDisksData1 = Invoke-SSHCommand -SessionId 0 -Command $linuxCommand1 $linuxCommand2 = 'lsblk -l | grep /mnt' $linuxDisksData2 = Invoke-SSHCommand -SessionId 0 -Command $linuxCommand2 Remove-SSHSession -Index 0 -Verbose $linuxMounts = $linuxDisksData2.Output -replace '\s+', ' ' | Select @{N='Partition';E={($_.split(" ")[0])}}, @{N='linuxMount';E={($_.split(" ")[6])}} $linuxDisks = $linuxDisksData1.Output -replace '\s+', ' ' | Select @{N='Partition';E={($_.split(" ")[8]).split('/')[3]+'1'}}, @{N='SCSIAddr';E={(($_.split(" ")[8]).split('/')[6]).split(':')[1]+':'+(($_.split(" ")[8]).split('/')[6]).split(':')[2]}} $linuxDisks = $linuxDisks | sort SCSIAddr } catch { $err = $error[0].FullyQualifiedErrorId } #Get disks information from vmware $vmDisks = Get-VM -Name $vmName | Get-HardDisk | Select @{N='vmwareHardDisk';E={$_.Name}}, @{N='vSCSI';E={$_.uid.split("/")[3].split("=")[1]}}, @{N='SCSIAddr';E={[string]([math]::truncate((($_.uid.split("/")[3].split("=")[1])-2000)/16))+':'+[string]((($_.uid.split("/")[3].split("=")[1])-2000)%16)}} $vmDisks = $vmDisks | sort SCSIAddr #Get total information about VM Disks $OLAYtotalEffects = $vmDisks | InnerJoin $linuxDisks SCSIAddr -eq SCSIAddr | InnerJoin $linuxMounts Partition -eq Partition| sort vmwareHardDisk #Display total information about VM Disks $OLAYtotalEffects | ft $OLAYtotalEffects | ft 2>$logFile #Get latest mount $linuxLatestDiskMount = [string](($OLAYtotalEffects | select linuxMount | where linuxMount -like "/mnt/data*" | % {[int](($_.linuxMount.Split("/")[2]).Replace("data",""))} | Measure -Maximum).Maximum) #Get latest vSCSI number $latestDiskvSCSI = ($OLAYtotalEffects | where {$_.linuxMount -eq "/mnt/data$linuxLatestDiskMount"}).vSCSI #Add HDD to VM $vm = Get-VM -Name $vmName New-HardDisk -VM $vm -CapacityGB $newHDDCapacity -Datastore $datastoreName -ThinProvisioned #Let the disk takes root Write-Host("Let the disk takes root...") sleep 10 if ((Test-Connection $vmCreds.url -Count 1 -Quiet) -eq $false) { $err = $error[0].FullyQualifiedErrorId } try { #Create partition & FS, mount disk to directory, edit fstab...etc. New-SSHSession -ComputerName $vmCreds.url -Credential $credential -Verbose -AcceptKey:$true $results = Invoke-SSHCommand -SessionId 0 -Command "/mnt/autodoit.sh" Remove-SSHSession -Index 0 -Verbose $results.Output } catch { $err = $error[0].FullyQualifiedErrorId } #After adding a new disk, some checks are just performed if ((Test-Connection $vmCreds.url -Count 1 -Quiet) -eq $false) { $err = $error[0].FullyQualifiedErrorId } try { # Get disks information from Linux New-SSHSession -ComputerName $vmCreds.url -Credential $credential -Verbose -AcceptKey:$true $linuxCommand1 = 'ls -dl /sys/block/sd*/device/scsi_device/*' $linuxDisksData1 = Invoke-SSHCommand -SessionId 0 -Command $linuxCommand1 $linuxCommand2 = 'lsblk -l | grep /mnt' $linuxDisksData2 = Invoke-SSHCommand -SessionId 0 -Command $linuxCommand2 Remove-SSHSession -Index 0 -Verbose $linuxMounts = $linuxDisksData2.Output -replace '\s+', ' ' | Select @{N='Partition';E={($_.split(" ")[0])}}, @{N='linuxMount';E={($_.split(" ")[6])}} $linuxDisks = $linuxDisksData1.Output -replace '\s+', ' ' | Select @{N='Partition';E={($_.split(" ")[8]).split('/')[3]+'1'}}, @{N='SCSIAddr';E={(($_.split(" ")[8]).split('/')[6]).split(':')[1]+':'+(($_.split(" ")[8]).split('/')[6]).split(':')[2]}} $linuxDisks = $linuxDisks | sort SCSIAddr } catch { $err = $error[0].FullyQualifiedErrorId } #Get disks information from vmware $vmDisks = Get-VM -Name $vmName | Get-HardDisk | Select @{N='vmwareHardDisk';E={$_.Name}}, @{N='vSCSI';E={$_.uid.split("/")[3].split("=")[1]}}, @{N='SCSIAddr';E={[string]([math]::truncate((($_.uid.split("/")[3].split("=")[1])-2000)/16))+':'+[string]((($_.uid.split("/")[3].split("=")[1])-2000)%16)}} $vmDisks = $vmDisks | sort SCSIAddr #Get total information about VM Disks $OLAYtotalEffects = $vmDisks | InnerJoin $linuxDisks SCSIAddr -eq SCSIAddr | InnerJoin $linuxMounts Partition -eq Partition| sort vmwareHardDisk #Display total information about VM Disks $OLAYtotalEffects | ft $OLAYtotalEffects | ft 2>$logFile Disconnect-VIServer -Confirm:$false Disable-ScheduledTask \PROD_TASKS\Add_HDD_OS0226 


Es gibt keine Beschwerden gegen UnionFS, es arbeitet seit mehr als zwei Jahren stabil.

Die Frage, warum die Speicherung im Allgemeinen organisiert ist, ist im Allgemeinen rhetorisch. Akzeptieren Sie sie einfach so, wie sie ist.

Bitte beachten Sie, dass für verschiedene Systeme unterschiedliche Arten der Laufwerkszuordnung verwendet werden müssen. Sei daher vorsichtig und Kraft wird mit dir kommen.

Source: https://habr.com/ru/post/de440138/


All Articles