eBizTalk - Berichten, Unterhalten, Weiterbilden
Ob Branchendiskurs, Fachartikel oder ein Blick hinter die Unternehmenskulissen: eBizTalk ist die Plattform, die uns auffordert, unsere Leser über Events und Projekte auf dem Laufenden zu halten. Und uns gegenseitig natürlich auch.

BizTalk Deployment Framework - Fallstricke und Best Practices

Veröffentlicht am 31.10.2018 von Jean-Pierre Pereira , BizTalk , DevOps , BTDF

In einem unserer aktuellen Projekte haben wir uns gefragt, welche Art des Deployment wohl für BizTalk und seine Nebenkomponenten (z.B. Webservices) am besten geeignet ist. Da es sich um verteilte Systeme handelt, war die Herausforderung zunächst, für jede logische Komponente ein eigenes Paket in Form einer MSI zur Verfügung zu stellen. Diese sollen dann über ein Software-Verteilungssystem automatisiert installiert und bereitgestellt werden. Zur Umsetzung ist aus unserer Sicht das BizTalk Deployment Framework (kurz: BTDF) hervorragend geeignet. Wir möchten daher im Folgenden auf einige Fallstricke eingehen, welche während des Projekts aufgefallen sind und einige Best Practices herleiten.

Was ist BTDF?

BTDF ist ein Framework, welches zum Konfigurieren und zur Bereitstellung von BizTalk-Anwendungen verwendet werden kann. Ins Leben gerufen wurde es durch Thomas F. Abraham, wobei die Anwendung frei verfügbar und ein somit mittlerweile ein Community-Projekt ist. Mit dem Biztalk Deployment Framework ist es mittlerweile sehr einfach extrem komplexe Biztalk-Komponenten, wie Orchestrations oder Pipelines zu deployen. Der Admin muss zur Installation der Biztalk-Anwendungen und zugehöriger Artefakte keine manuellen Schritte mehr tätigen, sondern kann die Installation komplett automatisiert durchführen lassen.
Um einen Überblick über das BizTalk Deployment Framework zu erhalten, gibt es bereits eine große Anzahl an Quellen und Tutorials, weshalb wir in diesem Artikel darauf nicht näher eingehen wollen. Viel mehr beschäftigen wir uns mit Fragen, welche aus unserer Sicht nicht ausreichend dokumentiert sind und euch das Deployment etwas vereinfachen. Die Erkenntnisse, die wir im Laufe des Projekts gesammelt haben, beziehen sich alle auf die dort eingesetzte (und dokumentierte) Version 5.5 des BTDF. Ein Release-Datum von der Version 6.0 (aktuell im Beta-Stadium) ist noch nicht bekanntgegeben.

Vorenthalten möchten wir euch die Einführungen natürlich trotzdem nicht, daher hier ein paar Quellen für die, die sich erst einmal grundlegend mit BTDF vertraut machen möchten:

Aber genug einleitende Worte. Hier kommen nun unsere gesammelten Fallstricke und Best Practices zum Biztalk Deployment Framework:

Das Problem mit dem AppPool

Webservices anlegen

In der Version 5.5 des BizTalk Deployment Frameworks ist dokumentiert, dass evtl. bereitzustellende Webservices über die folgenden Einträge der ".btdfproj"-Datei zu hinterlegen sind:

1. "IncludeVirtualDirectories" auf den Wert "true" setzen:
<PropertyGroup>

<IncludeVirtualDirectories>true</IncludeVirtualDirectories>

<PropertyGroup>

2. Eine "VDirList"-ItemGroup hinterlegen:
<ItemGroup>
  <VDirList Include="*">
    <Vdir>MyVDirName</Vdir>
    <Physdir>..\MyVDir</Physdir>
    <AppPool>MyAppPool</AppPool>
    <AppPoolNetVersion>v4.0</AppPoolNetVersion>
  </VDirList>
</ItemGroup>

Natürlich funktioniert das nur, insofern ihr daran gedacht habt, alle Webservices mittels einem "Copy-Befehl" in die MSI zu integrieren. Denn wenn die Services beim Deployment-Vorgang auf dem Zielserver nicht vorhanden sind, können sie auch nicht veröffentlicht werden. Hier exemplarisch der entsprechende Copy-Befehl dazu:

