Obecnie korzystamy z TeamCity dla kompilacji CI i staramy się również skonfigurować wdrożenia automatyczne.Zautomatyzowane wdrażanie do środowiska równoważnego obciążeniem F5
Projekt, który próbuję obecnie wdrożyć, to usługa systemu Windows, która znajduje się w module równoważenia obciążenia F5. W przyszłości chcielibyśmy również zautomatyzować wdrażanie naszych stron IIS, które również znajdują się pod F5.
Od TeamCity możemy wykonywać skrypty PowerShell, aby zunifikować usługę Windows na wybranym serwerze, przesłać do niej nasze pliki, a następnie ponownie zainstalować usługę.
Mam jednak problem z ustaleniem, jak radzić sobie z modułem równoważenia obciążenia. Chcielibyśmy wyłączyć 1 węzeł naraz, uważać na wszystkie połączenia, aby je upuścić, a następnie wdrożyć nasz kod i przywrócić węzeł.
Wydaje się, że byłby to bardzo powszechny problem, ale znajduję zaskakująco mało informacji o tym, jak to zrobić.
Dzięki!
Odpowiedział
Dzięki Jonathon Rossi dla iControl cmdlets PowerShell!
Na litość innych użytkowników, oto próbka zamknięcie, monitorowanie połączeń spadać, kod popychanie, a potem zawrócić na równoważenia obciążenia F5 przez skryptu PowerShell
dla tych skryptów do pracy ci najpierw będą musiały zainstalować cmdlet F5 iControl z linków podanych w odpowiedzi poniżej
#PULL IN OUR F5 UTILITY FUNCTIONS
. .\F5Functions.ps1
#DEFINE LOGIC TO DEPLOY CODE TO A NODE THAT HAS ALREADY BEEN REMOVED FROM THE LOAD BALANCER
function Deploy(
[F5Node]$Node
)
{
Write-Host "Deploying To: "$Node.Name
#TODO: Remotely shut down services, push code, start back up services
}
#DEFINE NODES
$nodes = @()
$nodes += New-Object F5Node -ArgumentList @("TestNode1", "1.1.1.1")
$nodes += New-Object F5Node -ArgumentList @("TestNode2", "1.1.1.2")
#DEPLOY
DeployToNodes -Nodes $nodes -F5Host $F5Host -F5UserName $F5UserName -F5Password $F5Password
I tu jest wielokrotnego użytku F5Functions skrypt
#Load the F5 powershell iControl snapin
Add-PSSnapin iControlSnapin;
Write-Host "Imported F5 function!!!"
Add-Type @'
public class F5Node
{
public F5Node(string name, string address){
Address = address;
Name = name;
}
public string Address {get;set;}
public string Name {get;set;}
public string QualifiedName {get{return "/Common/" + Name;}}
}
'@
function DeployToNodes(
[string]$F5Host = $(throw "Missing Required Parameter"),
[string]$F5UserName = $(throw "Missing Required Parameter"),
[string]$F5Password = $(throw "Missing Required Parameter"),
[F5Node[]]$Nodes = $(throw "Missing Required Parameter"),
[int]$MaxWaitTime = 300 #seconds... defaults to 5 minutes
){
Authenticate -F5Host $F5Host -F5UserName $F5UserName -F5Password $F5Password
foreach($node in $Nodes){
DisableNode -Node $node
WaitForConnectionsToDrop -Node $node -MaxWaitTime $MaxWaitTime
#Assume the Script that included this script defined a Deploy Method with a Node param
Deploy -Node $node
EnableNode -Node $node
}
}
function Authenticate(
[string]$F5Host = $(throw "Missing Required Parameter"),
[string]$F5UserName = $(throw "Missing Required Parameter"),
[string]$F5Password = $(throw "Missing Required Parameter")
)
{
Write-Host "Authenticating to F5..."
Initialize-F5.iControl -HostName $F5Host -Username $F5UserName -Password $F5Password
Write-Host "Authentication Success!!!"
}
function ParseStatistic(
[iControl.CommonStatistic[]]$StatsCollection = $(throw "Missing Required Parameter"),
[string]$StatName = $(throw "Missing Required Parameter")
)
{
for($i=0; $i -lt $StatsCollection.Count; $i++){
if($StatsCollection[$i].type.ToString() -eq $StatName){
return $StatsCollection[$i].value.low
break
}
}
}
function GetStats(
[F5Node]$Node = $(throw "Missing Required Parameter")
)
{
$arr = @($Node.QualifiedName)
$nodeStats = (Get-F5.iControl).LocalLBNodeAddressV2.get_statistics($arr)
return $nodeStats.statistics.statistics
#foreach($memberStats in $poolStats.statistics){
# if($memberStats.member.address.ToString() -eq $Node -and $memberStats.member.port -eq $Port){
# return $memberStats.statistics
# }
#}
}
function GetStatistic(
[F5Node]$Node = $(throw "Missing Required Parameter"),
[string]$StatName = $(throw "Missing Required Parameter")
)
{
$stats = GetStats -Node $Node
$stat = ParseStatistic -StatsCollection $stats -StatName $StatName
return $stat
}
function DisableNode(
[F5Node]$Node = $(throw "Missing Required Parameter")
)
{
Disable-F5.LTMNodeAddress -Node $Node.Address
Write-Host "Disabled Node '$Node'"
}
function EnableNode(
[F5Node]$Node = $(throw "Missing Required Parameter")
)
{
Enable-F5.LTMNodeAddress -Node $Node.Address
Write-Host "Enabled Node '$Node'"
}
function WaitForConnectionsToDrop(
[F5Node]$Node = $(throw "Missing Required Parameter"),
[int]$MaxWaitTime = 300
)
{
$connections = GetCurrentConnections -Node $Node
$elapsed = [System.Diagnostics.Stopwatch]::StartNew();
while($connections -gt 0 -and $elapsed.ElapsedMilliseconds -lt ($MaxWaitTime * 1000)){
Start-Sleep -Seconds 10
$connections = GetCurrentConnections -Node $Node
}
}
function GetCurrentConnections(
[F5Node]$Node = $(throw "Missing Required Parameter")
)
{
$connections = GetStatistic -Node $Node -StatName "STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS"
$name = $Node.Name + ":" + $Node.Address
Write-Host "$connections connections remaining on '$name'"
return $connections
}
każde ostateczne rozwiązanie z pełnym tekstem kodu źródłowego działającego na ten temat? – Kiquenet
@Kiquenet - Powyższe fragmenty kodu pod nagłówkiem "Odpowiadano" są tym, za pomocą których wdrażamy kod do produkcji około 5-10 razy dziennie. Drugi blok kodu jest modułem, który jest ładowany przez pierwszy blok kodu, który jest przykładem użycia tego modułu. Jedyną częścią, którą musisz wypełnić, jest to, co faktycznie robisz, aby wdrożyć kod, gdy węzeł F5 jest wyłączony (przenieś pliki, rozpakuj, zatrzymaj usługi, zrestartuj usługi itp.). Przepraszam za złe konwencje nazewnictwa. Byłem nowy w Power Shell, kiedy to pisałem. – Michael
Właściwie, kiedy ponownie czytam mój stary post, widzę, że jest znacznie mniej dojrzały niż końcowy produkt. 1. Przeniosłem skrypt funckitów F5 do modułu powershell zainstalowanego na serwerze kompilacji i załadowałem go modułem Load-Module 2. Funkcja DeployToNodes powinna przyjmować ScriptBlock i tablicę argumentów dla ScriptBlock, zamiast zakładać, że Deploy funkcja jest zadeklarowana gdzie indziej. 3. Funkcje powinny być zgodne z konwencją nazewnictwa rzeczownik-czasownik-nazwisko 4.Położyłem więcej logiki wokół zdejmowania węzłów, a więc zmniejszyłoby to połowę w czasie, pozwalając na migracje sql w środku – Michael