Docker was built for Sitecore Commerce XC 9.3

In this blog post we shall continue our Docker journey to hopefully reach a state where we could get Docker to help us with the Sitecore Commerce development.

I truly believe Docker was built for Sitecore Commerce. If you have been part of Sitecore Commerce projects, you would know that it takes quite a few installations on vm’s or the local machine to get up and running. You should also know that from time to time, you simply want to just wipe out your machine and restart the process again. No amount of checkpoints would save you on your hyper-v’s ;).

Docker manages this very easily. I could simply wipe out my whole environment and relaunch it within minutes.

Docker Sitecore Commerce

Before we go on, I want to thank all the community and sitecore contributors for working on the Sitecore Docker repo - https://github.com/Sitecore/docker-images.

In my previous blog post Dockerify your Sitecore 9.3 XP development environment - SSL, CM and Identity we talked about setting up SSL and getting our CM and Identity servers up and running.

Identity Server

I missed a few instructions on the Identify server configuration in my previous blog post. Since we need to revisit it for the Sitecore Commerce setup, might as well get both done with.

You need to add to your data folder (data\identity\wwwroot\Config\production), the Sitecore.IdentityServer.Host.xml config. Here you would specify the CertificateThumbprint (Generate any random one), PasswordRecoveryUrl (Your Identity server url), AllowedCorsOrigins (Your CM url for now) and the ClientSecret (Randomly generated key).

<?xml version="1.0" encoding="utf-8"?>
<Settings>
        <Sitecore>
                <IdentityServer>
                        <CertificateThumbprint>9F03BC8B4612D53B4E818972E7981A221CD61FSC</CertificateThumbprint>
                        <CertificateStoreLocation>LocalMachine</CertificateStoreLocation>
                        <CertificateStoreName>My</CertificateStoreName>
                        <SitecoreMembershipOptions>
                                <ConnectionString>Data Source=sql;Initial Catalog=Sitecore.Core;User ID=sa;Password=8Tombs-Given-Clock#-arming-Alva-debut-Spine-monica-Normal-Ted-About1-chard-Easily-granddad-5Context!</ConnectionString>
                        </SitecoreMembershipOptions>
                        <AccountOptions>
                                <PasswordRecoveryUrl>https://identity.bemyfriend.local/sitecore/login?rc=1</PasswordRecoveryUrl>
                        </AccountOptions>
                        <Clients>
                                <DefaultClient>
                                        <AllowedCorsOrigins>
                                                <AllowedCorsOriginsGroup1>https://cm.bemyfriend.local</AllowedCorsOriginsGroup1>
                                        </AllowedCorsOrigins>
                                </DefaultClient>
                                <PasswordClient>
                                        <ClientSecrets>
                                                <ClientSecret1>wHycAnTYOUBmYfr1EndPGGt2pUNhkxDRq0TCBoR4PjHTCYMW0rCrIDKH42qET4iDMYihXmDtVE2wckcb3AGx265ErSWMYdInV0O0</ClientSecret1>
                                        </ClientSecrets>
                                </PasswordClient>
                        </Clients>
                </IdentityServer>
        </Sitecore>
</Settings>

You also need to add Sitecore.Commerce.IdentityServer.Host.xml to your data folder (data\identity\wwwroot\Config\production). Here you would specify the same CertificateThumbprint as the one from Sitecore.IdentityServer.Host.xml file, PasswordRecoveryUrl (Your Identity server url), AllowedCorsOrigins (Your CM url for now) and the ClientSecret same as the one from Sitecore.IdentityServer.Host.xml file.

<?xml version="1.0" encoding="utf-8"?>
<Settings>
        <Sitecore>
                <IdentityServer>
                        <CertificateThumbprint>9F03BC8B4612D53B4E818972E7981A221CD61FSC</CertificateThumbprint>
                        <CertificateStoreLocation>LocalMachine</CertificateStoreLocation>
                        <CertificateStoreName>My</CertificateStoreName>
                        <SitecoreMembershipOptions>
                                <ConnectionString>Data Source=sql;Initial Catalog=Sitecore.Core;User ID=sa;Password=8Tombs-Given-Clock#-arming-Alva-debut-Spine-monica-Normal-Ted-About1-chard-Easily-granddad-5Context!</ConnectionString>
                        </SitecoreMembershipOptions>
                        <AccountOptions>
                                <PasswordRecoveryUrl>https://identity.bemyfriend.local/sitecore/login?rc=1</PasswordRecoveryUrl>
                        </AccountOptions>
                        <Clients>
                                <DefaultClient>
                                        <AllowedCorsOrigins>
                                                <AllowedCorsOriginsGroup1>https://cm.bemyfriend.local</AllowedCorsOriginsGroup1>
                                        </AllowedCorsOrigins>
                                </DefaultClient>
                                <PasswordClient>
                                        <ClientSecrets>
                                                <ClientSecret1>wHycAnTYOUBmYfr1EndPGGt2pUNhkxDRq0TCBoR4PjHTCYMW0rCrIDKH42qET4iDMYihXmDtVE2wckcb3AGx265ErSWMYdInV0O0</ClientSecret1>
                                        </ClientSecrets>
                                </PasswordClient>
                        </Clients>
                </IdentityServer>
        </Sitecore>
