Создание веб-фермы в PowerShell
Я пытаюсь автоматизировать создание фермы серверов в PowerShell. Благодаря ручному созданию у меня есть следующий XML:
<webFarms>
<webFarm name="alwaysup" enabled="true">
<server address="alwaysup-blue" enabled="true">
<applicationRequestRouting httpPort="8001" />
</server>
<server address="alwaysup-green" enabled="true">
<applicationRequestRouting httpPort="8002" />
</server>
<applicationRequestRouting>
<healthCheck url="http://alwaysup/up.html" interval="00:00:05" responseMatch="up" />
</applicationRequestRouting>
</webFarm>
<applicationRequestRouting>
<hostAffinityProviderList>
<add name="Microsoft.Web.Arr.HostNameRoundRobin" />
</hostAffinityProviderList>
</applicationRequestRouting>
</webFarms>
Попытка сделать это с помощью PS доказывает, что проблема: насколько я могу судить, для этого нет специального API (WebFarmSnapin предназначенный для более старой версии).
Я переключил свое внимание на Командлеты администрирования IIS, но получил только половину работы.
Код, который у меня есть:
#####
# Overwriting the server farm
#####
Write-Host "Overwriting the server farm $($webFarmName)"
$webFarm = @{};
$webFarm["name"] = 'siteFarm'
Set-WebConfiguration "/webFarms" -Value $webFarm
#####
# Adding the servers
#####
Write-Host "Adding the servers"
$blueServer = @{}
$blueServer["address"] = 'site-blue'
$blueServer["applicationRequestRouting"] = @{}
$greenServer = @{}
$greenServer["address"] = 'site-green'
$greenServer["applicationRequestRouting"] = @{}
$servers = @($blueServer, $greenServer)
Add-WebConfiguration -Filter "/webFarms/webFarm[@name='siteFarm']" -Value $servers
#####
# Adding routing
#####
Write-Host "Adding the routing configurations"
$blueServerRouting = @{}
$blueServerRouting["httpPort"] = "8001"
Add-WebConfiguration -Filter "/webFarms/webFarm[@name='siteFarm']/server[@address='site-blue']" -Value $blueServerRouting
Это генерирует
<webFarms>
<webFarm name="siteFarm">
<server address="site-blue" />
<server address="site-green" />
</webFarm>
<applicationRequestRouting>
<hostAffinityProviderList>
<add name="Microsoft.Web.Arr.HostNameRoundRobin" />
</hostAffinityProviderList>
</applicationRequestRouting>
</webFarms>
Как вы видите, отсутствует порт, связанный с маршрутизацией. И я даже не начал с того, что пытался добавить в этот момент проверку здоровья.
Что я делаю неправильно? Есть ли что-то из Cmdlet, которое я не нашел, что облегчает это?
Связанный, но без особого полезного ответа (вкладка PowerShell с сгенерированным кодом остается пустым).
Ответы
Ответ 1
Похоже, вы выяснили, как это сделать, изменив сам файл конфигурации XML. Несмотря на ощущение, что это не совсем похоже на "правильный путь", изменение файла конфигурации напрямую - это совершенно правильное решение. По сути, вы создали шаблон, а шаблоны конфигурации обеспечивают быстрый и понятный подход к созданию поддерживаемой и повторяемой конфигурации.
Мы можем улучшить этот подход, извлекая текст шаблона из script в отдельный текстовый файл. Затем скрипты могут читать (или источник) шаблона и менять любые значения заполнителя по мере необходимости. Это похоже на то, как мы отделяем проблемы в веб-приложении, отделяя наши HTML-шаблоны от кода.
Чтобы более точно ответить на этот вопрос, давайте посмотрим, как это сделать с помощью PowerShell и API администрирования IIS (вы правы, веб-ферма Framework больше не поддерживается для последних версий, если IIS и Windows). Исходный код в вопросе - хорошее начало. Нам просто нужно различать манипуляции с коллекциями конфигурации (с помощью командлетов *-WebConfiguration
) и элементов конфигурации (с помощью командлетов *-WebConfigurationProperty
). Здесь script, который установит значения конфигурации на основе примера в вопросе:
$farmName = 'siteFarm'
Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
-Filter 'webFarms' `
-Name '.' `
-Value @{ name = $farmName; enabled = $true }
Add-WebConfiguration -PSPath 'MACHINE/WEBROOT/APPHOST' `
-Filter "webFarms/webFarm[@name='$farmName']" `
-Value @(
@{ address = 'site-blue'; enabled = $true },
@{ address = 'site-green'; enabled = $true }
)
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
-Filter "webFarms/webFarm[@name='$farmName']/server[@address='site-blue']" `
-Name 'applicationRequestRouting' `
-Value @{ httpPort = 8001 }
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
-Filter "webFarms/webFarm[@name='$farmName']/server[@address='site-green']" `
-Name 'applicationRequestRouting' `
-Value @{ httpPort = 8002 }
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
-Filter "webFarms/webFarm[@name='$farmName']/applicationRequestRouting" `
-Name 'healthCheck' `
-Value @{
url = 'http://mySite/up.html'
interval = '00:00:05'
responseMatch = 'up'
}
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
-Filter "webFarms/webFarm[@name='$farmName']/applicationRequestRouting" `
-Name 'protocol' `
-Value @{ reverseRewriteHostInResponseHeaders = $true }
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
-Filter "webFarms/webFarm[@name='$farmName']/applicationRequestRouting/protocol" `
-Name 'cache' `
-Value @{ enabled = $false; queryStringHandling = 'NoCaching' }
Это может быть немного более подробным, чем необходимо, но я хотел четко проиллюстрировать намерение на каждом шаге. Эта реализация использует запросы XPath для аргументов -Filter
для выбора соответствующих узлов XML. Возможно, мы могли бы реорганизовать script, чтобы уменьшить повторяющиеся задачи, например, определив функцию Add-FarmServer
, которая принимает имя и порт сервера, а затем добавляет соответствующие директивы. Нам также может понадобиться Remove-WebConfigurationLock
, если мы столкнулись с проблемами с заблокированной конфигурацией.
Мы предпочитаем использовать шаблон или программный подход, зависит от предпочтений проекта и команды. API становится намного более привлекательным, когда у нас есть много похожих элементов для настройки, например, если у нас есть сотни серверов для добавления в веб-ферму. С другой стороны, шаблоны просты в понимании, не требуют, чтобы другие члены команды изучали новый (и, возможно, несколько запутывающий) API.
Ответ 2
Увидев, как никто не придумал решение: я использовал очень простой способ просто редактировать XML напрямую, а не проходить через API.
Фактическая функциональность webfarm, которую я еще не получил, но кажется, что все части есть, по крайней мере.
Примером манипулирования XML может быть следующее:
$configPath = "C:\Windows\System32\inetsrv\config\applicationHost.config"
$configXml = [xml] (type $configPath)
[xml] $webFarmXml = @"
<webFarms>
<webFarm name="siteFarm" enabled="true">
<server address="site-blue" enabled="true">
<applicationRequestRouting httpPort="$bluePort" />
</server>
<server address="site-green" enabled="true">
<applicationRequestRouting httpPort="$greenPort" />
</server>
<applicationRequestRouting>
<healthCheck url="http://mySite/up.html" interval="00:00:05" responseMatch="up" />
<protocol reverseRewriteHostInResponseHeaders="true">
<cache enabled="false" queryStringHandling="NoCaching" />
</protocol>
</applicationRequestRouting>
</webFarm>
<applicationRequestRouting>
<hostAffinityProviderList>
<add name="Microsoft.Web.Arr.HostNameRoundRobin" />
</hostAffinityProviderList>
</applicationRequestRouting>
</webFarms>
"@
$configXml.configuration.AppendChild($configXml.ImportNode($webFarmXml.webFarms, $true))
$configXml.Save($configPath)
Ответ 3
Я работал над этим, и я обнаружил, что вы можете использовать Microsoft.Web.Administration
в Powershell для выполнения этого.
Add-Type -AssemblyName "Microsoft.Web.Administration, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
$iisManager = New-Object Microsoft.Web.Administration.ServerManager
$applicationHostConfig = $IISManager.GetApplicationHostConfiguration()
# Get the WebFarms section. Section names are case-sensitive.
$webFarmSection = $ApplicationHostConfig.GetSection("webFarms")
$webFarms = $WebFarmSection.GetCollection()
# Create a new webfarm and assign a name.
$webFarm = $WebFarms.CreateElement("webFarm")
$webFarm.SetAttributeValue("name", "MyNewWebFarmName")
# Add it to the parent element
$webFarms.Add($webFarm)
# Save changes
$iisManager.CommitChanges()
Есть две вещи, которые необходимо упомянуть:
-
После вызова $iisManager.CommitChanges()
объект переходит в режим только для чтения. Перед внесением любых новых изменений необходимо повторно создать все объекты.
-
Если вы решили создать новый сервер в своей веб-ферме, у вас возникнет проблема, если вы присвоите серверу имя и затем попытаетесь получить доступ к его настройкам порта. Что вам нужно сделать, сначала назначьте порт, а затем назначьте имя и включите/отключите его. В противном случае это вызовет ошибку System.AccessViolationException: Attempted to read or write protected memory.
.
Сообщите мне, как это происходит!