Автоматическое создание Сервиса без DefaultServices на машинах разработчика
В недавнем выпуске вопросов и ответов сообщества Service Fabric 24-й серии много обсуждалось использование конструкции DefaultService в ApplicationManifest.xml
и это недостатки. Microsoft предложила полностью исключить это из ApplicationManifest и вместо этого изменить Deploy-FabricApplication.ps1
создать реализацию приложения по умолчанию, чтобы у разработчиков оставался приличный опыт работы с F5.
Поэтому я изменил Deploy-FabricApplication.ps1
к следующему (этот отрывок является нижней частью сценария):
if ($IsUpgrade)
{
$Action = "RegisterAndUpgrade"
if ($DeployOnly)
{
$Action = "Register"
}
$UpgradeParameters = $publishProfile.UpgradeDeployment.Parameters
if ($OverrideUpgradeBehavior -eq 'ForceUpgrade')
{
# Warning: Do not alter these upgrade parameters. It will create an inconsistency with Visual Studio's behavior.
$UpgradeParameters = @{ UnmonitoredAuto = $true; Force = $true }
}
$PublishParameters['Action'] = $Action
$PublishParameters['UpgradeParameters'] = $UpgradeParameters
$PublishParameters['UnregisterUnusedVersions'] = $UnregisterUnusedApplicationVersionsAfterUpgrade
Publish-UpgradedServiceFabricApplication @PublishParameters
}
else
{
$Action = "RegisterAndCreate"
if ($DeployOnly)
{
$Action = "Register"
}
$PublishParameters['Action'] = $Action
$PublishParameters['OverwriteBehavior'] = $OverwriteBehavior
$PublishParameters['SkipPackageValidation'] = $SkipPackageValidation
Publish-NewServiceFabricApplication @PublishParameters
#Get-ServiceFabricApplication
New-ServiceFabricService -Stateless -ApplicationName "fabric:/Acme.Hierarchy" -ServiceTypeName "Acme.Hierarchy.HierarchyServiceType" -ServiceName "fabric:/Acme.Hierarchy/Acme.Hierarchy.HierarchyService"-InstanceCount 1 -PartitionSchemeSingleton
}
Выше не получается с ошибкой
FabricElementNotFoundException
Однако, если вы раскомментируете строку #Get-ServiceFabricApplication
вы увидите, что он действительно возвращает заявку
ApplicationName : fabric:/Acme.Hierarchy
ApplicationTypeName : Acme.HierarchyType
ApplicationTypeVersion : 1.0.0
ApplicationParameters : { "_WFDebugParams_" = "[{"CodePackageName":"Code","Cod
ePackageLinkFolder":null,"ConfigPackageName":null,"Con
figPackageLinkFolder":null,"DataPackageName":null,"Dat
aPackageLinkFolder":null,"LockFile":null,"WorkingFolde
r":null,"ServiceManifestName":"Quantium.RetailToolkit.
Fabric.Hierarchy.HierarchyServicePkg","EntryPointType"
:"Main","DebugExePath":"C:\\Program Files
(x86)\\Microsoft Visual Studio\\2017\\Professional\\Co
mmon7\\Packages\\Debugger\\VsDebugLaunchNotify.exe","D
ebugArguments":"
{6286e1ef-907b-4371-961c-d833ab9509dd} -p [ProcessId]
-tid [ThreadId]","DebugParametersFile":null}]";
"Acme.Hierarchy.HierarchyServ
ice_InstanceCount" = "1" }
Create application succeeded.
и выполнение команды, которая завершается неудачно после завершения сценария публикации, работает отлично.
У кого-нибудь есть решение относительно того, как я могу получить хороший опыт разработчика, не используя DefaultServices и вместо этого используя сценарии Powershell?
заранее спасибо
2 ответа
Я обновил ответ, чтобы добавить больше деталей, почему не следует использовать службы по умолчанию (только в производстве).
На сервисной фабрике у вас есть два варианта создания сервисов:
- Декларативный способ, реализованный с помощью функции служб по умолчанию, где вы описываете службы, которые должны работать как часть вашего приложения с использованием ApplicationManifest.
- и динамический(императивный) способ использования команд powershell для создания этих служб после развертывания приложения.
Декларативный способ обеспечивает удобство определения ожидаемой структуры вашего приложения, так что Service Fabric выполняет работу по созданию и запуску экземпляров ваших сервисов в соответствии с объявлением в ApplicationManifest. Это удобство очень полезно для целей разработки. Представьте, что каждый раз, когда вам приходилось отлаживать приложение, ему приходилось: Build > Package > Deployed to Service Fabric > Вам приходилось вручную запускать множество сервисов, которые определяют ваше приложение. Это было бы слишком неудобно, поэтому служба по умолчанию стала удобной.
Другой сценарий, когда определение вашего приложения является неизменным, это означает, что одно и то же количество сервисов и экземпляров останется неизменным в течение всего времени его развертывания в рабочей среде.
Но мы знаем, что маловероятно, что эти определения будут оставаться неизменными на протяжении многих лет или даже часов в день, поскольку идея микросервисов заключается в том, что они должны быть масштабируемыми и гибкими, чтобы мы могли настраивать конфигурацию отдельных служб независимо от друг с другом.
Используя службы по умолчанию, было бы слишком сложно для логики оркестровки определить, какие изменения были внесены в ваши службы по сравнению со значением по умолчанию, указанным в исходном развертывании, а в случае конфликта, какая конфигурация должна иметь приоритет, например:
- Развернутые службы по умолчанию определяют службу с 5 экземплярами, после ее развертывания вы выполняете сценарий powershell для обновления до 10 экземпляров, затем приходит новое обновление приложения со службами по умолчанию, имеющими 5 экземпляров или с новым значением 8, что должно произойти? какой из них правильный?
- Вы добавляете дополнительные именованные службы (службы того же типа с другим именем) в существующее развертывание, которое не определено в службах по умолчанию. Что произойдет, когда новое развертывание войдет и скажет, что эта служба не должна ожидаться? Удали это? А данные? Как этот сервис должен быть снят с производства? Если я удален по ошибке во время разработки?
- Новая версия удаляет существующую службу, развертывание завершается неудачно, как старая служба должна быть воссоздана? И были ли какие-либо данные для переноса в рамках развертывания?
- Служба была переименована. Как отследить, что он был переименован вместо удаления старого и добавления нового?
Это некоторые из многих проблем, которые могут возникнуть. Вот почему вы должны отойти от сервисов по умолчанию и создавать их динамически (обязательно), с динамическими сервисами сервисная структура получит команду обновления и произойдет следующее:
"Это мой новый пакет типов приложений с новыми определениями типов служб, какую бы версию вы там не развернули, замените эту версию и сохраните ту же конфигурацию".
Если требуется новая конфигурация, вы предоставите в качестве параметров для развертывания переопределение старых значений или измените ее отдельной командой. Это значительно упростит задачу, поскольку SF не придется беспокоиться о различных конфигурациях, а просто применяет изменения пакетов к развернутым службам.
Вы также можете найти хорошую информацию об этих проблемах по этим ссылкам:
- Как не использовать сервисные фабричные сервисы по умолчанию
- Служебная ткань Q&A 10
- Служебная ткань Q&A 11
По поводу вашего основного вопроса:
У кого-нибудь есть решение относительно того, как я могу получить хороший опыт разработчика, не используя DefaultServices и вместо этого используя сценарии Powershell?
если вы хотите получить хороший опыт, вы должны использовать службы по умолчанию, это предназначено для этого, предоставьте разработчику хороший опыт, не беспокоясь о службах, необходимых для запуска при запуске.
Хитрость заключается в том, что во время процесса CI вы должны удалить службы по умолчанию из манифеста приложения перед упаковкой приложения, чтобы впоследствии не столкнуться с недостатками.
Удаляя defaultServices во время CI (например, VSTS Build), вы получаете преимущества defaultServices в среде dev, не нужно поддерживать версии сценариев powershell (если появляется новая версия), а удаление служб по умолчанию очень простое. Сценарий powershell добавлен в качестве шага сборки. Кроме этого, все остается прежним.
PS: У меня нет настоящего сценария под рукой, но я буду очень прост, как это:
$appManifest = "C:\Temp\ApplicationManifest.xml" #you pass as parameter
[xml]$xml = Get-Content $appManifest
$xml.ApplicationManifest.DefaultServices.RemoveAll()
$xml.save($appManifest)
Решением здесь является использование сценария с именем Start-Service.ps1 в папке "Сценарии" в проекте приложения.
Ниже приведен пример сценария для образца агрегации данных, предоставленного Microsoft.
$cloud = $false
$singleNode = $true
$constrainedNodeTypes = $false
$lowkey = "-9223372036854775808"
$highkey = "9223372036854775807"
$countyLowKey = 0
$countyHighKey = 57000
$appName = "fabric:/DataAggregation"
$appType = "DataAggregationType"
$appInitialVersion = "1.0.0"
if($singleNode)
{
$webServiceInstanceCount = -1
$deviceCreationInstanceCount = -1
$countyServicePartitionCount = 1
$deviceActorServicePartitionCount = 1
$doctorServicePartitionCount = 1
}
else
{
$webServiceInstanceCount = @{$true=-1;$false=1}[$cloud -eq $true]
$deviceCreationInstanceCount = @{$true=-1;$false=1}[$cloud -eq $true]
$countyServicePartitionCount = @{$true=10;$false=5}[$cloud -eq $true]
$deviceActorServicePartitionCount = @{$true=15;$false=5}[$cloud -eq $true]
$doctorServicePartitionCount = @{$true=100;$false=5}[$cloud -eq $true]
if($constrainedNodeTypes)
{
$webServiceConstraint = "NodeType == "
$countyServiceConstraint = "NodeType == "
$nationalServiceConstraint = "NodeType == "
$deviceServiceConstraint = "NodeType == "
$doctorServiceConstraint = "NodeType == "
$deviceCreationServiceConstraint = "NodeType == "
}
else
{
$webServiceConstraint = ""
$countyServiceConstraint = ""
$nationalServiceConstraint = ""
$deviceServiceConstraint = ""
$doctorServiceConstraint = ""
$deviceCreationServiceConstraint = ""
}
}
$webServiceType = "DataAggregation.WebServiceType"
$webServiceName = "DataAggregation.WebService"
$nationalServiceType = "DataAggregation.NationalServiceType"
$nationalServiceName = "DataAggregation.NationalService"
$nationalServiceReplicaCount = @{$true=1;$false=3}[$singleNode -eq $true]
$countyServiceType = "DataAggregation.CountyServiceType"
$countyServiceName = "DataAggregation.CountyService"
$countyServiceReplicaCount = @{$true=1;$false=3}[$singleNode -eq $true]
$deviceCreationServiceType = "DataAggregation.DeviceCreationServiceType"
$deviceCreationServiceName = "DataAggregation.DeviceCreationService"
$doctorServiceType = "DataAggregation.DoctorServiceType"
$doctorServiceName = "DataAggregation.DoctorService"
$doctorServiceReplicaCount = @{$true=1;$false=3}[$singleNode -eq $true]
$deviceActorServiceType = "DeviceActorServiceType"
$deviceActorServiceName= "DataAggregation.DeviceActorService"
$deviceActorReplicaCount = @{$true=1;$false=3}[$singleNode -eq $true]
New-ServiceFabricService -ServiceTypeName $webServiceType -Stateless -ApplicationName $appName -ServiceName "$appName/$webServiceName" -PartitionSchemeSingleton -InstanceCount $webServiceInstanceCount -PlacementConstraint $webServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create national
New-ServiceFabricService -ServiceTypeName $nationalServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$nationalServiceName" -PartitionSchemeSingleton -MinReplicaSetSize $nationalServiceReplicaCount -TargetReplicaSetSize $nationalServiceReplicaCount -PlacementConstraint $nationalServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create county
New-ServiceFabricService -ServiceTypeName $countyServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$countyServiceName" -PartitionSchemeUniformInt64 -LowKey $countyLowKey -HighKey $countyHighKey -PartitionCount $countyServicePartitionCount -MinReplicaSetSize $countyServiceReplicaCount -TargetReplicaSetSize $countyServiceReplicaCount -PlacementConstraint $countyServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create doctor
New-ServiceFabricService -ServiceTypeName $doctorServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$doctorServiceName" -PartitionSchemeUniformInt64 -LowKey $lowkey -HighKey $highkey -PartitionCount $doctorServicePartitionCount -MinReplicaSetSize $doctorServiceReplicaCount -TargetReplicaSetSize $doctorServiceReplicaCount -PlacementConstraint $doctorServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create device
New-ServiceFabricService -ServiceTypeName $deviceActorServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$deviceActorServiceName" -PartitionSchemeUniformInt64 -LowKey $lowkey -HighKey $highkey -PartitionCount $deviceActorServicePartitionCount -MinReplicaSetSize $deviceActorReplicaCount -TargetReplicaSetSize $deviceActorReplicaCount -PlacementConstraint $deviceServiceConstraint -ServicePackageActivationMode ExclusiveProcess -Verbose
#create device creation
New-ServiceFabricService -ServiceTypeName $deviceCreationServiceType -Stateless -ApplicationName $appName -ServiceName "$appName/$deviceCreationServiceName" -PartitionSchemeSingleton -InstanceCount $deviceCreationInstanceCount -PlacementConstraint $deviceCreationServiceConstraint -ServicePackageActivationMode ExclusiveProcess