Выполнение скрипта при запуске службы от имени локального пользователя или системной учетной записи

Перед запуском исполняемого файла службы Service Fabric могут потребоваться некоторые действия по настройке, например для установки переменных среды. Вы можете указать в манифесте службы скрипт, который будет выполняться перед запуском исполняемого файла службы. Настроив политику запуска от имени для точки входа установки службы, вы можете изменить учетную запись, от имени которой выполняется исполняемый файл установки. Отдельная точка входа установки позволяет на короткое время запускать конфигурацию с высоким уровнем привилегий, чтобы исполняемый узел службы не работал с высоким уровнем привилегий в течение продолжительного периода.

Привилегированная точка входа настройки определяется в манифесте службы как SetupEntryPoint и выполняется до запуска других точек входа с теми же учетными данными, что и служба Service Fabric (обычно это учетная запись NetworkService). Исполняемый файл, указанный для точки входа EntryPoint, обычно представлен длительно выполняемым узлом службы. Исполняемый файл EntryPoint запускается после успешного выхода из исполняемого файла SetupEntryPoint. Созданный им процесс отслеживается и перезапускается (снова начиная с точки входа SetupEntryPoint), если произойдет непредвиденное завершение его работы или сбой.

Настройка точки входа установки службы

Ниже приведен простой манифест службы без отслеживания состояния, в котором задан сценарий установки MySetup.bat в службе SetupEntryPoint. Параметр Arguments используется для передачи аргументов в скрипт при его выполнении.

<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="MyStatelessServicePkg"
                 Version="1.0.0"
                 xmlns="http://schemas.microsoft.com/2011/01/fabric"
                 xmlns:xsd="https://www.w3.org/2001/XMLSchema"
                 xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
  <Description>An example service manifest.</Description>
  <ServiceTypes>
    <StatelessServiceType ServiceTypeName="MyStatelessServiceType" />
  </ServiceTypes>

  <!-- Code package is your service executable. -->
  <CodePackage Name="Code" Version="1.0.0">
    <SetupEntryPoint>
      <ExeHost>
        <Program>MySetup.bat</Program>
        <Arguments>MyValue</Arguments>
        <WorkingFolder>Work</WorkingFolder>        
      </ExeHost>
    </SetupEntryPoint>
    <EntryPoint>
      <ExeHost>
        <Program>MyStatelessService.exe</Program>
      </ExeHost>
    </EntryPoint>
  </CodePackage>

  <ConfigPackage Name="Config" Version="1.0.0" />

  <Resources>
    <Endpoints>
      <Endpoint Name="ServiceEndpoint" />
    </Endpoints>
  </Resources>
</ServiceManifest>

Определение политики для точки входа настройки службы

По умолчанию исполняемый файл точки входа установки службы запускается с теми же учетными данными, что и Service Fabric (обычно это учетная запись NetworkService). В манифесте приложения вы можете изменить разрешения безопасности для запуска скрипта от имени администратора или локальной системной учетной записи.

Настройка политики с локальной системной учетной записью

В следующем примере манифест приложения настраивает запуск от имени учетной записи администратора (SetupAdminUser) для точки входа установки службы.

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="MyApplicationType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="MyStatelessService_InstanceCount" DefaultValue="-1" />
  </Parameters>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="MyStatelessServicePkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides />
    <Policies>
      <RunAsPolicy CodePackageRef="Code" UserRef="SetupAdminUser" EntryPointType="Setup" />
    </Policies>
  </ServiceManifestImport>
  <DefaultServices>
    <Service Name="MyStatelessService" ServicePackageActivationMode="ExclusiveProcess">
      <StatelessService ServiceTypeName="MyStatelessServiceType" InstanceCount="[MyStatelessService_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
  </DefaultServices>
  <Principals>
    <Users>
      <User Name="SetupAdminUser">
        <MemberOf>
          <SystemGroup Name="Administrators" />
        </MemberOf>
      </User>
    </Users>
  </Principals>
</ApplicationManifest>

Сначала создайте раздел Principals с именем пользователя, например SetupAdminUser. Учетная запись SetupAdminUser входит в системную группу "Администраторы".

Затем в разделе ServiceManifestImport настройте политику для применения этого субъекта к точке SetupEntryPoint. Эта политика сообщает Service Fabric, что файл MySetup.bat должен всегда выполняться с правами администратора (от имени учетной записи SetupAdminUser). Так как вы не применяете политику к главной точке входа, код из файла MyServiceHost.exe будет запущен от имени системной учетной записи NetworkService. Это учетная запись по умолчанию, с использованием которой запускаются все точки входа службы.

Настройка политики с использованием учетных записей локальной системы

Как правило, выполнять скрипты запуска лучше от имени локальной системной учетной записи, а не от имени администратора. Обычно невозможно выполнять политику запуска от имени с учетными записями из группы администраторов, так как на компьютерах по умолчанию включен контроль учетных записей (UAC) на уровне пользователей. В таких случаях мы рекомендуем запускать SetupEntryPoint от имени учетной записи LocalSystem, а не локального пользователя из группы "Администраторы". В следующем примере показана настройка SetupEntryPoint для запуска с учетной записью LocalSystem.

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="MyApplicationType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="MyStatelessService_InstanceCount" DefaultValue="-1" />
  </Parameters>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="MyStatelessServicePkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides />
    <Policies>
         <RunAsPolicy CodePackageRef="Code" UserRef="SetupLocalSystem" EntryPointType="Setup" />
      </Policies>
  </ServiceManifestImport>
  <DefaultServices>
    <Service Name="MyStatelessService" ServicePackageActivationMode="ExclusiveProcess">
      <StatelessService ServiceTypeName="MyStatelessServiceType" InstanceCount="[MyStatelessService_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
  </DefaultServices>
  <Principals>
      <Users>
         <User Name="SetupLocalSystem" AccountType="LocalSystem" />
      </Users>
   </Principals>