</Settings>

Commerce Authoring, Minions, Ops and Shops

To get the four commerce roles on SSL, we did something similar to the CM. We have a specific PowerShell script in the startup that added the SSL bindings and called the C:\tools\entrypoints\sitecore-xc-engine\Development.ps1 script. The C:\tools\entrypoints\sitecore-xc-engine\Development.ps1 is specific to the commerce roles.

[CmdletBinding()]
param(
    [Parameter(Mandatory = $false)]
    [string]$EntryPointScriptPath = "C:\tools\entrypoints\sitecore-xc-engine\Development.ps1"
)
Write-Host "Running startup.ps1"
Import-Module WebAdministration
$website = "Default Web Site"
Write-Host "Checking if $($website) has any existing HTTPS bindings"
$hostHeaders = "${env:HOST_HEADER}".Split(";", [System.StringSplitOptions]::RemoveEmptyEntries)
function Set-HttpBinding {
    param(
        [string]$SiteName,
        [string]$HostHeader
    )
    if ($null -eq (Get-WebBinding -Name $siteName | Where-Object { $_.BindingInformation -eq "*:80:$($hostHeader)" })) {
        Write-Host "Adding a new HTTP binding for $($siteName)"
        $binding = New-WebBinding -Name $siteName -Protocol http -IPAddress * -Port 80 -HostHeader $hostHeader
    } else {
        Write-Host "HTTP binding for $($siteName) already exists"
    }
    if ($null -eq (Get-WebBinding -Name $siteName | Where-Object { $_.BindingInformation -eq "*:443:$($hostHeader)" })) {
        Write-Host "Adding a new HTTPS binding for $($siteName)"
        $securePassword = (Get-Content -Path C:\startup\cert.password.txt) | ConvertTo-SecureString -AsPlainText -Force
        $cert = Import-PfxCertificate -Password $securePassword -CertStoreLocation Cert:\LocalMachine\root -FilePath C:\startup\cert.pfx   
        $thumbprint = $cert.Thumbprint
        $binding = New-WebBinding -Name $siteName -Protocol https -IPAddress * -Port 443 -HostHeader $hostHeader
        $binding = Get-WebBinding -Name $siteName -Protocol https
        $binding.AddSslCertificate($thumbprint, "root")
    } else {
        Write-Host "HTTPS binding for $($siteName) already exists"
    }
}
foreach($hostheader in $hostHeaders) {
    Set-HttpBinding -SiteName $website -HostHeader $hostheader
}

Write-Host "Running $($EntryPointScriptPath)"
& $EntryPointScriptPath

