Applying configuration transforms
Sitecore implementations often require modifications of configuration files that you cannot change with Sitecore configuration patching, such as Web.config
, ConnectionStrings.config
, Domains.config
, Layers.config
, and others. In these cases, you use an XDT transform file instead.
This topic shows how you apply these XDT-based configuration transforms when you build your Sitecore Docker images. The transform files can be located in your solution or the can be local to the Dockerfile for a particular Sitecore role. The example uses a Sitecore Experience Management (XM1) instance.
Clone the Docker Examples repository
If you have not already done so, clone the Docker Examples repository to a location on your machine, such as C:\sitecore\docker-examples\
(the example uses this folder). You use the custom-images folder in the example.
Example preparation
The custom-images example requires some preparation before you can run it. If you have not already done so, either follow the preparation steps or run the included init.ps1
script to perform these preparation steps automatically:
-
Open a PowerShell administrator prompt, navigate to the custom-images folder, and run this command, replacing the
-LicenseXmlPath
with the location of your Sitecore license file:RequestResponse.\init.ps1 -LicenseXmlPath C:\License\license.xml
The Docker Examples transform files
The Docker Examples solution contains two XDT configuration transform files for the Web.config
where a custom Docker-Examples
HTTP header is manipulated. Navigate to the custom-images folder, and look at the following transform files:
-
\src\DockerExamples.Website\Web.config.xdt
Because this transform file is located in the solution, it is applied to all core Sitecore roles (CM and CD in an XM1 topology). This is an example of a solution transform. Here, the
Docker-Examples
HTTP header is added and it is set toSolution transform
:RequestResponse<?xml version="1.0" encoding="utf-8"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.webServer> <httpProtocol> <customHeaders> <add name="Docker-Examples" xdt:Locator="Match(name)" value="Solution transform" xdt:Transform="InsertIfMissing" /> </customHeaders> </httpProtocol> </system.webServer> </configuration>
-
\docker\build\cm\transforms\Web.config.xdt
This transform file is located in the docker\build folder, local to the cm service. This is an example of a role transform. It changes the
Docker-Examples
HTTP header toRole transform
:RequestResponse<?xml version="1.0" encoding="utf-8"?> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.webServer> <httpProtocol> <customHeaders> <add name="Docker-Examples" xdt:Locator="Match(name)" value="Role transform" xdt:Transform="SetAttributes(value)" /> </customHeaders> </httpProtocol> </system.webServer> </configuration>
It is best practice to take order of operation into consideration when you apply multiple transforms. However, because transforms are applied to a fresh config file every time, there is no need to ensure they are idempotent.
The example applies solution transforms first, then role transforms.
Solution transforms
You store configuration transforms that apply to all core Sitecore roles directly in the solution structure.
The following example uses a dedicated solution build artifact to collect and apply solution transforms. The advantage of this approach is that it supports multiple transforms for the same config file, and this is often used in Sitecore Helix solutions.
For example, you can have multiple Web.config
transforms among the layers:
-
\src\Foundation\[Module Name]\website\Web.config.xdt
-
\src\Feature\[Module Name]\website\Web.config.xdt
-
\src\Project\[Module Name]\website\Web.config.xdt
In this setup, if you include all these in the build output (thats is: Build Action
is set to Content
), only one ends up in the output and ultimately gets applied. Instead, each of these files can be excluded (that is Build Action
is set to None
), and they are collected separately in the solution build image.
You can also to keep the transform files in the main build output and perform the transforms in-place in the web root. However, this does not support multiple transforms for the same config file.
Configure in solution build
Navigate to the custom-images folder, and look at the Dockerfile
that is there.
You' can see that the transform files (.xdt
extension) are collected within the builder
stage and dropped at C:\out\transforms
. The use of robocopy
(along with the /s
flag) is important here because it preserves the folder structure:
RUN Invoke-Expression 'robocopy C:\build\src C:\out\transforms /s /ndl /njh /njs *.xdt'
Note this is done before the msbuild
so you do not have to pick up extra .xdt
files that have not been excluded from build output. Then these files are copied in from the builder
stage to the final image with this structure: \artifacts\transforms
:
COPY --from=builder C:\out\transforms .\transforms\
Apply to Sitecore runtime images
To apply transforms to runtime images:
-
Open the Sitecore runtime Dockerfile for the cm service. You can see the solution transforms just collected copied in, landing at
\transforms\solution\
:RequestResponseCOPY --from=solution \artifacts\transforms\ \transforms\solution\
-
Development tools are copied in from the
tooling
image (toC:\tools
), and theInvoke-XdtTransform.ps1
script is used to apply the transforms:RequestResponseCOPY --from=tooling \tools\ \tools\ RUN C:\tools\scripts\Invoke-XdtTransform.ps1 -Path .\ -XdtPath C:\transforms\solution\DockerExamples.Website
The Invoke-XdtTransform.ps1
script accepts two folders for the -Path
and -XdtPath
parameters. When using folders:
-
the folder structure of the
-XdtPath
must match-Path
-
transform files located in
-XdtPath
must be named to match the config, with an added.xdt
file extension
In this case, -Path
is the current WORKDIR
of C:\inetpub\wwwroot
, and -XdtPath
is the root of our single Visual Studio Website
project.
The Helix solution example
The Docker Examples solution is a simple example with a single Website
project. In a real-world solution that follow the Sitecore Helix practices, the transform commands would need to be adjusted to reflect the nested folder structure and layer priority (such as Project, Feature, Foundation):
RUN Get-ChildItem C:\transforms\solution\Foundation\*\website | ForEach-Object { & C:\tools\scripts\Invoke-XdtTransform.ps1 -Path .\ -XdtPath $_.FullName }; `
Get-ChildItem C:\transforms\solution\Feature\*\website | ForEach-Object { & C:\tools\scripts\Invoke-XdtTransform.ps1 -Path .\ -XdtPath $_.FullName }; `
Get-ChildItem C:\transforms\solution\Project\*\website | ForEach-Object { & C:\tools\scripts\Invoke-XdtTransform.ps1 -Path .\ -XdtPath $_.FullName };
Alternative: Use transform files in main build output
You can keep the transform files with all other files in the main build output. The disadvantage to this approach is that it does not support multiple transforms for the same config file, but it can be your only option if you do not have a solution build Dockerfile and image and instead rely on a more traditional build.
The following is an example:
RUN $xdts = [System.Collections.ArrayList]@(); `
$xdts.AddRange(@(Get-ChildItem -Path .\*.xdt)); `
$xdts.AddRange(@(Get-ChildItem -Path .\App_Config\*.xdt -Recurse)); `
$xdts | ForEach-Object { & C:\tools\scripts\Invoke-XdtTransform.ps1 -Path $_.FullName.Replace('.xdt', '') -XdtPath $_.FullName }; `
$xdts | ForEach-Object { Remove-Item -Path $_.FullName };
The Invoke-XdtTransform.ps1
script also accepts matching configuration and transform files as parameters.
This example looks for .xdt
files in the web root and App_Config folder, passes them through the Invoke-XdtTransform.ps1
script, and then deletes the .xdt
files.
Role transforms
You can store configuration transforms that only apply to a specific Sitecore role inside the dedicated docker\build folder of that role.
Add to docker\build folder
Navigate to the docker\build folder for the cm service. Note there is an extra transforms folder for this role:
build
cm
transforms
Web.config.xdt
Dockerfile
There is a single Web.config.xdt
transform, but this transform can contain any other transforms necessary for the cm role. As is the case with solution transforms, you structure the transform files to match the folder structure of your target.
You then apply these transforms in the Sitecore runtime Dockerfile for the role.
Apply to Sitecore runtime image
You can see in the Sitecore runtime Dockerfile for the cm service that the transforms folder contents are copied in from the Docker build context, landing at \transforms\role\
:
COPY .\transforms\ \transforms\role\
The transforms are then applied after solution transforms, using the same Invoke-XdtTransform.ps1
script:
RUN C:\tools\scripts\Invoke-XdtTransform.ps1 -Path .\ -XdtPath C:\transforms\role
Run Docker Examples solution
To run the Docker Examples solution:
-
Open the Sitecore runtime Dockerfile for the cd service (for example
C:\sitecore\docker-examples\custom-images\docker\build\cd\Dockerfile
). You can see that the cd service has the solution transforms, but does not have any role transforms. -
Open a PowerShell prompt and navigate to the custom-images folder. Run the Docker Examples with the Docker Compose
up
command:RequestResponsedocker compose -f docker compose.xm1.yml -f docker compose.xm1.override.yml up -d
NoteNote the
docker compose -f docker compose.xm1.yml -f docker compose.xm1.override.yml
command. Because this example uses the Sitecore Experience Management (XM1) instance, thedocker compose
commands are explicitly referencing the xm1 Compose fileswith the-f
flag. The default Compose files are XP0.You can access Sitecore Experience Management (XM1) containers with the following:
-
Sitecore Content Management (cm): https://cm.dockerexamples.localhost
-
Sitecore Content Delivery (cd): https://cd.dockerexamples.localhost
-
-
When the instance is up and running, you can use developer tools in your browser to inspect the HTTP headers. You can see the
Docker-Examples
custom header that is in the transform examples.The cm site displays
Role transform
, while the cd site displaysSolution transform
.
Apply updates to running containers
To apply updates to a running container:
-
Change to one of the example
Web.config.xdt
files. For example, change the solution transformvalue
toMy transform
. -
Run the following command to see the change applied in the running containers:
RequestResponsedocker compose -f docker compose.xm1.yml -f docker compose.xm1.override.yml up --build -d
You can also be more selective and only build the containers that are impacted:
RequestResponsedocker compose -f docker compose.xm1.yml -f docker compose.xm1.override.yml build solution cm cd docker compose -f docker compose.xm1.yml -f docker compose.xm1.override.yml up -d
In both cases, when the
up
command is called, Docker recreates only the cm and cd containers. The rest of the roles continue running. -
When you are finished, stop and remove the containers using the
down
command:RequestResponsedocker compose -f docker compose.xm1.yml -f docker compose.xm1.override.yml down
When you are actively developing configuration transforms, it is helpful to use a transform test tool such as https://webconfigtransformationtester.apphb.com/ to shorten the feedback loop.