</ApplicationManifest>

Примечание

Чтобы запустить службу или точку входа установки в качестве корня на кластерах Linux, можно указать для AccountType значение LocalSystem.

Запуск скрипта из точки входа установки

Теперь добавьте в проект скрипт запуска, который будет выполняться с правами администратора.

В Visual Studio щелкните проект службы правой кнопкой мыши и добавьте новый файл MySetup.bat.

Затем убедитесь, что файл MySetup.bat включен в пакет службы. По умолчанию он не включен. Щелкните файл правой кнопкой мыши, чтобы открыть контекстное меню, и выберите Свойства. Убедитесь, что в диалоговом окне "Свойства" параметр Копировать в выходной каталог имеет значение Копировать, если новее. Экран должен выглядеть следующим образом.

Свойство CopyToOutput в Visual Studio для пакетного файла SetupEntryPoint

Теперь измените файл MySetup.bat и добавьте следующие команды, которые устанавливают системную переменную среды и выводят текстовый файл:

REM Set a system environment variable. This requires administrator privilege
setx -m TestVariable %*
echo System TestVariable set to > out.txt
echo %TestVariable% >> out.txt

REM To delete this system variable us
REM REG delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v TestVariable /f

Затем скомпилируйте и разверните решение в кластере локальной разработки. После запуска службы (это будет видно в Service Fabric Explorer) вы можете убедиться в успешном выполнении файла MySetup.bat двумя способами. Откройте командную строку PowerShell и введите следующую команду.

PS C:\ [Environment]::GetEnvironmentVariable("TestVariable","Machine")
MyValue

В Service Fabric Explorer запишите имя узла, на котором развернута и запущена служба. Предположим, что это узел Node 2. Затем перейдите в рабочую папку экземпляра приложения и найдите файл out.txt, в котором хранится значение TestVariable. Например, если служба была развернута на узле Node 2, для приложения MyApplicationType используйте такой путь:

C:\SfDevCluster\Data\_App\Node.2\MyApplicationType_App\work\out.txt

Запуск команд PowerShell из точки входа установки

Чтобы запустить PowerShell из точки входа SetupEntryPoint, запустите PowerShell.exe в пакетном файле, который указывает на файл PowerShell. Сначала добавьте файл PowerShell в проект службы, например с именем MySetup.ps1. Не забудьте указать свойство Копировать, если новее , чтобы включить этот файл в состав пакета службы. В следующем примере показан пакетный файл для запуска файла PowerShell с именем MySetup.ps1, который задает системную переменную среды с именем TestVariable.

Файл MySetup.bat для запуска файла PowerShell.

powershell.exe -ExecutionPolicy Bypass -Command ".\MySetup.ps1"

В файле PowerShell добавьте следующую команду, чтобы задать системную переменную среды.

[Environment]::SetEnvironmentVariable("TestVariable", "MyValue", "Machine")
[Environment]::GetEnvironmentVariable("TestVariable","Machine") > out.txt

Примечание

По умолчанию пакетный файл ищет файлы в папке приложения с именем work. В этом примере нам нужно, чтобы пакетный файл MySetup.bat при запуске нашел файл MySetup.ps1 в той же папке, в которой расположен пакет кода приложения. Чтобы изменить эту папку, задайте рабочую папку:

<SetupEntryPoint>
    <ExeHost>
    <Program>MySetup.bat</Program>
    <WorkingFolder>CodePackage</WorkingFolder>
    </ExeHost>
</SetupEntryPoint>

Локальная отладка скрипта запуска с помощью перенаправления консоли

Иногда для отладки нужно просмотреть выходные данные консоли, в которой выполняется скрипт. С помощью манифеста службы вы можете задать для точки входа установки политику перенаправления консоли, которая записывает выходные данные в файл. Выходной файл сохраняется в папку приложения с именем log на том узле кластера, где развертывается и выполняется приложение, находящемся в C:\SfDeployCluster\_App\{application-name}\log. В пути может отображаться число после имени приложения. Это число увеличивается при каждом развертывании. Файлы, записанные в папку журнала, включают Code_{имя_службы}Pkg_S_0.err, который является стандартным выводом ошибок, и Code_{имя_службы}Pkg_S_0.out, который является стандартным выходом. В зависимости от попыток активации службы может отображаться несколько файлов.

Предупреждение

Никогда не используйте политику перенаправления консоли для приложений в рабочей среде, так как она может повлиять на отработку отказа приложения. Используйте ее только для локальной разработки и отладки.

В приведенном ниже примере манифеста службы показано, как установить для перенаправления консоли значение FileRetentionCount.

<SetupEntryPoint>
    <ExeHost>
    <Program>MySetup.bat</Program>
    <WorkingFolder>CodePackage</WorkingFolder>
    <ConsoleRedirection FileRetentionCount="10"/>
    </ExeHost>
</SetupEntryPoint>

Если теперь изменить файл MySetup.ps1 для вывода данных командой Echo, эти данные будут записаны в выходной файл, который можно использовать для отладки.

Echo "Test console redirection which writes to the application log folder on the node that the application is deployed to"

Предупреждение

Завершив отладку сценария, немедленно удалите эту политику перенаправления консоли.

Дальнейшие действия