<Target Name="CustomRedist">

  <MakeDir Directories="$(RedistDir)\TestFiles" />

  <CreateItem Include="..\TestFiles\**\*.*">

    <Output TaskParameter="Include" ItemName="TestFileSourceGroup" />

  </CreateItem>

  <Copy DestinationFolder="$(RedistDir)\TestFiles\%(RecursiveDir)" SourceFiles="@(TestFileSourceGroup)"/>

</Target>

Die WebServices werden auf diese Art und Weise vollkommen problemlos bereitgestellt. Der AppPool wird sogar fehlerfrei angelegt, insofern er nicht schon vorhanden ist - allerdings im PipeLine-Modus "Classic". Was aber tun wir, wenn wir den PipeLine-Modus auf "Integrated" stellen möchten? Klar - manuell geht das schnell. Aber das ist eben nicht der Sinn eines automatisierten Deployments. Zu viele Einzelschritte - vor Allem, wenn sie von Personen ausgeführt werden, die vielleicht weniger Fachkenntnis in diesem Bereich haben, führen potentiell zu Fehlern. Außerdem steigt der Aufwand mit der Anzahl der Webserver immens. Was also tun?

Die Lösung fand die Community mit der Veröffentlichung der Version 5.7. Hier erhält der Nutzer die volle Kontrolle über den IISAppPool:

https://github.com/BTDF/DeploymentFramework/blob/master/src/Samples/BizTalk/IIS/IIS.Deployment/IIS.Deployment.btdfproj

Falls ihr aber aus irgendeinem Grund eine andere Version des Deployment Frameworks benutzen wollt oder müsst, haben wir folgenden Workaround für euch:

BTDF bietet euch eine einfache Möglichkeit, externe Programme auszuführen - Powershell-Skripte eingeschlossen. Hier können wir die ganze Power von Powershell für uns nutzen, aber lasst uns Schritt für Schritt vorgehen:

1. Zunächst erstellen wir uns ein Powershell-Skript, welches die folgenden Eingangsparameter enthält:
param(
  [string] $WebSitePath,
  [string] $WebsiteName,
  [string] $AppName,
  [string] $AppPoolName,
  [string] $UserName,
  [string] $Password
)

Wieso ist das wichtig? Ganz einfach! Wir werden später im BTDF alle Parameter beim Aufruf des Skripts mitgeben. So können wir je nach Umgebung eine andere Webseite, Pfad usw. auswählen und müssen diese nicht manuell einpflegen. Weiterer Vorteil: Durch die Eingabe des AppNames können wir das selbe Skript für eine Vielzahl an unterschiedlichen Webservices einsetzen. Wir haben hier also eine generische Lösung. Den Rest kennt man sicherlich von anderen Deployment-Szenarien im Kontext von Webservices:

2. Wir erstellen zwei Funktionen, eine zum Bereitstellen des AppPools und eine zum Bereitstellen und Zuordnen der Services:

Function Add-IISAppool([string]$AppPoolName, [string]$UserName, [string]$Password)
{
  C:\Windows\system32\inetsrv\appcmd add apppool /name:$AppPoolName
  C:\Windows\system32\inetsrv\appcmd set apppool $AppPoolName /processModel.userName:$UserName /processModel.password:$Password
  C:\Windows\system32\inetsrv\appcmd set config /section:applicationPools "/[name='$AppPoolName'].processModel.identityType:SpecificUser"
}

Function Add-IISApp([string]$AppPoolName, [string]$SiteName, [string]$PhysicalPath, [string]$AppName)

{

  C:\Windows\system32\inetsrv\appcmd add app /site.name:$SiteName /path:/$AppName /physicalPath:$PhysicalPath

  C:\Windows\system32\inetsrv\appcmd set app "$SiteName/$AppName" /applicationPool:$AppPoolName

}


3. Nun können die Funktionen ganz normal abgerufen werden:


If (!Test-Path "IIS:\AppPools\$AppPoolName"))
{
  Add-IISApppool -AppPoolName $AppPoolName -UserName $UserName -Password $Password
}

If (Test-Path $WebsitePath\$AppName)
{
  Remove-Item -path $WebsitePath\$AppName\* -include *.publishproj -recurse

  If (Test-Path $WebsitePath\$AppName\App_Data )
  {
     Remove-Item -path $WebsitePath\$AppName\App_Data -recurse
  }

  Add-IISApp -SiteName:$WebsiteName -AppName:$AppName-AppPoolName:$AppPoolName -PhysicalPath:$WebsitePath\$AppName
}

So haben wir eine einfache Lösung unsere Services und die zugehörigen AppPools auf die gewünschten Server zu deployen und dabei so flexibel wie möglich zu bleiben. Der AppPool ist daraufhin mit dem Pipeline-Modus "Integrated" erstellt, womit wir unser Ziel erreicht haben. Und noch viel mehr: Dadurch, dass der Write-Host Output während des Deployments seitens BTDF mit ausgegeben wird, sind wir im Bereich Logging maximal flexibel. Man könnte beispielsweise hinter jedem Einzelschritt einen entsprechenden Text ausgeben.

Wie die Integration seitens BTDF aussieht, könnt ihr ganz einfach im oben aufgeführten Wiki nachlesen.

Wohin mit der Business-Rule-Engine?

Da wir, wie oben erwähnt, über verteilte Systeme sprechen, ist diese Frage nach der Rules Engine absolut berechtigt. Ich persönlich war am Anfang davon ausgegangen, dass die Business-Rules ganz einfach zusammengefasst in einem Teil des Deployments implementiert werden sollten. Was aber, wenn ein Teil des Projekts auf einem anderen Server bereitgestellt werden soll? Die Business Rule würde nicht mehr greifen und unsere Nachrichten würden in der MessageBox versauern!
Es ist daher unsere Empfehlung, pro Fachapplikation ein eigenes Business-RuleSet zu erstellen und letztlich auch zu deployen. Gemeinsam genutzte Komponenten, wie z.B. eine Orchestration, werden in einer Biztalk-Applikation deployed. Fachspezifische Artefakte (z.B. ein für einen fachlichen UseCase spezifischer SendPort) erhalten dann wiederum eine eigene Applikation. Und jede Applikation erhält Ihre eigenen Business Rules. Das verspricht die maximale Flexibilität während des Deployments.

Übrigens: Falls ihr euch auch wundern solltet, weshalb eure Business Rule zwar published, aber nicht deployed werden. Ihr müsst die MSBuild-Property "ExplicitlyDeployRulePoliciesOnDeploy" auf den Wert "true" setzen. Das wird leicht übersehen, da im Wiki nur das Publishing näher beschrieben und der Deployment-Vorgang nur referenziert wird.

Wie erstelle ich Hosts, Hostinstanzen und Adapter?

Zwar bietet BTDF die Möglichkeit Hostinstanzen neuzustarten - eine Neuanlage inkl. Der dazugehörigen Adapter wird bis dato jedoch nicht unterstützt. Wie im Fall der WebServices müssen wir uns auch hier eine eigene Lösung überlegen und was bietet sich hier besser an als das zu nutzen, was wir sowieso schon im Einsatz haben? Richtig, das bedeutet Hosts, Hostinstanzen und Adapter, können wir ohne Probleme mithilfe von Powershell erstellen und vom BizTalk Deployment Framework aus aufrufen. Dabei sollten wir wieder darauf achten, das Skript so generisch wie möglich zu halten. Aufgerufen werden die Skripte genauso wie die Skripte der WebServices. Ein genaues Tutorial hierzu findet ihr im referenzierten Wiki am Anfang des Artikels.
Wie bereits erwähnt, wollen wir ein hohes Maß an Generalität erzeugen, weshalb wir im ersten Schritt wieder unsere altbekannten Parameter in das Powershell-Skript einfügen. Wir werden hier beispielhaft einen Receive-Host inklusive Hostinstanz und WCF-WebHTTP Adapter erstellen.


Parameter hinterlegen:

param(

[string] $Isolated_UserName,

[string] $Isolated_Password,

[string] $InProc_UserName,

[string] $InProc_Password,

[string] $BTSPath)

Warum haben wir hier zwei unterschiedliche User-Variablen in unserem Skript? Das liegt daran, dass wir einen Adapter erstellen, welcher im "Isolated-Mode" (WCF-WebHTTP) agiert und uns offen halten wollen einen weiteren Adapter, welcher im "InProcess-Mode" (WCF-BasicHTTP) agiert zu erstellen.


Powershell Extensions für BizTalk:

Für die Kommunikation mit BizTalk existiert bereits eine Extension für Powershell, das vereinfacht die Arbeit um ein Vielfaches. Bevor wir unsere Befehle also ausführen können, müssen wir die Extension einfügen, welche sich unter dem BizTalk-Installationspfad befindet:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe $BTSPath"SDK\Utilities\PowerShell\BizTalkFactory.Powershell.Extensions.dll"

Jetzt noch aktivieren:

Add-PSSnapin -Name BizTalkFactory.Powershell.Extensions

Und nun können wir auf alle Funktionen der Extension zugreifen und mit der eigentlichen Ausführung beginnen. Das funktioniert dann wie folgt: Wir erstellen uns ein Powershell-Drive und bewegen uns anschließend darin, um zu den einzelnen Zielen, wie den Hosts, in BizTalk zu gelangen.


PSDrive und Hosts erstellen:

Mit dem ersten Befehl erstellen wir unseren PSDrive.

$Server = (Get-ItemProperty "hklm:SOFTWARE\Microsoft\Biztalk Server\3.0\Administration").MgmtDbServer

New-PSDrive -Name BizTalk -Root BizTalk:\ -PsProvider BizTalk -Instance $Server -Database BizTalkMgmtDb

Set-Location -Path BizTalk

Um jetzt in diesem Drive den „Ordner“ zu wechseln und z.B. im Bereich der Hosts zu arbeiten, wechseln wir den Pfad wie folgt

Set-Location -Path 'Platform Settings\Hosts'

Die Hosts können wir dann unter diesem Pfad wie folgt erstellen:

$HostGroupName = Get-ItemProperty -Path 'BizTalkServerIsolatedHost' -Name 'NtGroupName'

New-Item ReceiveHost -NtGroupName $HostGroupName.NtGroupName -HostType 'Isolated'

Set-ItemProperty -Path ReceiveHost -name 'Is32BitOnly' -Value 'False'

Jetzt haben wir in unserem Beispiel einen Isolated-Host erstellt und die Beschränkung auf 32-Bit ausgeschaltet. Das Vorgehen für die Adapter, sowie der Hostinstanzen ist ähnlich. Die Besonderheit an den Hostinstanzen ist allerdings, dass wir an dieser Stelle bereits die Zugangsdaten hinterlegen müssen. Dies sieht dann in etwa wie folgt aus:

$IsolatedPassword = ConvertTo-SecureString -String $Isolated_Password -AsPlainText -Force

$IsolatedCredentials = New-Object -TypeName:System.Management.Automation.PsCredential -ArgumentList $Isolated_UserName, $IsolatedPassword

New-Item -Path:'HostInstance' -HostName:ReceiveHost -Credentials:$HostisoCredentials


Erstellen eines WCF-WebHTTP Adapter:

New-Item -Path .\ReceiveHost -Hostname ReceiveHost -Direction Receive

Es ist wichtig daran zu denken, immer vorab den Pfad - wie weiter oben bereits erwähnt - zu ändern, ansonsten läuft die Anforderung ins Leere. Die Pfade sind hierbei äquivalent zu den Bereichen der Biztalk Management Console.
Leider ist die Extension im World Wide Web nicht so gut dokumentiert wie das BTDF. Allerdings findet man eine kleine Readme-Datei unter dem Installationspfad des BizTalk-Servers, hier sind nicht nur die verfügbaren Befehle hinterlegt, sondern auch eine kleine Installationsanweisung der Extension.

Und wie deploye ich das nun ohne die MSI manuell zu bedienen?

