Windows Service in Docker container - docker

I am looking at possible dockerisation of an application. The application includes multiple Windows Services (.NET WCF). I am yet to try out creating a dockerfile for the windows services. But shall appreciate if someone may provide me with some pointer whether this works well.

In your situation, I'd probably create one image for each Windows Service.
The following Dockerfile works well for me in building a Windows Service into a docker image.
All your service files need to be in the 'Installs' folder of the docker context, plus a copy of the InstallUtils.exe file (from .NET / Visual Studio).
# escape=\
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.7.2-windowsservercore-1709
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
COPY ["Installs/", "/Service/"]
WORKDIR "C:/Service/"
RUN "C:/Service/InstallUtil.exe" /LogToConsole=true /ShowCallStack SmartFormsToWorkInjuryReportingService.exe; \
Set-Service -Name "\"My Windows Service Name\"" -StartupType Automatic; \
Set-ItemProperty "\"Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\My Windows Service Name\"" -Name AllowRemoteConnection -Value 1
ENTRYPOINT ["powershell"]
CMD Start-Service \""My Windows Service Name\""; \
Get-EventLog -LogName System -After (Get-Date).AddHours(-1) | Format-List ;\
$idx = (get-eventlog -LogName System -Newest 1).Index; \
while ($true) \
{; \
start-sleep -Seconds 1; \
$idx2 = (Get-EventLog -LogName System -newest 1).index; \
get-eventlog -logname system -newest ($idx2 - $idx) | sort index | Format-List; \
$idx = $idx2; \
}
FYI, you can then run the service by:
docker run --rm --net=MyNet --platform=windows -p 80:80 --name MyWindowsServiceContainer mywindowsserviceimage

Related

Gitlab CICD cannot add service

