Provisionar um segundo controlador de Sites
Aplica-se a: Windows Azure Pack
Microsoft Azure Pack: Os Sites podem ter um máximo de dois Controladores de Sites. Para a alta disponibilidade, é altamente recomendável que você exercita essa máxima e provisione um segundo Controlador de Sites. Você pode fazer isso de duas maneiras:
- Quando você cria um novo farm
- Adicionar um controlador a um farm existente
Adicionar um segundo controlador de Sites a um novo farm (com a versão de atualização 6 e posterior)
Usando o Windows console de gerenciamento de Sites do Azure Pack, você pode adicionar um segundo controlador de Sites ao configurar um novo farm.
- Ao selecionar o tipo de controlador, selecione Ingressar servidor em uma nuvem de Sites existente como controlador secundário.
- Na lista de Chaves do Sistema e ConnectionStrings de Banco de Dados, clique em Configurar
- Na janela pop-up, insira valores para estes campos:
- Controlador primário
- Nome de usuário
- Senha
- Clique em OK para configurar o segundo controlador.
Adicionar um segundo controlador de Sites a um farm existente
Use os seguintes scripts para adicionar um controlador a um farm existente:
OnStartSecondaryController.cmd - Instala o WebPlatform Installer (Web PI) no servidor do Windows 2012 ou na Máquina Virtual que você preparou. Depois, ele chama os scripts HostingBootstrapperBootstrapper e OnStartSecondaryController sucessivamente para concluir o provisionamento do controlador secundário. Os parâmetros necessários incluem as credenciais administrativas do SQL Server e do Controlador que serão usadas em sua configuração.
HostingBootstrapperBootstrapper.ps1 - Chama Arquivos de Programas\Microsoft\Web Platform Installer\WebpiCmd.exe para instalar o segundo controlador de Sites. Ele usa o mesmo procedimento da instalação do controlador primário, mas descarta o portal de configuração especificando a opção de linha de comando/SuppressPostFinish.
OnStartSecondaryController.ps1 - Copia dados de configuração do controlador primário para o controlador secundário, inclusive as chaves
SystemCore
eSiteRuntime
e as cadeias de conexão de medição de recursos e hospedagem. Ao terminar, ele inicia o WebFarmService.Common.ps1 - Fornece funções de suporte para o script OnStartSecondaryController.ps1.
Importante
Esses scripts exigem que o Windows Remote Management (WinRM) seja habilitado no controlador primário.
Etapas para executar os scripts
Copie os arquivos de script em uma pasta no servidor que será o controlador secundário.
Copie o arquivo WebPlatformInstaller.msi na mesma pasta que os scripts. Isso é necessário porque o script OnStartSecondaryController.cmd automatiza a instalação do Web PI.
Execute OnStartSecondaryController.cmd com direitos de administrador, fornecendo os parâmetros descritos na tabela abaixo. Os privilégios administrativos são necessários para que os produtos adequados possam ser instalados através da automação de Web PI e o controlador primário possa ser acessado através de WinRM.
Observação
Em um cenário de WORKGROUP, talvez você precise habilitar WinRM no controlador primário, ou executar manualmente os comandos do script OnStartSecondaryController.cmd.
OnStartSecondaryController.cmd
Sintaxe
OnStartSecondaryController.cmd -feed %Feed% -webSitesInstanceName %WebSitesInstanceName% -sqlservername %DatabaseServerName% -sqlsysadmin %DatabaseSysAdminAccount% -sqlsysadminpwd %DatabaseSysAdminPassword% -controllerAdminUserName %ControllerAdminUserName% -controllerAdminPassword %ControllerAdminPassword%
Parâmetros
Nome do parâmetro | Descrição | Observações |
feed |
Opcionalmente, especifica o feed de Web PI que será usado para instalar o controlador. | Se esse parâmetro não for especificado, o feed primário do Web PI padrão será usado. |
webSitesInstanceName |
Usado como prefixo de objetos do banco de dados | Deve corresponder ao nome de prefixo do banco de dados na instalação. |
sqlservername |
Nome da instância do SQL Server. | |
sqlsysadmin |
Nome de conta do usuário administrador de sistema do SQL Server. | Precisa ser membro de funções de servidor sysadmin. |
sqlsysadminpwd |
Senha de conta do usuário administrador de sistema do SQL Server. | |
controllerAdminUserName |
Nome da conta de Administrador de Web Farm Framework (WFF) a ser provisionada | Se essa for uma conta de domínio, ele será adicionada ao grupo de administradores locais. Se o servidor estiver em WORKGROUP, ele tentará criar o usuário, caso esse usuário não exista, e o adicionará ao grupo de administradores locais. |
controllerAdminPassword |
Senha da conta do Administrador WFF a ser provisionada |
Script OnStartSecondaryController.cmd
@echo off
echo Starting OnStartSecondaryController.cmd
rem ---------------------------------------------
rem Initialize Variables
rem ---------------------------------------------
set POWERSHELL=%windir%\System32\WindowsPowerShell\v1.0\powershell.exe
set FEED=
set INSTANCE_NAME=
set SQL_SERVERNAME=
set SQL_SYSADMIN=
set SQL_SYSADMINPWD=
set CONTROLLER_ADMIN_USERNAME=
set CONTROLLER_ADMIN_PASSWORD=
rem ---------------------------------------------
rem Parse command line parameters
rem ---------------------------------------------
:parse_param
set PARAM_MATCHED=0
if "%1"=="" (
goto :parse_param_completed
)
if /I "%1"=="-feed" (
set FEED=%2
shift
set PARAM_MATCHED=1
)
if /I "%1"=="-webSitesInstanceName" (
set INSTANCE_NAME=%2
shift
set PARAM_MATCHED=1
)
if /I "%1"=="-sqlservername" (
set SQL_SERVERNAME=%2
shift
set PARAM_MATCHED=1
)
if /I "%1"=="-sqlsysadmin" (
set SQL_SYSADMIN=%2
shift
set PARAM_MATCHED=1
)
if /I "%1"=="-sqlsysadminpwd" (
set SQL_SYSADMINPWD=%2
shift
set PARAM_MATCHED=1
)
if /I "%1"=="-controllerAdminUserName" (
set CONTROLLER_ADMIN_USERNAME=%2
shift
set PARAM_MATCHED=1
)
if /I "%1"=="-controllerAdminPassword" (
set CONTROLLER_ADMIN_PASSWORD=%2
shift
set PARAM_MATCHED=1
)
if "%PARAM_MATCHED%"=="0" (
echo Parameter %1 was not matched
exit 1
)
shift
goto :parse_param
:parse_param_completed
rem -----------------------------------------------------------------------
rem Provision Controller
rem ------------------------------------------------------------------------
echo Installing WebPlatformInstaller.
start /wait %windir%\system32\msiexec.exe /qn /i WebPlatformInstaller.msi /l %SystemDrive%\WebPlatformInstaller.log
if errorlevel 1 (
echo WebPlatform Installer installation failed. See log at %SystemDrive%\WebPlatformInstaller.log for more details.
exit 1
)
echo WebPlatformInstaller setup completed successfully.
echo Enabling remote desktop access.
start /wait cscript %windir%\system32\scregedit.wsf /ar 0
if errorlevel 1 (
echo Enabling remote desktop failed.
exit 1
)
echo Remote desktop access has been enabled successfully.
if exist StrongNameHijack.msi (
echo Installing StrongNameHijack...
start /wait %windir%\system32\msiexec.exe /qn /i StrongNameHijack.msi /l %SystemDrive%\StrongNameHijack.log
if errorlevel 1 (
echo "StrongNameHijack installation failed. See log at %SystemDrive%\StrongNameHijack.log for more details."
exit 1
)
echo StrongNameHijack setup completed successfully.
net stop msiserver & net start msiserver
)
echo Starting HostingBootstrapperBootstrapper.ps1
if "%FEED%"=="" (
%POWERSHELL% -ExecutionPolicy Unrestricted -File HostingBootstrapperBootstrapper.ps1
) else (
%POWERSHELL% -ExecutionPolicy Unrestricted -File HostingBootstrapperBootstrapper.ps1 -mainFeed "%FEED%"
)
if errorlevel 1 (
echo HostingBootstrapperBootstrapper.ps1 failed.
exit 1
)
echo HostingBootstrapperBootstrapper.ps1 completed successfully.
echo Starting OnStartSecondaryController.ps1
%POWERSHELL% -ExecutionPolicy Unrestricted -File OnStartSecondaryController.ps1 -webSitesInstanceName "%INSTANCE_NAME%" -sqlservername "%SQL_SERVERNAME%" -sqlsysadmin "%SQL_SYSADMIN%" -sqlsysadminpwd "%SQL_SYSADMINPWD%" -controllerAdminUserName "%CONTROLLER_ADMIN_USERNAME%" -controllerAdminPassword "%CONTROLLER_ADMIN_PASSWORD%"
if errorlevel 1 (
echo OnStartSecondaryController.ps1 failed.
exit 1
)
echo OnStartSecondaryController.ps1 completed successfully.
echo OnStartSecondaryController.cmd completed successfully.
exit 0
HostingBootstrapperBootstrapper.ps1
# PowerShell script to setup Web Sites Controller using WebPI.
# Copyright (c) Microsoft Corporation. All rights reserved.
Param
(
[string] $boostrapperProductId = "HostingPrimaryControllerBootstrapper_v2",
[string] $mainFeed = "",
[string] $customFeed = ""
)
# Change Error Action to Stop
$ErrorActionPreference="Stop"
Function BootstrapBootstrapper ()
{
$WebPiCmd = [System.Environment]::ExpandEnvironmentVariables("%ProgramW6432%\Microsoft\Web Platform Installer\WebpiCmd.exe")
$WebPiLog = [System.Environment]::ExpandEnvironmentVariables("%SystemDrive%\HostingPrimaryControllerBootstrapper.log")
If ($mainFeed -eq "")
{
Invoke-Command -ScriptBlock { & $WebPiCmd /Install /Products:$boostrapperProductId /AcceptEula /SuppressReboot /SuppressPostFinish /Log:$WebPiLog }
}
Else
{
If ($customFeed -eq "")
{
Invoke-Command -ScriptBlock { & $WebPiCmd /Install /Products:$boostrapperProductId /AcceptEula /SuppressReboot /SuppressPostFinish /XML:$mainFeed /Log:$WebPiLog }
}
Else
{
Invoke-Command -ScriptBlock { & $WebPiCmd /Install /Products:$boostrapperProductId /AcceptEula /SuppressReboot /SuppressPostFinish /XML:$mainFeed /Feeds:$customFeed /Log:$WebPiLog }
}
}
If ($lastexitcode -ne $Null -And $lastexitcode -ne 0)
{
Exit $lastexitcode
}
}
# Entry Point
BootstrapBootstrapper
OnStartSecondaryController.ps1
# PowerShell script to setup a Web Sites secondary controller.
# Copyright (c) Microsoft Corporation. All rights reserved.
Param
(
[string] $webSitesInstanceName,
[string] $sqlservername,
[string] $sqlsysadmin,
[string] $sqlsysadminpwd,
[string] $controllerAdminUserName,
[string] $controllerAdminPassword
)
# Init Global Variables
$cnstr = "server=$($sqlservername);database=Hosting;uid=$($sqlsysadmin);pwd=$($sqlsysadminpwd);"
# Load common script file
$startDir = "."
$common = [System.IO.Path]::Combine($startDir, "Common.ps1")
. $common
Function Get-PrimaryController()
{
Try
{
$siteManager = New-Object Microsoft.Web.Hosting.SiteManager $cnstr
$primaryController = $siteManager.Controllers.GetPrimaryController([Microsoft.Web.Hosting.PlatformOptions]::VirtualMachineManager)
Return $primaryController.MachineName;
}
Finally
{
If($siteManager -ne $Null)
{
$siteManager.Dispose()
}
}
}
Function Test-PrimaryController()
{
Try
{
$PrimaryController = Get-PrimaryController
Return $PrimaryController -ne $Null
}
Catch [Microsoft.Web.Hosting.WebHostingObjectNotFoundException]
{
Write-Host "$(Get-Date): Primary Controller NOT Ready"
Return $False;
}
}
Function WaitForPrimaryControllerToBeReady()
{
$WaitIndex=0;
$MaxWait=15
$WaitInterval=60000
Write-Host "$(Get-Date): Waiting for Primary Controller to be ready"
$valid = Test-PrimaryController
If ($valid -eq $False)
{
While ($WaitIndex -lt $MaxWait -and $valid -eq $False)
{
[System.Threading.Thread]::Sleep($WaitInterval);
$WaitIndex = $WaitIndex + 1
$valid = Test-PrimaryController
}
}
If ($valid -eq $False)
{
Throw New-Object [System.Exception] "Primary Controller NOT ready. Timed out waiting."
}
Write-Host "$(Get-Date): Primary Controller is Ready"
}
Function Copy-SystemCoreKeyFromPrimaryController([string] $PrimaryController)
{
Write-Host "$(Get-Date): Copy SystemCore key"
$remoteCommand = {
Add-PSSnapIn WebHostingSnapIn
Get-WebSitesConfig -Type SecurityKey -SymmetricKeyName SystemCore
}
$SystemCoreKey = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand
Set-WebSitesConfig -Type SecurityKey -SymmetricKeyName SystemCore -SymmetricKey $SystemCoreKey -Force
}
Function Copy-SiteRuntimeKeyFromPrimaryController([string] $PrimaryController)
{
Write-Host "$(Get-Date): Copy SiteRuntime key"
$remoteCommand = {
Add-PSSnapIn WebHostingSnapIn
Get-WebSitesConfig -Type SecurityKey -SymmetricKeyName SiteRuntime
}
$SiteRuntimeKey = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand
Set-WebSitesConfig -Type SecurityKey -SymmetricKeyName SiteRuntime -SymmetricKey $SiteRuntimeKey -Force
}
Function Copy-HostingConnectionStringFromPrimaryController([string] $PrimaryController)
{
Write-Host "$(Get-Date): Copy hosting connection string"
$remoteCommand = {
Add-PSSnapIn WebHostingSnapIn
[Microsoft.Web.Hosting.SiteManager]::GetDefaultConnectionString()
}
$HostingCnStr = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand
Set-WebSitesConnectionString -Type Hosting -ConnectionString $HostingCnStr
}
Function Copy-MeteringConnectionStringFromPrimaryController([string] $PrimaryController)
{
Write-Host "$(Get-Date): Copy metering connection string"
$remoteCommand = {
Add-PSSnapIn WebHostingSnapIn
[Microsoft.Web.Hosting.SiteManager]::GetMeteringConnectionString()
}
$computerName = [Microsoft.Web.Hosting.Common.NetworkHelper]::GetComputerName([Microsoft.Web.Hosting.Common.ComputerNameFormat]::DnsFullyQualified)
$MeteringCnStr = Invoke-Command -ComputerName $PrimaryController -ScriptBlock $remoteCommand
Set-WebSitesConnectionString -Type Metering -ConnectionString $MeteringCnStr -ServerName $computerName
}
Function OnStartSecondaryController()
{
Try
{
Write-Host "$(Get-Date): Starting OnStartSecondaryController()" -ForegroundColor Green
Add-PSSnapin WebHostingSnapin
ConfigureRoleAdministrator $controllerAdminUserName $controllerAdminPassword
WaitForHostingDatabaseToBeReady $cnstr
WaitForPrimaryControllerToBeReady
$PrimaryController = Get-PrimaryController
Copy-SystemCoreKeyFromPrimaryController $PrimaryController
Copy-SiteRuntimeKeyFromPrimaryController $PrimaryController
Copy-HostingConnectionStringFromPrimaryController $PrimaryController
Copy-MeteringConnectionStringFromPrimaryController $PrimaryController
Start-Service WebFarmService
Write-Host "$(Get-Date): OnStartSecondaryController completed successfully" -ForegroundColor Green
}
Catch [System.Exception]
{
Write-Host "$(Get-Date): Exception encountered while executing OnStartSecondaryController:" -ForegroundColor Red
Write-Host $_ -ForegroundColor Red
Write-Host "$(Get-Date): Exiting OnStartSecondaryController.ps1" -ForegroundColor Red
Exit -1
}
}
# Entry Point
OnStartSecondaryController
Common.ps1
# PowerShell Web Sites common script.
# Copyright (c) Microsoft Corporation. All rights reserved.
Function LoadHostingFramework()
{
$mwhc = Get-Item ".\Microsoft.Web.Hosting.Common.dll"
[void] [System.Reflection.Assembly]::LoadFrom($mwhc.FullName)
Write-Host "$(Get-Date): Microsoft.Web.Hosting.Common assembly was successfully loaded from: $mwhc"
$mwh = Get-Item ".\Microsoft.Web.Hosting.dll"
[void] [System.Reflection.Assembly]::LoadFrom($mwh.FullName)
Write-Host "$(Get-Date): Microsoft.Web.Hosting assembly was successfully loaded from: $mwh"
}
Function IsHostingDatabaseReady([string] $cnstr)
{
Try
{
$siteManager = New-Object Microsoft.Web.Hosting.SiteManager $cnstr
$siteManager.TestConnection([Microsoft.Web.Hosting.PlatformOptions]::VirtualMachineManager)
Return $true;
}
Catch [Exception]
{
Write-Host "$(Get-Date): Hosting Database NOT Ready"
Return $false;
}
Finally
{
If($siteManager -ne $Null)
{
$siteManager.Dispose()
}
}
}
Function WaitForHostingDatabaseToBeReady ([string] $cnstr)
{
$WaitIndex=0;
$MaxWait=120
$WaitInterval=60000
Write-Host "$(Get-Date): Waiting for Hosting Database to be ready"
$ready = IsHostingDatabaseReady $cnstr
If($ready -ne $true)
{
While ($WaitIndex -lt $MaxWait -and $ready -ne $true)
{
[System.Threading.Thread]::Sleep($WaitInterval);
$WaitIndex = $WaitIndex + 1
$ready = IsHostingDatabaseReady $cnstr
}
}
If ($ready -ne $true)
{
Throw New-Object [System.Exception] "Hosting Database NOT ready. Timed out waiting."
}
Write-Host "$(Get-Date): Hosting Database is Ready"
}
Function ConfigureRoleAdministrator([string] $roleadminusr, [string] $roleadminpwd)
{
$isDomain = $false
# Identify if user is a domain user account
$values = $roleadminusr.Split('\');
If ($values.Length -eq 1)
{
$domain = $env:COMPUTERNAME
$username = $values[0]
}
ElseIf ($values.Length -eq 2)
{
If ([String]::Equals($values[0], ".") -Or
[String]::Equals($values[0], [Environment]::MachineName, [StringComparison]::OrdinalIgnoreCase))
{
$isDomain = $false
$domain = $env:COMPUTERNAME
$username = $values[1]
}
Else
{
$isDomain = $true
$domain = $values[0]
$username = $values[1]
}
}
Else
{
Throw New-Object ArgumentException "Invalid user name" "roleadminusr"
}
# Create user if specified user is not a domain account
if ($isDomain -eq $false)
{
Try
{
$computer = [ADSI]"WinNT://$env:COMPUTERNAME"
$user = $computer.Create("User", $username)
$user.setpassword($roleadminpwd)
$user.SetInfo()
}
Catch [System.Runtime.InteropServices.COMException]
{
# User already exists
If ($_.Exception.ErrorCode -eq -2147022672)
{
Write-Host "$(Get-Date): User $domain\$username already exits."
Write-Host "$(Get-Date): Updating password for User $domain\$username."
$user = [ADSI]("WinNT://$env:COMPUTERNAME/$username,user")
$user.setpassword($roleadminpwd)
$user.SetInfo()
}
Else
{
Write-Host "$(Get-Date): Error creating user $domain\$username." -ForegroundColor Red
Throw
}
}
}
# Add user to local administrators group
#first translate the "Administrators" name to the name based on locale (make well known SID -> Name translation)
$administratorsSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$administratorsGroupName = $administratorsSID.Translate([System.Security.Principal.NTAccount]).Value
# retrieve the short name eg in german translate VORDEFINIERT\Administratoren ->Administratoren
# the translation should always return fully qualified name equivalent to BUILTIN\Administrators
$localizedAdministratorsGroupName=$administratorsGroupName.Split("\\")[1]
$adminGroup = [ADSI]("WinNT://$env:COMPUTERNAME/$localizedAdministratorsGroupName,group")
Try
{
If ($isDomain -eq $true)
{
$adminGroup.add("WinNT://$domain/$username,user")
}
Else
{
$adminGroup.add("WinNT://$env:COMPUTERNAME/$username,user")
}
}
Catch [System.Runtime.InteropServices.COMException]
{
If ($_.Exception.ErrorCode -eq -2147023518) # ERROR_MEMBER_IN_ALIAS 1378 (0x562)
{
Write-Host "$(Get-Date): User $domain\$username is already member of Administrators group."
}
Else
{
Write-Host "$(Get-Date): Error adding user $domain\$username to Administrators group." -ForegroundColor Red
Throw
}
}
}