Sitecore + Docker - Get a grip on your compose file
Entrée
There are multiple ways to compose your docker container and work with your Docker Compose files while working with Sitecore. One of them involves directly modifying the files you get when cloning the Sitecore Docker repository, and others revolves around extending, overriding resulting in the usage of multiple compose files.
If you're also wondering what is the impact of each of the options, which one is my preferred way of working with Sitecore Docker? I'll be covering those points in this article.
Table of content:
La Pièce de Résistance
Direct usage of the original docker-compose file
After cloning the repository, you'll get a set of compose files that will allow you to run docker on the spot.
While directly working and modifying the original is the best way to get started with Docker - as it gives the opportunity to explore and experiment, doing so, would result in me ending up with a custom docker compose file therefore preventing me from (1) having a reference when I would like to revert some of the changes and (2) I would voluntarily exclude myself from getting the latest version from the Github repository when they are updated.
When dealing with more lengthy compose file such as the one for XP, SXA and JSS, I find it particularily challenging to keep a record of my changes. I would end up spending my time cherry picking the change I would like to apply when the file I get the lastest from the master branch.
Usage of multiple compose files
Extending the original docker compose file
The extends
keyword of a Docker Compose file allows you to share common configuration amongst multiple files and can be extended to a project level as well.
For this use case, I will extend docker-compose.xp.sxa.jss.yml
as example.
When defining any service in a docker-compose file, you can declare that you are extending another service like so:
# original compose file
cm:
image: ${REGISTRY}sitecore-xp-sxa-jss-standalone:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
entrypoint: powershell.exe -Command "& C:\\tools\\entrypoints\\iis\\Development.ps1"
ports:
- "44001:80"
...
...
...
# new docker-compose.yml file on which the extends is applied.
services:
mysitecoreprojectname:
extends:
file: docker-compose.xp.sxa.jss.yml
service: cm
volumes:
- ./custom:C:/inetpub/wwwroot/etc/etc
ports:
- "44002:443"
# result
services:
mysitecoreprojectname:
volumes:
- ./custom:C:/inetpub/wwwroot/etc/etc
ports:
- "44001:80"
- "44002:443"
In this case, you'll get exactly what is defined in the cm
service from docker-compose.xp.sxa.jss.yml
in addition with what you've written in your custom docker compose file. That is: value from the ports
from both files + volumes
.
Side note: At the time of writing, the docker files found in the Github repository are shipped with some additional commands that ensures that the services will start in th right order as seen below.
depends_on:
sql:
condition: service_healthy
solr:
condition: service_started
xconnect:
condition: service_started
By using extend on the current compose files, you would end up with an error message like:
services with 'depends_on' cannot be extended
It is still possible to work with it but that would involves a slight modification of the original Docker compose files which might result in an unwanted behavior when you run the docker-compose up command.
Overriding the original Docker Compose
The override's command works approximately with the same principle as the extension command with the difference of having to give the override file a specific name such as docker-compose.override.yml
and rewrite the whole command when it is overwritten.
using the same example as above, I would proceed as below:
# original docker-compose.yml file
cm:
image: ${REGISTRY}sitecore-xp-sxa-jss-standalone:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
entrypoint: powershell.exe -Command "& C:\\tools\\entrypoints\\iis\\Development.ps1"
ports:
- "44001:80"
...
...
...
# new docker-compose.yml file on which the extends is applied.
services:
cm:
volumes:
- ./custom:C:/inetpub/wwwroot/etc/etc
ports:
- "44001:80"
- "44002:443"
# result
services:
cm:
volumes:
- ./custom:C:/inetpub/wwwroot/etc/etc
ports:
- "44001:80"
- "44002:443"
Instead of having a custom name for the service, we would have to use the same name as already declared in the original docker-compose.yml file. And here since we want to have another port for our SSL, we would have te rewrite the whole ports
command otherwise only the one defined in the override file will be executed.
When the normal docker-compose up
command will be triggered, the override will be automatically picked up.
The usage of -f as parameter
This might be the most straightforward extension of a compose file over a multiple set of compose files.
It is done by using the parameter -f
followed by the name/path of the file
docker-compose -f docker-compose.yml -f docker-compose.xxx.yml
Apply Docker Compose to my Development, Test, Acceptance and Production environments (DTAP)
Applying what is stated above, let's take into consideration that for every environments: DEV, TEST, ACC and PROD I have a specific set of configuration for each service; In our case let's take the connection string to the Sitecore database and the environment role.
How do I make sure that every environment composes the right configuration?
# original compose file provided by the github repo
cm:
environment:
SITECORE_APPSETTINGS_ROLE:DEFINE: Standalone
SITECORE_CONNECTIONSTRINGS_CORE: Data Source=sql;Initial Catalog=Sitecore.Core;User ID=sa;Password=${SQL_SA_PASSWORD}
...
...
# my docker.compose.override.yml for development machine
# would be empty because I want to use the original one to work on my development machine
# docker.compose.test.yml
cm:
environment:
SITECORE_APPSETTINGS_ROLE:DEFINE: ContentManagement
SITECORE_CONNECTIONSTRINGS_CORE: Data Source=test_sql;Initial Catalog=Sitecore.Core;User ID=sa;Password=${SQL_SA_PASSWORD}
...
...
# docker.compose.acc.yml
cm:
environment:
SITECORE_APPSETTINGS_ROLE:DEFINE: ContentManagement
SITECORE_CONNECTIONSTRINGS_CORE: Data Source=acc_sql;Initial Catalog=Sitecore.Core;User ID=sa;Password=${SQL_SA_PASSWORD}
...
...
# docker.compose.prod.yml
cm:
environment:
SITECORE_APPSETTINGS_ROLE:DEFINE: ContentManagement
SITECORE_CONNECTIONSTRINGS_CORE: Data Source=prod_sql;Initial Catalog=Sitecore.Core;User ID=sa;Password=${SQL_SA_PASSWORD}
...
...
When deploying my application, I'd run the below command to apply each environment's configuration
# Development Machine
docker-compose
# Test Environment
docker-compose -f docker-compose.yml -f docker-compose.test.yml
# Acceptance Environment
docker-compose -f docker-compose.yml -f docker-compose.acc.yml
# Production Environment
docker-compose -f docker-compose.yml -f docker-compose.prod.yml
Le dessert
In this article, I've explored some ways of working with docker while maintaining the original docker-compose file by leveraging the docker compose command. We saw that while modifying the original file is the most straightforward option and using the extends
command has its limitation (at this time of writing); the best way to get the job done is to override the original compose file by having a docker-compose.override.yml
to host your development machine specific configuration and a set of environement specific compose files for other environments such as Test, Acceptance and Production.
Are you running Sitecore on docker as well? I am really curious to know how did you solve this situation, let me know in the comment section below.