Deploying items

Current version: 10.2

This topic explains Sitecore item package and deployment automation strategies on Docker. There are different ways to do this, depending on the item serialization tool you use.

Sitecore CLI and Sitecore Content Serialization

The Sitecore CLI is optimized for scripted interaction with a remote Sitecore instance. It can be used to package items during your continuous integration process, and to install those packages during your deployment and delivery process. Automating item deployment into a Sitecore environment with the Sitecore CLI is no different when using containers.

The Sitecore CLI documentation has more details, and the Sitecore module reference has information about installing the required Sitecore Management Services module in your CM container image.

Sitecore TDS

Sitecore TDS has a number of built-in tools that facilitate item packaging and deployment. The general approach is to use these tools to create item packages during your solution build, and then add them to the Content Management (CM) image when building your Sitecore runtime images.

The Helix.Examples repository on GitHub has a complete example.

Sitecore TDS Project Configuration

This example takes advantage of two Sitecore TDS features: Build Output and WebDeploy Packages. These are settings configured on the TDS project property pages:

  • Build Output Path - Located on the Build page, you set this for the Release build configuration. Specify a path shared by all TDS projects. In our example, this is set to ..\..\TdsGeneratedPackages\Release\.

  • Build WebDeploy package - Located on the WebDeploy Package page, select this for the Release build configuration. Specify a Package Name, and select Item only Package for Code and Item Packaging Options.

The following assumes you have configured your TDS projects accordingly.

Configure in solution build

Sitecore TDS requires licensing environment variables for Docker or cloud builds:

  • In your solution build Dockerfile, declare ARGs for these at the start of your code compilation and build stage (builder in the examples):

    RequestResponse
    ARG TDS_Owner
    ARG TDS_Key

    The location within the Dockerfile is important due to ARG scope. If you instead declare these in a previous build stage, the values are empty when used in the builder stage. Also note that ARG is used instead of ENV because these are only used for building the image.

    These values are populated for the solution service in the docker-compose.override.yml file, for example:

    RequestResponse
    solution:
      image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-solution:${VERSION:-latest}
      build:
        context: .
        args:
          BASE_IMAGE: ${SOLUTION_BASE_IMAGE}
          BUILD_IMAGE: ${SOLUTION_BUILD_IMAGE}
          TDS_Owner: ${TDS_OWNER}
          TDS_Key: ${TDS_KEY}
      scale: 0

    You can have the TDS_OWNER and TDS_KEY values in the environment file (.env), but usually you specify them as system environment variables on local development machines and as secrets on your build server (for security purposes).

  • In the solution build Dockerfile, you can simplify the msbuild instruction, and instead rely on the build output configured in your TDS projects:

    RequestResponse
    RUN msbuild /p:Configuration=Release

    The build output lands at the location specified in the TDS project (the Build Output Path), relative to the builder's WORKDIR. In the example, this means build output is:

    • \build\TdsGeneratedPackages\Release (files)

    • \build\TdsGeneratedPackages\WebDeploy_Release (WDP item packages)

    You copy these in from the builder stage to the final image with the following structure:

    • \artifacts\website

    • \artifacts\packages

    • \artifacts\transforms

  • You can adjust the final instructions to:

    RequestResponse
    WORKDIR C:\artifacts
    COPY --from=builder \build\TdsGeneratedPackages\Release .\website\
    COPY --from=builder \build\TdsGeneratedPackages\WebDeploy_Release .\packages\
    COPY --from=builder C:\out\transforms .\transforms\

Add to Sitecore CM runtime image

When you have packaged and included items with the solution image, you can add them to the Content Management (CM) image when you build your Sitecore runtime images.

At the end of the Dockerfile for your cm service, add instructions to deploy your item packages. TDS has 2 options for handling this:

  • Option 1: Deploy on container create

    This allows Sitecore TDS to install item packages on site startup. It uses a built-in feature of TDS. However, you must be aware that this happens every time a container is created using this image:

    RequestResponse
    COPY --from=solution \artifacts\packages\ \temp\
    RUN Get-ChildItem -Path 'C:\\temp\\*.wdp.zip' | % { Expand-Archive -Path $_.FullName -DestinationPath 'C:\\temp' -Force; }; `
        Move-Item -Path 'C:\\temp\\Content\\Website\\Bin\*' -Destination .\bin -Force; `
        Move-Item -Path 'C:\\temp\\Content\\Website\\temp\*' -Destination .\temp -Force; `
        Remove-Item -Path 'C:\\temp' -Recurse -Force; `
        # Ensure TDS has permissions to delete items after install
        cmd /C icacls .\temp\WebDeployItems /grant 'IIS AppPool\DefaultAppPool:(OI)(CI)M';
  • Option 2: Deploy on-demand

    Use the Deploy-TdsWdpPackages.ps1 script from the tooling image. Copy it in along with your packages:

    RequestResponse
    COPY --from=tooling \tools\scripts\Deploy-TdsWdpPackages.ps1 \install\Deploy-TdsWdpPackages.ps1
    COPY --from=solution \artifacts\packages\ \install\packages\

    You can then invoke Deploy-TdsWdpPackages.ps1 on the container on-demand with the following script:

    RequestResponse
    docker exec <container> powershell -command "C:\install\Deploy-TdsWdpPackages.ps1"

