Example: Cireson SCSM Portal on Docker Windows Containers

Joe_BurrowsJoe_Burrows Cireson Devops Super IT Monkey ✭✭✭✭✭
edited May 14 in Cireson Uploads


Seem all the cool peps are running Applications in containers these days, and considering I haven’t posted in a while - I thought I’d share a working example to quickly create instances of the Cireson Portal for your dev, test environments to help you be one of those cool peps  B) .

Publish the different versions to your container repo to give you the ability to freely move the portal around your various environments to automate the deployment, recovery or scaling of the portal quickly.

Overview Steps:

  1. Creating the Docker Host
  2. Creating the GSMA Account, Credspec file and Permissions
  3. Building the Portal Docker Image
  4. Running the Image
Step 1: Creating the docker host

On a Windows 2016 server, Start up a PowerShell command window running as an administrator and run the following commands to download and install the latest version of Docker:

Install-Module DockerMsftProvider -Force 
Install-Package Docker -ProviderName DockerMsftProvider -Force

Step 2: Permissions

As docker does not yet have active directory support, we must configure a few things in AD and the docker host to have the portal permissions working happily as they would with a domain joined server. Using Group Managed Service Accounts on the host any service running on the nested container as LocalSystem can act as the the gMSA account as their domain indentity: (see https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts for more information)


New-ADServiceAccount
-name GMSA_DOCKER -DNSHostName GMSA_DOCKER.EVALLAB.LOCAL
-PrincipalsAllowedToRetrieveManagedPassword 'Domain Computers'

  • Import AD Modules & Install the gMSA Account on the Docker Host

Add-WindowsFeature 
RSAT-AD-PowerShell 
Import-Module ActiveDirectory 
Install-AdServiceAccount GMSA_DOCKER
Test-AdServiceAccount GMSA_DOCKER

Import-Module
./CredentialSpec.psm1
New-CredentialSpec -Name GMSA_DOCKER -AccountName GMSA_DOCKER

  • .Add GMSA_Docker to your SCSM Administrators group for SCSM, and grant GMSA_DOCKER$ permissions in SQL Server to ServiceManager & ServiceManagement (Or if creating a new portal database - grant sysadmin rights)