For my projects I sometimes need to unittest my code against a ms sql server.
At the moment, I created a monstrous docker image, containing all the tools I need, including the sql server.
Now this image got to about 15 GB in size, which is really not cool.
So I'm trying to use the GitLab CICD Service part (as described here https://docs.gitlab.com/ee/ci/services/index.html).
But when I'm trying to add my (custom) image as a service I keep getting the health check issue:
*** WARNING: Service runner-hrtjgacu-project-1489-concurrent-0-2ae3f3cd2099f19a-gitlab.mydomain.lcaol__windowsdockerimages__mssql-0 probably didn't start properly.
Health check error:
service "runner-hrtjgacu-project-1489-concurrent-0-2ae3f3cd2099f19a-gitlab.mydomain.local__windowsdockerimages__mssql-0-wait-for-service" health check: exit code 1
Health check container logs:
2023-01-19T09:58:09.913696500Z FATAL: No HOST or PORT found
Service container logs:
*********
Now I found something online about needing to expose the ports of the service in the Dockerfile, so I tried that, but that did not help.
This is what my MSSQL DockerFile currently looks like:
FROM mcr.microsoft.com/windows/servercore:ltsc2019
# Download Links:
ENV exe "https://go.microsoft.com/fwlink/?linkid=840945"
ENV box "https://go.microsoft.com/fwlink/?linkid=840944"
ENV sa_password="_" \
attach_dbs="[]" \
ACCEPT_EULA="Y" \
sa_password_path="C:\ProgramData\Docker\secrets\sa-password"
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
# make install files accessible
COPY start.ps1 /
WORKDIR /
RUN Invoke-WebRequest -Uri $env:box -OutFile SQL.box ; \
Invoke-WebRequest -Uri $env:exe -OutFile SQL.exe ; \
Start-Process -Wait -FilePath .\SQL.exe -ArgumentList /qs, /x:setup ; \
.\setup\setup.exe /q /ACTION=Install /INSTANCENAME=MSSQLSERVER /FEATURES=SQLEngine /UPDATEENABLED=0 /SQLSVCACCOUNT='NT AUTHORITY\System' /SQLSYSADMINACCOUNTS='BUILTIN\ADMINISTRATORS' /TCPENABLED=1 /NPENABLED=0 /IACCEPTSQLSERVERLICENSETERMS ; \
Remove-Item -Recurse -Force SQL.exe, SQL.box, setup
RUN stop-service MSSQLSERVER ; \
set-itemproperty -path 'HKLM:\software\microsoft\microsoft sql server\mssql14.MSSQLSERVER\mssqlserver\supersocketnetlib\tcp\ipall' -name tcpdynamicports -value '' ; \
set-itemproperty -path 'HKLM:\software\microsoft\microsoft sql server\mssql14.MSSQLSERVER\mssqlserver\supersocketnetlib\tcp\ipall' -name tcpport -value 1433 ; \
set-itemproperty -path 'HKLM:\software\microsoft\microsoft sql server\mssql14.MSSQLSERVER\mssqlserver\' -name LoginMode -value 2 ;
HEALTHCHECK CMD [ "sqlcmd", "-Q", "select 1" ]
EXPOSE 1433/tcp
EXPOSE 4022/tcp
EXPOSE 135/tcp
EXPOSE 1434/tcp
EXPOSE 1434/udp
CMD .\start -sa_password $env:sa_password -ACCEPT_EULA $env:ACCEPT_EULA -attach_dbs \"$env:attach_dbs\" -Verbose
And this is is my .gitlab-ci.yml file:
default:
image:
name: gitlab.mydomain.local:4567/windowsdockerimages/basicnetframeworkimage:latest
tags:
- windows
- docker
# The stages during this build
stages:
- build
build:
stage: build
script:
- echo "Hello world"
- ping mssql
- dotnet run
services:
- name: gitlab.mydomain.local:4567/windowsdockerimages/mssql
alias: mssql
Anyone who can help me get closer to the solution?
*Note, the ping mssql also fails, the container in which we run cannot find the DNS
entry
I would use an existing official image for MSSQL server (https://hub.docker.com/_/microsoft-mssql-server) and run unit tests in one container and the database in another one.

Need Uri for Activeperl installation in docker

For my use case, I need to create a windows container of Activeperl application. I found a GitHub link which explains the process for a Strawberry Perl.
Code snippet from the link
RUN \
if(!(Test-Path -Path 'C:\Temp')) \
{ \
New-Item \
-Path 'C:\Temp' \
-ItemType Directory \
-Verbose | Out-Null ; \
} ; \
\
Invoke-WebRequest \
-Uri "http://strawberryperl.com/download/$ENV:PERL_VERSION/strawberry-perl-$ENV:PERL_VERSION-64bit.zip" \
-OutFile "C:\\Temp\\strawberry-perl-$ENV:PERL_VERSION-64bit.zip" \
-UseBasicParsing \
-Verbose ; \
\
Expand-Archive \
-Path "C:\\Temp\\strawberry-perl-$ENV:PERL_VERSION-64bit.zip" \
-DestinationPath 'C:\Program Files\Perl' \
-Verbose ; \
\
Set-ItemProperty \
-Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment' \
-Name 'Path' \
-Value $($ENV:Path + ';C:\Program Files\Perl\perl\bin;C:\Program Files\Perl\perl\site\bin;C:\Program Files\Perl\c\bin') \
-Verbose ;
Strawberryperl Uri - http://strawberryperl.com/download/$ENV:PERL_VERSION/strawberry-perl-$ENV:PERL_VERSION-64bit.zip
For me, I want an equivalent Uri for downloading Activeperl instead of Strawberryperl. I am even ok with a Windows Container Image with activeperl installed already. I just couldn't find any of them.
Since ActivePerl doesn't provide an option for downloading a zipped version of Perl.
This is how I was able to transfer an active Perl to a Windows container
In my host windows machine, I have downloaded the Active Perl from https://activeperl.software.informer.com/download/
The downloaded file is ActivePerl-5.28.1.0000-MSWin32-x64-e90bcbf1.msi
I have installed this at the location C:\Perl64\
Copied this Perl64 folder into a new folder called Perl_root, so that this can be copied into the container via Dockerfile. Create a file called Dockerfile in the same location as Perl_root.
Filesystem_Root
C:\
|__ docker_trial
|___ Perl_root
|___ Dockerfile
Dockerfile:
#pulled a windows container from docker hub
FROM mcr.microsoft.com/windows/servercore:1607-amd64
ADD Perl_root .
Open a command prompt and navigate to the folder where dockerfile is present.
>docker build --tag dockertrail:1.0 .
>docker run -it --name tag1 dockertrail:1.0
Once the terminal inside the docker container opens up, open a PowerShell and create the update the environment variable Path as below
Powershell>[Environment]::SetEnvironmentVariable("Path",$env:Path+"C:\Perl64\site\bin;C:\Perl64\bin","Machine")
exit from the PowerShell and container. Now restart the container tag1, for the environment variable to work.
start the container tag1 again, once it starts, open up a PowerShell and run the command $env:Path you must be able to see the perl path being added to environment variables.
Now check the functioning of Perl using the command perl -v
This should print the perl verion.

Dockerizing a Windows Service

I am new to docker and I have an application including a set of windows services (.NET). I d like to run it into a docker container. What should I do ?
I have successfully put a Windows Service into a docker container using the following Dockerfile. Replace MyWindowsServiceName with the name of your own windows service.
# escape=\
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.7.2-windowsservercore-1709
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
COPY ["MyWindowsServiceName/bin/Release/", "/Service/"]
WORKDIR "C:/Service/"
RUN "C:/Service/InstallUtil.exe" /LogToConsole=true /ShowCallStack MyWindowsServiceName.exe; \
Set-Service -Name "\"MyWindowsServiceName\"" -StartupType Automatic; \
Set-ItemProperty "\"Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MyWindowsServiceName\"" -Name AllowRemoteConnection -Value 1
ENTRYPOINT ["powershell"]
CMD Start-Service \""MyWindowsServiceName\""; \
Get-EventLog -LogName System -After (Get-Date).AddHours(-1) | Format-List ;\
$idx = (get-eventlog -LogName System -Newest 1).Index; \
while ($true) \
{; \
start-sleep -Seconds 1; \
$idx2 = (Get-EventLog -LogName System -newest 1).index; \
get-eventlog -logname system -newest ($idx2 - $idx) | sort index | Format-List; \
$idx = $idx2; \
}
NOTE1: My windows service logs to the Windows Event system. So this file contains some nice code at the end to print EventLog information to the console, as per Docker convention. You may or may not need this part for your own service. If not, only use the first line minus the '\'.
NOTE2: The name of a windows service may be different to its executable name. That is, 'MyWindowsServiceName.exe' could have a service name of 'My Windows Service Name' or 'Fred', you need to know both.
Starting from the answer provided by QA Collective, this is what worked for me.
Note 1 No InstallUtil.exe required
Note 2 the "Get-Event..." part from the last part of the code is just to keep the process alive so that the container will continue to run.
Note 3 You can set the StartupType as automatic and remove the Start-Service from the CMD.
Note 4 When you provide the BinaryPathName Make sure to provide the FULL PATH. It stores it in the registries and if you provide a relative path, it won't know where to run it from and you'd get some nasty errors that will make you cry - what happened to me.
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
COPY ["Release/", "/Service/"]
WORKDIR "C:/Service/"
RUN New-Service -Name "\"MyService"\" -StartupType "\"Manual"\" -BinaryPathName "\"C:\\Service\\MyService.exe"\";
ENTRYPOINT ["powershell"]
cmd Start-Service "MyService"; \
Get-EventLog -LogName System -After (Get-Date).AddHours(-1) | Format-List ;\
$idx = (get-eventlog -LogName System -Newest 1).Index; \
while ($true) \
{; \
start-sleep -Seconds 1; \
$idx2 = (Get-EventLog -LogName System -newest 1).index; \
get-eventlog -logname system -newest ($idx2 - $idx) | sort index | Format-List; \
$idx = $idx2; \
}
In general, you should choose a base image which has the necessary libraries already installed on it as much as possible instead of taking a very base image such as plain Linux or Windows and installing on it.
In your case, select a docker image which has .NET installed on it.This image for instance The ideal flow is as follows.
Select the Docker Image you want to use
Include a Dockerfile in the root location of your project
Include commands in Dockerfile to copy the code or the executable on to the image
Specify a start command
Build the Image docker build -t YourRepoName . Run this at the location of your Dockerfile
Test it docker run YourImage
Dockerfile This is one of the dockerfiles I wrote for Springboot. You may use it for reference. Please note, I am copy only the jar file here onto my Container and not the source code since at the point of building the docker container, the jar file is available. You may choose to include commands for copying the source code and creating the executable inside the Dockerfile.

How to Dockerize windows application

i have a windows application which I want to containerize. Its a windows desktop application (not web application). I did some searching and found very little about containerizing desktop application. The application which I want to containerize works fine on WindowsServerCore. I have Windowsservercore image on my machine.
I want to know how can I go about containerizing it. Any documentation or useful videos are available?
when i completed dockerfile can i interact with my application gui??? how???
You can find tons of example of WindowsServiceCore-based applications in StefanScherer/dockerfiles-windows
You need to write a Dockerfile (like for instance diskspd/Dockerfile where you copy/unzip/install the application you need.
FROM microsoft/windowsservercore:10.0.14393.1770
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV DISKSPD_VERSION 2.0.17
RUN Invoke-WebRequest $('https://gallery.technet.microsoft.com/DiskSpd-a-robust-storage-6cd2f223/file/152702/1/Diskspd-v{0}.zip' -f $env:DISKSPD_VERSION) -OutFile 'diskspd.zip' -UseBasicParsing ; \
Expand-Archive diskspd.zip -DestinationPath C:\ ; \
Remove-Item -Path diskspd.zip ; \
Remove-Item -Recurse armfre ; \
Remove-Item -Recurse x86fre ; \
Remove-Item *.docx ; \
Remove-Item *.pdf
ENTRYPOINT [ "C:\\amd64fre\\diskspd.exe" ]
That being said, a full GUI support for windowscoreserver is still requested:
"Create base container with full GUI support".

DockerFile executing powershell file cannot be found

I'm attempting to get an asp.net MVC application running using docker for windows. Which I've configured to use windows containers.
I'm using VS2017 to add docker support which generates the DockerFile and the docker-compose project.
The default DockerFile consists of:
FROM microsoft/aspnet:4.6.2
ARG source
WORKDIR /inetpub/wwwroot
COPY ${source:-obj/Docker/publish} .
Creating an image configured to run IIS with .net 4.6.2
This works fine, however I need to configure SSL. Using this example (https://github.com/MicrosoftDocs/Virtualization-Documentation/blob/live/windows-container-samples/iis-https/Dockerfile) and changing my file to:
FROM microsoft/aspnet:4.6.2
ARG source
WORKDIR /inetpub/wwwroot
COPY ${source:-obj/Docker/publish} .
RUN powershell.exe -Command " \
Import-Module IISAdministration; \
$cert = New-SelfSignedCertificate -DnsName demo.contoso.com -CertStoreLocation cert:\LocalMachine\My; \
$certHash = $cert.GetCertHash(); \
$sm = Get-IISServerManager; \
$sm.Sites[\"Default Web Site\"].Bindings.Add(\"*:443:\", $certHash, \"My\", \"0\"); \
$sm.CommitChanges();"
Works fine. However this is a self-signed cert and I wish to use a cert I copy to the image that I can also install into my cert store on my own machine for it to be trusted.
I've changed the DockerFile to:
FROM microsoft/aspnet:4.6.2
ARG source
WORKDIR /inetpub/wwwroot
COPY ${source:-obj/Docker/publish} .
WORKDIR /
COPY ${source:-server.pfx} ./server.pfx
RUN powershell.exe ls;
RUN powershell.exe -executionpolicy bypass -Command " \
Import-Module WebAdministration; \
$pwd = ConvertTo-SecureString -String \"server\" -Force -AsPlainText; \
Import-PfxCertificate -CertStoreLocation \"cert:\\LocalMachine\\Root\\b455d81e2414ec1da38f4de105b98066506cf86e\" -Password $pwd -FilePath \"c:\\server.pfx\"; \
Import-PfxCertificate -CertStoreLocation \"cert:\\LocalMachine\\My\\b455d81e2414ec1da38f4de105b98066506cf86e\" -Password $pwd -FilePath \"c:\\server.pfx\"; \
$cert = Get-Item "cert:\LocalMachine\My\b455d81e2414ec1da38f4de105b98066506cf86e"; \
New-WebBinding -Name \"Default Web Site\" -Protocol \"https\" -IPAddress \"*\" -Port 443; \
New-Item \"IIS:\\SslBindings\\0.0.0.0!443\" -Value $cert;"
Which feels like it should work. The powershell ls command shows the server.pfx file sitting on the c: drive of the container. However when it runs the powershell command setting up the certificate it errors saying it cannot find the file.
I've also run into issues where I've put the powershell into an actual script file, copied it onto the container, executed it, its all gone through fine but nothing seems to have happened.
If I use this chaps docker hub image it works as expect and he's using an actual powershell file:
https://hub.docker.com/r/rgarita/aspnet-ssl/
https://github.com/rgarita/aspnet-ssl-docker/tree/master/4.6.2
I'm at a bit of a loss with this, not sure if anyone has any ideas or have already gone through pain similar to this?
Thanks in advance,
Jon

Resources