Im Best Case seid ihr nun an den Punkt angekommen, an dem ihr zumindest eine MSI habt, welche ihr nun auf euren Ziel-Server ausführen lassen möchtet. Eingangs hatte ich beschrieben, dass sowas idealerweise durch ein Softwareverteilungsprogramm geschieht, allerdings kann dieses Programm sich nicht durch die Installationsroutine der MSI klicken, was also tun?

MSI unterstützt standardmäßig Befehlszeilenargumente. Das bedeutet, dass ihr euch für das Deployment beispielsweise eine kleine Batch-Datei schreiben könnt, die das Deployment automatisiert vornimmt. Diese kopiert ihr einfach gemeinsam mit der MSI auf das Zielsystem und führt sie aus. Aber Achtung: Da ihr im Befehlszeilenargument eine bestimmte Umgebung bzw. ein bestimmtes Settings-File für eure Umgebung auswählt, benötigt ihr für jede Umgebung eine eigene Batch-Datei.

Ich zeige euch nun in kleinen Schritten exemplarisch, wie ihr eine Batch-Datei für ein bestimmtes Environment definiert.


Installation ausführen:

@echo off

msiexec.exe /I /YourGreatBizTalkApplication.msi

/log YourGreatLog.log /passive

INSTALLDIR="C:\Program Files\YourGreatBizTalkApplication\1.0"

Bevor wir etwas deployen, muss natürlich die Applikation installiert werden. Ich habe hierfür den Pfad "…/Program Files/" gewählt - aber letztlich, bleibt das euch überlassen. Bitte denkt daran "YourGreatBizTalkApplication.msi" durch den Namen eurer MSI zu ersetzen.


Settings exportieren:

Im nächsten Schritt exportiert ihr alle eure Environment-Settings vom SettingsFileGenerator.xml in das Ziel-Verzeichnis. Ihr benötigt diesen Schritt, um beim Deployment die richtige Datei und somit das richtige Environment wählen zu können. Die MSI kann leider nicht anhand der XML entscheiden, welches Environment das Richtige ist:

"C:\Program Files\YourGreatBizTalkApplication\1.0\Deployment\Framework\DeployTools\EnvironmentSettingsExporter.exe"

"C:\Program Files\YourGreatBizTalkApplication\1.0\Deployment\EnvironmentSettings\SettingsFileGenerator.xml"

"C:\Program Files\YourGreatBizTalkApplication\1.0\Deployment\EnvironmentSettings"


Application deployment:

Nun können wir unsere Applikation deployen, alle Vorbereitungen dafür sind ja bereits getroffen. Hierzu verwenden wir die MSBuild.exe, welche standardmäßig im angegebenen Pfad installiert sein sollte.

"%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"

/p:DeployBizTalkMgmtDB=true;Configuration=Server;SkipUndeploy=true /target:Deploy

/l:FileLogger, Microsoft.Build.Engine;logfile="C:\Program Files\YourGreatBizTalkApplication\1.0\DeployResults\DeployResult.txt"

"C:\Program Files\YourGreatBizTalkApplication\1.0\Deployment\Deployment.btdfproj"

/p:ENV_SETTINGS:"C:\Program Files\YourGreatBizTalkApplication\1.0\Deployment\EnvironmentSettings\Exported_Test_Settings.xml"

Damit sind alle Schritte getan und mit einem Klick auf die Batch-Datei sollte nun die MSI ausgeführt und die Applikation bereitgestellt werden.

Unsere Erfahrungen mit dem Biztalk Deployment Framwork waren durchweg positiv. Natürlich gibt es einige Fallstricke. Aber diese sind verglichen mit einem manuellen oder ggf. alternativen Deployment zu vernachlässigen – BTDF vereinfacht die Bereitstellung eurer Anwendungen enorm. Sicherlich werden uns in Folgeprojekten weitere Fallstricke auffallen – denn wir werden das Framework weiterverwenden. Sobald wir diese gefunden haben, könnt ihr genau hier nach unseren Erkenntnissen suchen (und sie finden).

google_about_ebiz fb_about_ebiztwitter_about_ebizxing_about_ebiz
ebiz_consulting_expertise