Can a Service Fabric Aplication be deployed from within a Windows Docker Container to a cluster? Can a Service Fabric Aplication be deployed from within a Windows Docker Container to a cluster? docker docker

Can a Service Fabric Aplication be deployed from within a Windows Docker Container to a cluster?


Update:

Service Fabric SDK 3.3.617 released as part of Service Fabric 6.4 can now be installed in containers to build and deploy Service Fabric projects. This can be done in a Dockerfile using the following:

ADD https://download.microsoft.com/download/D/D/D/DDD408E4-6802-47FB-B0A1-ECF657BEB35F/MicrosoftServiceFabric.6.4.617.9590.exe C:\TEMP\MicrosoftServiceFabricRuntime.exeADD https://download.microsoft.com/download/D/D/D/DDD408E4-6802-47FB-B0A1-ECF657BEB35F/MicrosoftServiceFabricSDK.3.3.617.msi C:\TEMP\MicrosoftServiceFabricSDK.msiRUN C:\TEMP\MicrosoftServiceFabricRuntime.exe /accepteula /sdkcontainerclient /quietRUN msiexec.exe /i "C:\TEMP\MicrosoftServiceFabricSDK.msi" /qn 

Here is an example Dockerfile

Original Answer:

Turns out, this is no small feat. This script requires the Windows Service Fabric SDK to be installed. The recommended (and only supported) way to install the Service Fabric SDK is through WebPI, which is available here. It's possible to Dockerize the WebPI, however there's a problem. The WebPI installer consists of three components; the Service Fabric SDK, the Service Fabric Runtime, and the Service Fabric Tools for Visual Studio. The WebPI installer will install all of them. Unfortunately, the Service Fabric Runtime (as of this writing) cannot run under a Docker container since it wants to install a kernel level driver. This bug is being tracked here, but has been open for nearly a year with no real progress. This means that one could not run a Service Fabric cluster within a Docker container, but surely the SDK and tools should still be able to run, correct? Unfortunately, there is no way to tell the installer to only install the SDK and tools, but not the runtime.

So, perhaps there is an unsupported way to install just the SDK and tools. Turns out, the release notes have references to various MSIs for the individual components.

SDK Available Here

Tools for Visual Studio Available Here

It's fairly trivial to run msiexec.exe from a Dockerfile, which means we should be able to install the SDK that way. Nope. Unforunately, msiexec will fail with a generic 1603 code. If you run msiexec in verbose mode and output a log file, you can dig into this error and see the root cause:

MSI (s) (78:34) [19:07:56:049]: Product: Microsoft Azure Service Fabric SDK -- This product requires Service Fabric Runtime to be installed.

This product requires Service Fabric Runtime to be installed. Action ended 19:07:56: LaunchConditions. Return value 3.

So, we're once again shot down. I've found no other packaged version of the Service Fabric SDK (Chocolatey has one, but it just launches the WebPI installer) which leaves one final solution; we install the SDK manually without the help of an installer. This requires reverse engineering exactly what the installer does, and integrating this into our Dockerfile.

The SDK installer does a few things. It copies a bunch of files into c:\program files\microsoft sdks\service fabric\ and a bunch of files into c:\program files\microsoft service fabric\. It also GAC's a bunch of stuff (Such as System.Fabric.dll), adds some stuff to the registry, and also installs a Powershell module. We need to do all those things for the script to run.

What I ended up doing is mounting the key folders as Docker volumes so I can use them within my container:

docker run `  -v 'c:\program files\microsoft sdks\service fabric\tools\psmodule\servicefabricsdk:C:\ServiceFabricModules' `  -v 'c:\program files\microsoft service fabric\bin\fabric\fabric.code:C:\ServiceFabricCode' `  -v 'c:\program files\microsoft service fabric\bin\servicefabric:C:\ServiceFabricBin' `  -e ModuleFolderPath=C:\ServiceFabricModules `  -it build-agent powershell

First, I need to share out the c:\program files\microsoft sdks\service fabric\tools\psmodule\servicefabricsdk directory which contains the Powershell module that the Deploy-FabricApplication.ps1 script loads:

Import-Module "$ModuleFolderPath\ServiceFabricSDK.psm1"

Next, we need to share out c:\program files\microsoft service fabric\bin\fabric\fabric.code because it has a bunch of DLLs that the installer GACs.

Lastly, we share out c:\program files\microsoft service fabric\bin\servicefabric because that directory contains the PowerShell module installed by the SDK.

When the container starts, we need to do the following:

First, register the module with PowerShell:

Copy-Item C:\ServiceFabricBin C:\windows\system32\WindowsPowerShell\v1.0\modules\ServiceFabric -Recurse

After you do this, Get-Module -ListAvailable will show the ServiceFabric module. However, no exports will be loaded because it's missing a bunch of DLLs. The installer puts those DLLs in the GAC, but the GAC is dumb so let's just put those DLLs in the same directory so the module finds them:

Copy-Item C:\ServiceFabricCode\System.Fabric*.dll C:\windows\system32\WindowsPowerShell\v1.0\modules\ServiceFabric -Recurse

After this, you should be able to run Get-Module -ListAvailable and see the ServiceFabric module fully loaded.

There's one final thing to do. The Deploy-FabricApplication.ps1 script imports the ServiceFabricSDK.psm1 module (see above). But what is $ModuleFolderPath? Well, the script by default looks in the registry for this value, which of course the installer sets for you. We don't want to muck with the registry for our Docker image, so let's just change the script to look at an environment variable instead:

$ModuleFolderPath = $ENV:ModuleFolderPathImport-Module "$ModuleFolderPath\ServiceFabricSDK.psm1"

Now we can set that environment variable when we run our Docker container (or from our Dockerfile). Obviously, if you didn't want to modify the Deploy-FabricApplication.ps1 file, you could set this at HKLM:\SOFTWARE\Microsoft\Service Fabric SDK\FabricSDKPSModulePath as well. I'm fairly anti-registry so an environment variable (or just hard code if you really don't care) makes more sense to me.

Also note you'll need to import your certificate (Which you can download from the Key Vault in the form of a PFX file) before the script will deploy:

Import-PfxCertificate -Exportable -CertStoreLocation Cert:\CurrentUser\My\ -FilePath C:\Certs\MyCert.pfx

I believe a more production quality version of this would be to copy the required files into the image within your Dockerfile rather than mount them as volumes so the image would be more self contained, but that should be fairly straight forward. Also, I believe the DLLs that were GAC'ed are also available on NuGet, so it could be possible to download all those files through NuGet during the Docker build process.

Also, here's my full Dockerfile which I've successfully deployed an app to Service Fabric using:

# escape=`FROM microsoft/dotnet-framework:4.7.1SHELL ["cmd", "/S", "/C"]# Install Visual Studio Build ToolsADD https://aka.ms/vs/15/release/vs_buildtools.exe C:\SETUP\vs_buildtools.exeRUN C:\SETUP\vs_buildtools.exe --quiet --wait --norestart --nocache `    --add Microsoft.VisualStudio.Workload.AzureBuildTools ` || IF "%ERRORLEVEL%"=="3010" EXIT 0SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]# Our Deploy CertsADD ./Certs/ C:\Certs\# Update Path (I forget if this was needed for something)RUN SETX /M PATH $($Env:PATH + ';C:\ServiceFabricCode')

I'm hoping this helps someone, but more so I'm hoping Microsoft fixes their installer to remove the runtime requirement.


Best way to install Azure service fabric is by creating a poweshell file and call it from dockerfile

PowershellFile:

Start-Process "msiexec" -ArgumentList '/i', 'C:/app/WebPlatformInstaller_amd64_en-US.msi', '/passive', '/quiet', '/norestart', '/qn' -NoNewWindow -Wait; & "C:\Program Files\Microsoft\Web Platform Installer\WebPICMD.exe" /Install /Products:MicrosoftAzure-ServiceFabric-CoreSDK /AcceptEULA

Dockerfile :

RUN powershell -noexit "& ""./InstallServiceFabric.ps1"""