Unicorn

Important

Unicorn is a third-party open source tool which is not supported by Sitecore Support. These instructions are provided as guidance only, for the convenience of Unicorn users.

Unlike the other serialization tools described here, Unicorn does not have a built-in packaging capability, and it runs in-process with the Sitecore platform. Therefore, the serialized items in your Unicorn configuration need to be present in the filesystem of the Content Management instance weher you want to sync them. When you use Docker this is easy because you can copy the items during your container build. Unicorn also provides a PowerShell module to trigger item synchronization. This is convenient for automating item deployment when using containers.

The following steps assume you are already using Docker to build your solution and create a custom Sitecore images. Refer to the Helix.Examples repository on GitHub for a complete example.

Add serialized items to your solution artifacts

When you use Unicorn, you typically place the serialized items within your Sitecore solution source, and organize them in a structure that is defined by your Unicorn configuration, potentially following Sitecore Helix practices. You can copy all these serialized items during your solution build, but retaining their directory structure is important. Robocopy is one easy option for accomplishing this:

RequestResponse
# Copy serialized items, retaining directory structure
RUN Invoke-Expression 'robocopy C:\build\src C:\out\items /s /ndl /njh /njs *.yml'

# ... later in your artifacts build stage
WORKDIR C:\artifacts
COPY --from=builder c:\out\items .\items\

Build items and deployment scripts into your CM image

Now that you have items as build artifacts in your solution image, copy them into your CM image, just as you have done previously with your msbuild output. Additionally, place the files needed for Unicorn remoting in the CM image, so that you can later run a scripted sync from a CM container:

  1. A unicorn folder in your CM build context must contain the files needed for Unicorn remote scripting:

    • MicroCHAP.dll

    • Unicorn.psm1

    • A custom sync.ps1

  2. The sync.ps1 script in this case must contain a standard invocation of Sync-Unicorn, and use an environment variable to populate the Unicorn shared secret:

    RequestResponse
    $ScriptPath = Split-Path $MyInvocation.MyCommand.Path
    Import-Module $ScriptPath\Unicorn.psm1
    Sync-Unicorn -ControlPanelUrl 'http://localhost/unicorn.aspx' -SharedSecret $env:UNICORN_SHARED_SECRET
  3. In your CM Dockerfile, copy in this folder and the serialized items artifact, and set an environment variable that you can use later for configuring Unicorn:

    RequestResponse
    # Set the default location for serialized items
    # This value will be used in our Unicorn configuration
    ENV ITEM_SYNC_LOCATION c:\items
    
    # Copy serialized items and Unicorn sync script
    COPY --from=solution \artifacts\items\ \items\
    COPY .\unicorn \unicorn\

Configure Unicorn and your Docker environment

The base filesystem path used for Unicorn sync is typically set in Sitecore configuration using an sc.variable called sourceFolder:

  1. Populate this value from the environment variable defined above in our Dockerfile.

    RequestResponse
    <sc.variable name="sourceFolder" value="$(env:ITEM_SYNC_LOCATION)" />
  2. Populate the Unicorn shared secret from an environment variable as well, allowing you to use the same environment variable as you did in sync.ps1 previously:

    RequestResponse
    <authenticationProvider type="Unicorn.ControlPanel.Security.ChapAuthenticationProvider, Unicorn">
      <SharedSecret>$(env:UNICORN_SHARED_SECRET)</SharedSecret>
    </authenticationProvider>
  3. Define this environment variable in your docker-compose.override.yml and .env:

    RequestResponse
    cm:
        [...]
        environment:
          UNICORN_SHARED_SECRET: ${UNICORN_SHARED_SECRET}
    RequestResponse
    UNICORN_SHARED_SECRET=your-secret-here

Run a sync

At this point, you have everything you need to trigger an item sync with Unicorn:

  • Serialized items on the filesystem of your CM container

  • Unicorn configured to use this path as its item source

  • The Unicorn shared secret configured via an environment variable

  • A PowerShell script to trigger the sync

When you want to deploy the items, whether manually or within your delivery pipeline, use docker exec, or the equivalent within your production container orchestrator:

RequestResponse
docker exec <container> powershell -command "c:\unicorn\sync.ps1"

Do you have some feedback for us?

If you have suggestions for improving this article,