How to deploy config changes into Sitecore roles hosted in Docker or Kubernetes

Artsem Prashkovich on September 13, 2021

Working on Sitecore projects hosted in Docker or in Kubernetes, sometimes we need to add custom code or config changes to the Identity server, XConnect, Marketing Automation, etc. This article describes the approach to achieve that, which is common and applies to all Sitecore roles.

During the last project, which is a corporate website, I had the need to add a config with a custom Client configuration to the Identity server. This client configuration allows you to log in to Sitecore through Sitecore CLI using a secret token. That is useful when you need to build CI/CD processes and you need to run serialization/publish/index rebuild remotely. So that is a good example to explore.

First of all, we need to create a Class Library project within our solution that will contain our custom, identity server-related, changes. I have called this project Corporate.Environment.Identity

All custom configs need to be placed in the Config folder. I have added only one file Sitecore.IdentityServer.Corporate.xml with the following content:

<?xml version="1.0" encoding="utf-8"?>
<Settings>
<Sitecore>
<IdentityServer>
<Clients>
<!-- used to authenticate servers with client id and client secret -->
<CliServerClient>
<ClientId>Corporate_CI</ClientId>
<ClientName>Corporate_CI</ClientName>
<AccessTokenType>0</AccessTokenType>
<AccessTokenLifetimeInSeconds>3600</AccessTokenLifetimeInSeconds>
<IdentityTokenLifetimeInSeconds>3600</IdentityTokenLifetimeInSeconds>
<RequireClientSecret>true</RequireClientSecret>
<AllowOfflineAccess>false</AllowOfflineAccess>
<AllowedGrantTypes>
<!-- client_credentials authenticates with client ID and client secret which is good for CI, tools, etc. However, it's not tied to a USER, it's tied to a client ID.-->
<AllowedGrantType1>client_credentials</AllowedGrantType1>
</AllowedGrantTypes>
<ClientSecrets>
<ClientSecret1>260CA22A3F9R40498DEA074C117DAFB8</ClientSecret1>
</ClientSecrets>
<AllowedScopes>
<!-- this is required even if not a 'user' for Sitecore to like us -->
<AllowedScope3>sitecore.profile.api</AllowedScope3>
</AllowedScopes>
</CliServerClient>
</Clients>
</IdentityServer>
</Sitecore>
</Settings>

The ClientId and ClientSecret1 will be used to log in to Sitecore during the CI/CD process.

Since we don’t need anything else, we are ready to switch to updating our docker images.

First of all, we need to add a build command in our solution Dockerfile and copy build artifacts to the image:

# escape=`
ARG BUILD_IMAGE

FROM ${BUILD_IMAGE} AS nuget-prep
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
# Gather only artifacts necessary for NuGet restore, retaining directory structure
COPY *.sln nuget.config Directory.Build.targets Packages.props /nuget/
COPY src/ /temp/
RUN Invoke-Expression 'robocopy C:/temp C:/nuget/src /s /ndl /njh /njs *.csproj *.scproj packages.config'

FROM ${BUILD_IMAGE} AS builder
ARG BUILD_CONFIGURATION

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
WORKDIR /build

# Copy prepped NuGet artifacts, and restore as a distinct layer to take advantage of caching.
COPY --from=nuget-prep ./nuget ./

RUN nuget restore -Verbosity quiet

# Copy remaining source code
COPY src/ ./src/

# Copy transforms, retaining directory structure
RUN Invoke-Expression 'robocopy /build/src /build/transforms /s /ndl /njh /njs *.xdt'

# Build the Sitecore main platform artifacts
RUN msbuild .\src\Environment\platform\Corporate.Environment.Platform.csproj /p:Configuration=$env:BUILD_CONFIGURATION /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:PublishUrl=/build/sitecore
RUN msbuild .\src\Environment\identity\Corporate.Environment.Identity.csproj /p:Configuration=$env:BUILD_CONFIGURATION
/p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:PublishUrl=/build/identity

# Build the rendering host
WORKDIR /build/src/Project/Corporate/rendering/
RUN dotnet publish -c $env:BUILD_CONFIGURATION -o /build/rendering --no-restore

FROM mcr.microsoft.com/windows/nanoserver:1809
WORKDIR /artifacts
# Copy final build artifacts
COPY --from=builder /build/sitecore ./sitecore/
COPY --from=builder /build/transforms ./transforms/
COPY --from=builder /build/rendering ./rendering/
COPY --from=builder /build/identity/Config ./identity/Config

Once our solution image contains the required artifacts, we need to update our docker-compose.override.yml to pass the solution image to the identity server build:

# Use our retagged Identity Server image.
# Configure for a mounted license file instead of using SITECORE_LICENSE.
id:
image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-id:${VERSION:-latest}
build:
context: ./docker/build/id
args:
PARENT_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-id:${SITECORE_VERSION}
SOLUTION_IMAGE: ${REGISTRY}${COMPOSE_PROJECT_NAME}-solution:${VERSION:-latest}
depends_on:
- solution
volumes:
- ${HOST_LICENSE_FOLDER}:c:\license
environment:
SITECORE_LICENSE_LOCATION: c:\license\license.xml

Then we need to update the identity server build docker file itself to copy config from solution image to the identity one:

# escape=`

ARG PARENT_IMAGE
ARG SOLUTION_IMAGE

FROM ${SOLUTION_IMAGE} as solution
FROM ${PARENT_IMAGE}

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

WORKDIR C:\Identity

# Copy identity artifacts
COPY --from=solution /artifacts/identity/ ./

ENTRYPOINT ["dotnet", "Sitecore.IdentityServer.Host.dll"]

After the next docker-compose build all new configs will be deployed to the docker. It allows us to use Sitecore CLI within CI/CD processes. You can find the Powershell script to run Sitecore Serialization sync below:

function Arg { param([Parameter()][string]$Parameter) return $Parameter }

$idHost= Arg '$(ID_HOST)';
$cmHost= Arg '$(CM_HOST)';
$clientSecret= Arg '$(ID_SERVER_CORPORATE_CLIENT_SECRET)';

# Add nuget source & install Sitecore CLI
Write-Host "Installing Sitecore CLI"
dotnet nuget add source $(SITECORE_PUBLIC_NUGET_FEED) --name "Sitecore-Public-Nuget-Feed"
dotnet tool install --add-source=$(SITECORE_PUBLIC_NUGET_FEED) --version 3.0.0 sitecore.cli

dotnet tool restore

# Login to ID Server
Write-Host "Logging into ID Server"
dotnet sitecore login --client-credentials true --auth https://$idHost --cm https://$cmHost --allow-write true --client-id "Camao_CI" --client-secret "$clientSecret"

# Deserialize Content
Write-Host "Push Content"
dotnet sitecore ser push

# Publish Database
Write-Host "Publish Database"
dotnet sitecore publish