Comments

  • Joe_BurrowsJoe_Burrows Cireson Devops Super IT Monkey ✭✭✭✭✭
    edited April 23
    Step 3: Portal Docker Build

    If you not familiar with docker, I’d recommend following the examples on the docker website here.

    First we need to automate everything the portal needs in order to get built, which we declare in a dockerfile. Luckily the Cireson Portal comes already scripted in PowerShell for all the pre-reqs and install - so the only changes we need to make to the install process is to have the AppPool, CacheBuilder and Platform cache run as LocalSystem so the container can impersonate the gMSA account that has the correct SQL and Service Manager permissions.

    We will need the following on a new container to complete a build with the Cireson Portal

    1. A Local Admin Account that we can set for the parameters installportal.ps1 requires for services.
    2. Some folders on the image to hold the packages and scripts we want locally
    3. Cireson Portal for SCSM Zip package downloadable from downloads.cireson.com
    4. Some Powershell scripts to switch the Service Accounts to LocalSystem
    5. Other bits and bobs

    Bring this all together in a dockerfile – too easy right? Will break about the dockerfile with what each step is doing (The complete dockerfile used in this example can be downloaded from the post above and adjusted to suit your environment).

    # escape=` 
    FROM microsoft/dotnet-framework:3.5
    LABEL maintainer "Joe Burrows"
    # Container Parameters
    ARG smp_setup_zip_uri=https://ciresonreleases.blob.core.windows.net/servicemgrportal/PreviousVersions/8.4.3.2016.zip
    ARG ManagementDBName=ServiceManagement
    ENV ManagementDBName ${ManagementDBName}
    ENV smp_setup_zip_uri ${smp_setup_zip_uri} SHELL ["powershell","-Command"]

    By default the escape character in Docker is \ - this becomes a pain when working with Windows containers so is changeable by declaring # escape=` at the beginning.

    The image we are using as the base is the Official Microsoft Server Core Image for docker with dotnet-framework 3.5

    Then we set ARG which are the augments we can use when running a docker build (more on this latter), we are setting a default in case nothing is declared in the docker build command – and then storing them as environment variables that can called in the scripts in the steps latter in the docker file.

    Next we create our Local Admin User using the net user command and net localgroup with a super secure password

    # Container Image Environment Configuration ##Create Local Admin User 
    RUN NET USER ContainerAdmin [email protected] /add /y /expires:never; `NET LOCALGROUP Administrators ContainerAdmin /add

    Next we want create our working folders, download the portal installer ZIP to our image from our Environment Variable we stored above, download our custom scripts, unblock the zip, unzip, run the installpreqs and remove that annoying Default IIS Web Site.

    # Download SMP Setup Zip, Container
    Scripts and Install Pre-reqs 
    EXPOSE 80
    RUN md C:\Setup; `    md C:\Scripts; `    Write-host "Downloading SMP From $ENV:smp_setup_zip_uri...."; `    invoke-WebRequest -outfile C:\Setup\SMP.Zip $ENV:smp_setup_zip_uri; `    Write-host "Downloading Scripts From https://ciresonresources.blob.core.windows.net/docker/EvalLab/smp.....";`    invoke-WebRequest -outfile C:\Scripts\Update-Service.ps1 https://ciresonresources.blob.core.windows.net/docker/EvalLab/smp/Update-Service.ps1;`    invoke-WebRequest -outfile C:\Scripts\Run-Database-Dac.ps1 https://ciresonresources.blob.core.windows.net/docker/EvalLab/smp/Run-Database-Dac.ps1;`    unblock-file -path C:\Setup\SMP.Zip; `   Expand-Archive C:\Setup\SMP.Zip C:\Setup; `.\Setup\InstallPreReq.ps1; `Remove-Website -Name 'Default Web Site'

    Before we run the InstallPortal.PS1 script we need to edit the script so it installs the App Pool to Run as LocalSystem (Rather than a Windows AD User), this is achieved by finding and replacing some lines in the script as below:

    ## Replace AppPool Account Settings in Installer script to Use LocalSystem
    
    RUN((Get-Content "C:\Setup\InstallPortal.ps1")-creplace 'appPool.processModel.identityType = 3','appPool.processModel.identityType = 2') | Set-Content "C:\Setup\InstallPortal.ps1"

    Then we are good to declare the parameters the InstallPortal script requires for installation:

    RUN
    & {C:\Setup\InstallPortal.ps1 ` 
    -ManagementServer 'EvalLab-SCSM.evallab.local' `
    -SQLServer 'EvalLab-SQL.evallab.local' `
    -PortalUser '.\ContainerAdmin' `
    -SiteRootPath 'C:\InetPub\' `
    -PortalPassword '[email protected]' `
    -CreateManagementDB $true `
    -ManagementDBName $ENV:ManagementDBName `
    -ExecuteDac $true `
    -InstallManagementPacks $true `
    -ApplicationTitle 'Cireson Eval Lab Portal' `
    -InstallWebsite $true `
    -ManagementServerBinaryPath '\\EvalLab-SCSM.evallab.local\c$\Program Files\Microsoft System Center\Service Manager\SDK Binaries' `
    -RunCacheBuilderAsService $true `
    -CacheServiceUserName '.\ContainerAdmin' `
    -CacheServicePassword '[email protected]' `
    -AnalystsADGroup 'SCSM Analysts' `
    -AssetManagementADGroup 'SCSM Asset Managers' `
    -KnowledgeManagerADGroup 'SCSM KB Managers' `
    -SMSQLServer 'EvalLab-SQL.evallab.local' `
    -SMTPServerName 'EvalLab-SCSM.evallab.local' `
    -SMTPServerPort 25 `
    -SMTPEmailReturnAddress '[email protected]' `
    -AnalyticServiceUserName '.\ContainerAdmin' `
    -AnalyticServicePassword '[email protected]'`
    -InstallAnalytic $true `
    -AnalyticFrequencyStartDate '2017-12-09T16:17:43.747224+00:00' `
    }; `

    Next we want to run our custom script that we downloaded to the image to switch the installed services from our local user to LocalSystem

    & \Scripts\Update-Service.ps1 "CacheBuilder"; ` 
    
    & \Scripts\Update-Service.ps1 "Platform_Cache"

    And also Delete the customspace folder (As we want to bind the customspace folder from the dockerhost to the container – to make customization easier and if we delete containers we don’t want to lose customizations)

    #Empty CustomSpace Folder so it can be mapped as a Volume from the docker Host in the docker run command
    
    RUN Remove-item C:\InetPub\CiresonPortal\CustomSpace -Recurse -Force -verbose

    The last step is optional but I create a scheduled task to re-run the DAC file on container startup incase the image was pulled from another environment I want to make sure the database gets upgraded correctly.

    #Create Scheduled task to run DAC On container start to Upgrade database incase image pulled from Repo rather than built locally
    
    RUN schtasks /Create /TN Run-Database-Dac /SC ONSTART /TR 'c:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\Scripts\Run-Database-Dac.ps1' /ru SYSTEM

    With all the above in a file called ‘dockerfile’ we can then run docker build to create an image with all the above steps run. Set our build arg to the installer zip we want in the below example we using 8.4.3.2016. We do need to set –security-opt to tell docker to run as GMSA_Docker:

    $SMPVersion = "8.4.3.2016",   
    $SMPZipURL = "https://ciresonreleases.blob.core.windows.net/servicemgrportal/PreviousVersions/$SMPVersion.zip" Docker build -t portal:$SMPVersion --security-opt "credentialspec=file://GMSA_Docker.json" --build-arg smp_setup_zip_uri=$SMPZipURL .


    Now we successfully have 8.4.3.2016 saved into an image we can quickly run or share across multiple environments :D

    docker images will show the newly created image with the tag:


  • Joe_BurrowsJoe_Burrows Cireson Devops Super IT Monkey ✭✭✭✭✭
    edited April 23
    Step 4: Running the Image

    Now we have the image we want to run the image using docker run and setting the needed switches:

    • -dit to run detached
    • -p port bindings (in this case mapping port 80 on the host to port 80 on the nested container - recommend creating a transparent network so you dont have to nat ports to the containerhost, once the network is created you can simply assign an IP address per container replace -p with --network={NameOfYourTransparentNetwork} --ip={IPAddressToAssignContainer} and the EXPOSE ports declared in the docker file will be accessible on that IP address)
    • –dns IP address of the DNS server in the vnet so the container can do internal name resolution
    • -v to bin a folder on the host to a folder on the windows container (In this case custom space so anything in C:\Container-Volumes\SMP\CustomSpace will be available to the portal in the container)
    • –name container name – optional but I like to have the container named after the application its running rather than the random names the docker daemon assigns.
    • -h Windows Container Host name – must match the name of the GMSA account its impersonating.
    • Credentialspec (as created from the powershell script in the permissions step)
    • Docker Image name to run

    docker run -dit -p 80:80 --dns=172.21.21.5 -v C:\Container-Volumes\SMP\CustomSpace:C:\Inetpub\CiresonPortal\CustomSpace --dns-search=evallab.local --name=SMP-Portal -h GMSA_Docker --security-opt "credentialspec=file://GMSA_Docker.json" portal:8.4.3.2016




     B) 





Sign In or Register to comment.