Создание веб-фермы в 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..

Сообщите мне, как это происходит!