The Docker compose file for the commerce roles is shown below:

  commerce-authoring:
    image: ${REGISTRY}sitecore-xc-engine-authoring:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    entrypoint: PowerShell.exe -NoLogo -NoProfile -File C:\\startup\\startup-commerce.ps1
    mem_limit: ${MEM_LIMIT_COMMERCE:-1GB}
    volumes:
      - .\data\commerce-authoring\logs:C:\inetpub\wwwroot\wwwroot\logs
      - .\data\commerce-authoring\wwwroot:C:\src
      - .\startup:C:\startup
    ports:
      - "44005:80"
      - "44006:443"
    networks:
        default:
          aliases:
            - commerce-authoring.bemyfriend.local
    environment:
          HOST_HEADER: commerce-authoring.bemyfriend.local          
    depends_on:
      - sql
      - solr
    isolation: ${ISOLATION}
    restart: always
    container_name: commerce-authoring.bemyfriend.local

  commerce-minions:
    image: ${REGISTRY}sitecore-xc-engine-minions:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    entrypoint: PowerShell.exe -NoLogo -NoProfile -File C:\\startup\\startup-commerce.ps1
    mem_limit: ${MEM_LIMIT_COMMERCE:-1GB}
    volumes:
      - .\data\commerce-minions\logs:C:\inetpub\wwwroot\wwwroot\logs
      - .\data\commerce-minions\wwwroot:C:\src
      - .\startup:C:\startup
    ports:
      - "44010:80"
      - "44011:443"
    networks:
        default:
          aliases:
            - commerce-minions.bemyfriend.local
    environment:
          HOST_HEADER: commerce-minions.bemyfriend.local          
    depends_on:
      - sql
      - solr
    isolation: ${ISOLATION}
    container_name: commerce-minions.bemyfriend.local

  commerce-ops:
    image: ${REGISTRY}sitecore-xc-engine-ops:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    entrypoint: PowerShell.exe -NoLogo -NoProfile -File C:\\startup\\startup-commerce.ps1
    mem_limit: ${MEM_LIMIT_COMMERCE:-1GB}
    volumes:
      - .\data\commerce-ops\logs:C:\inetpub\wwwroot\wwwroot\logs
      - .\data\commerce-ops\wwwroot:C:\src 
      - .\startup:C:\startup     
    ports:
      - "44015:80"
      - "44016:443"
    networks:
        default:
          aliases:
            - commerce-ops.bemyfriend.local
    environment:
          HOST_HEADER: commerce-ops.bemyfriend.local          
    depends_on:
      - sql
      - solr
    isolation: ${ISOLATION}
    container_name: commerce-ops.bemyfriend.local

  commerce-shops:
    image: ${REGISTRY}sitecore-xc-engine-shops:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    entrypoint: PowerShell.exe -NoLogo -NoProfile -File C:\\startup\\startup-commerce.ps1
    #entrypoint: PowerShell.exe -Command "& C:\\tools\\entrypoints\\sitecore-xc-engine\\Development.ps1"
    mem_limit: ${MEM_LIMIT_COMMERCE:-1GB}
    volumes:
      - .\data\commerce-shops\logs:C:\inetpub\wwwroot\wwwroot\logs
      - .\data\commerce-shops\wwwroot:C:\src
      - .\startup:C:\startup
    ports:
      - "44020:80"
      - "44021:443"
    networks:
        default:
          aliases:
            - commerce-shops.bemyfriend.local
    environment:
          HOST_HEADER: commerce-shops.bemyfriend.local         
    depends_on:
      - sql
      - solr
    isolation: ${ISOLATION}
    container_name: commerce-shops.bemyfriend.local

In your commerce solution, modify the config.json in the wwwroot folder and modify the SitecoreIdentityServerUrl and the AllowedOrigins attributes with appropriate values.

"SitecoreIdentityServerUrl": "https://identity.bemyfriend.local",
    "AllowedOrigins": [
      "https://bizfx.bemyfriend.local",
      "https://cm.bemyfriend.local"
    ],

BizFx

Next in line is the BizFx server configuration.

Official Definition: The Sitecore Commerce Business Tools (BizFX) role provides a single point of access to an interface allowing business users and commerce administrators to perform activities related to merchandising, pricing, promotions, orders and customers management, but also more advanced administrator tasks.

Since we already configured the CM, all four commerce roles and the Identity roles, its super easy to configure the BizFx role.

You need to add to your data folder (data\bizfx\wwwroot\assets), the config.json file. Here you would specify the EngineUri (Your Sitecore Commerce Authoring role url), IdentityServerUri (Your Identity server url) and the BizFxUri (Your BizFx url). You can also modify the other config items if necessary.

{
    "EnvironmentName": "HabitatAuthoring",
    "EngineUri": "https://commerce-authoring.bemyfriend.local",
    "IdentityServerUri": "https://identity.bemyfriend.local",
    "BizFxUri": "https://bizfx.bemyfriend.local",
    "Language": "en",
    "Currency": "USD",
    "ShopName": "CommerceEngineDefaultStorefront",
    "LanguageCookieName": "selectedLanguage",
    "EnvironmentCookieName": "selectedEnvironment",
    "AutoCompleteTimeout_ms": 300
}
  

The following is the Docker compose definition for the BizFx role:

  bizfx:
    image: ${REGISTRY}sitecore-xc-bizfx:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    entrypoint: PowerShell.exe -NoLogo -NoProfile -File C:\\startup\\startup.ps1
    mem_limit: ${MEM_LIMIT_SERVICES:-1GB}
    volumes:
      - ${LICENSE_PATH}:C:\license
      - .\data\bizfx\logs:C:\inetpub\wwwroot\logs
      - .\startup:C:\startup      
      - .\data\bizfx\wwwroot:C:\src          
    ports:
      - "4200:80"
      - "4201:443"
    networks:
        default:
          aliases:
            - bizfx.bemyfriend.local
    environment:
          HOST_HEADER: bizfx.bemyfriend.local        
    depends_on:
        - commerce-authoring
        - identity
    isolation: ${ISOLATION}
    restart: always
    container_name: bizfx.bemyfriend.local

Credit where its due

If you have any questions, please get in touch with me. @akshaysura13 on twitter or on Slack.