두 번째 웹 사이트 컨트롤러 프로비전
적용 대상: Windows Azure Pack
Windows Azure 팩: 웹 사이트에는 최대 두 개의 웹 사이트 컨트롤러가 있을 수 있습니다. 고가용성을 위해 이 최대값을 적용하고 두 번째 웹 사이트 컨트롤러를 프로비전하는 것이 좋습니다. 다음 두 가지 방법 중 하나를 사용하여 이 작업을 수행할 수 있습니다.
- 새 팜을 만들 때
- 기존 팜에 컨트롤러 추가
새 팜에 두 번째 웹 사이트 컨트롤러 추가(업데이트 릴리스 6 이상 포함)
Windows Azure Pack 웹 사이트 관리 콘솔을 사용하여 새 팜을 구성할 때 두 번째 웹 사이트 컨트롤러를 추가할 수 있습니다.
- 컨트롤러 유형을 선택할 때 보조 컨트롤러로 기존 웹 사이트 클라우드에 서버 조인을 선택합니다.
- 시스템 키 및 데이터베이스 ConnectionStrings 목록에서 구성을 클릭합니다.
- 팝업 창에서 다음 필드에 대한 값을 입력합니다.
- 기본 컨트롤러
- 사용자 이름
- 암호
- 확인을 클릭하여 두 번째 컨트롤러를 구성합니다.
기존 팜에 두 번째 웹 사이트 컨트롤러 추가
다음 스크립트를 사용하여 기존 팜에 컨트롤러를 추가합니다.
OnStartSecondaryController.cmd - 준비한 Windows 2012 Server 또는 가상 머신에 웹 플랫폼 설치 관리자(웹 PI)를 설치합니다. 그런 다음 연속해서 HostingBootstrapperBootstrapper 및 OnStartSecondaryController 스크립트를 호출하여 보조 컨트롤러 프로비저닝을 완료합니다. 필수 매개 변수에는 설치 프로그램에 사용할 SQL Server 및 컨트롤러 관리 자격 증명이 포함됩니다.
HostingBootstrapperBootstrapper.ps1 - Program Files\Microsoft\Web Platform Installer\WebpiCmd.exe를 호출하여 두 번째 웹 사이트 컨트롤러를 설치합니다. 기본 컨트롤러를 설치할 때와 동일한 절차를 사용하지만 명령줄 스위치 /SuppressPostFinish를 지정하여 구성 포털을 삭제합니다.
OnStartSecondaryController.ps1 -
SystemCore
및SiteRuntime
키와 호스팅 및 리소스 측정 연결 문자열을 포함하여 구성 데이터를 기본 컨트롤러에서 보조 컨트롤러로 복사합니다. 완료되면 WebFarmService를 시작합니다.Common.ps1 - OnStartSecondaryController.ps1 스크립트에 대한 지원 기능을 제공합니다.
중요
이 스크립트를 실행하려면 기본 컨트롤러에서 WinRM(Windows 원격 관리)를 사용하도록 설정해야 합니다.
스크립트를 실행하는 단계
보조 컨트롤러가 될 서버의 폴더에 스크립트 파일을 복사합니다.
스크립트와 동일한 폴더에 WebPlatformInstaller.msi 파일을 복사합니다. 이 작업은 OnStartSecondaryController.cmd 스크립트가 웹 PI의 설치를 자동화하기 때문에 필요합니다.
아래 표에 설명된 매개 변수를 제공하여 관리자 권한으로 OnStartSecondaryController.cmd 를 실행합니다. 웹 PI 자동화를 통해 적절한 제품을 설치할 수 있고 WinRM을 통해 기본 컨트롤러에 액세스할 수 있도록 관리자 권한이 필요합니다.
참고
작업 그룹 시나리오에서는 기본 컨트롤러에서 WinRM을 사용하도록 설정하거나 수동으로 OnStartSecondaryController.cmd 스크립트의 명령을 실행해야 할 수도 있습니다.
OnStartSecondaryController.cmd
구문
OnStartSecondaryController.cmd -feed %Feed% -webSitesInstanceName %WebSitesInstanceName% -sqlservername %DatabaseServerName% -sqlsysadmin %DatabaseSysAdminAccount% -sqlsysadminpwd %DatabaseSysAdminPassword% -controllerAdminUserName %ControllerAdminUserName% -controllerAdminPassword %ControllerAdminPassword%
매개 변수
매개 변수 이름 | 설명 | 참고 사항 |
feed |
선택적으로 컨트롤러를 설치하는 데 사용될 웹 PI 피드를 지정합니다. | 이 매개 변수를 지정하지 않으면 웹 PI 기본 피드가 사용됩니다. |
webSitesInstanceName |
데이터베이스 개체에 대한 접두사로 사용 | 설치에서 데이터베이스의 접두사 이름과 일치해야 합니다. |
sqlservername |
SQL Server 인스턴스의 이름 | |
sqlsysadmin |
SQL Server sys 관리자 사용자 계정 이름 | sysadmin 서버 역할의 멤버여야 합니다. |
sqlsysadminpwd |
SQL Server sys 관리자 사용자 계정 암호 | |
controllerAdminUserName |
프로비전할 WFF(Web Farm Framework) 관리자 계정 이름 | 도메인 계정인 경우 로컬 관리자 그룹에 추가됩니다. 서버가 작업 그룹에 포함된 경우 사용자가 없으면 새로 만들어 로컬 관리자 그룹에 추가합니다. |
controllerAdminPassword |
프로비전할 WFF 관리자 계정 암호 |
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
}
}
}