Alright let’s address the elephant in the room! Kam Figy is not the creator of Unicorn, Kamruz Jaman is. This post is not mean to sing praises of Unicon or the Kams as we callz it. It is mainly to show how we use Unicorn to build our end to end deployment from a dev machine to the production CD’s using Unicorn for serialization.
If I have not said so before, I love VSTS and Octopus Deploy. I am not a master of either but I got a great deal of experience in the past year setting them up. I will follow up this blog post with Octopus posts but this one is reserved for Unicorn.
Unicorn != TDS && TDS != Unicorn. This has been said multiple times. Each has a few features which are common but they have their own set of features. TDS being that its a paid product has a lot of great features especially to do with deployment, builds etc.
So lets start. First you install Unicorn from NuGet:
Install-Package Unicorn -Version 3.3.2
This installs a set of configs and adds appropriate references to your project. If you plan on serializing roles, you would also need Unicorn.Roles:
Install-Package Unicorn.Roles -Version 3.3.2
By default, Unicorn provides sample configurations. Here are some I use:
<!-- A source folder param to be used later to specify folders where serialization will store files -->
This is an example of how to configure a basic Unicorn configuration using your own config patch file.
Copy this file to use as a basis for your own configuration definitions.
Enabled configuration definition patches should be present on all environments Unicorn is present on.
See Unicorn.config for commentary on how configurations operate, or https://github.com/kamsar/Unicorn/blob/master/README.md
The default configuration is an example to start making other configurations from.
WHAT SHOULD I INCLUDE?
In general, include the fewest items possible. This both makes things faster and reduces the amount of things kept in source control.
The most common candidates for serialization are layout items and template items, but Unicorn can serialize any type of item or field including media.
Configurations can override the default dependencies defined in Unicorn.config's <defaults> to apply
custom behaviors to specific configurations. They behave like an inherited IoC container.
Configurations may also depend on each other. Add a comma-delimited list of configuration names to depend on to the 'dependencies' attribute on the configuration.
Dependent configurations do not force dependencies to sync if not selected, but syncs will always occur in dependency order if multiple dependent configurations sync at once.
Transitive dependency and multiple dependency (comma delimited) are supported.
Favor using several configurations over a single monolithic one.
Favor using more includes and fewer excludes in your predicates.
Start with minimal configurations and add includes as you need to serialize new things.
Set the Project folder under the sourceFolder.
<targetDataStore physicalRootPath="$(sourceFolder)\PROJECTNAME" useDataCache="false" type="Rainbow.Storage.SerializationFileSystemDataStore, Rainbow" singleInstance="true"/>
<predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true">
<!-- Layouts - Simple content items, specify a unique name, database name and the path -->
<include name="Layouts_PROJECT" database="master" path="/sitecore/layout/Layouts/PROJECTNAME" />
<!-- using the right predicate is very important. Here we want Unicorn to take the parent node, exclude all children except the ones named.-->
<include name="FBPowershellScripts" database="master" path="/sitecore/system/Modules/PowerShell/Script Library">
<except name="Why Cant you be my friend" />
<except name="What did I ever do to you" />
<except name="All I wanted is to be your friend" />
<except name="Kamruz is the only Coveo MVP in the world" />
<!-- Core Settings - Notice the database value as core-->
<include database="core" path="/sitecore/system/Settings/Html Editor Profiles" />
<!-- As per the roles, as long as you have Unicron.Roles installed and you specify the following predicates you can sync roles across all environments -->
<roleDataStore type="Unicorn.Roles.Data.FilesystemRoleDataStore, Unicorn.Roles" physicalRootPath="$(sourceFolder)\Roles" singleInstance="true"/>
<rolePredicate type="Unicorn.Roles.RolePredicates.ConfigurationRolePredicate, Unicorn.Roles" singleInstance="true">
<include domain="sitecore" pattern="^ProjectName.*$" />
Traditional Sync (the default) updates the state of the database only when a sync operation is run. It supports additional operations but can be more of a chore to remember to sync.
Transparent Sync (preferred) updates the state of Sitecore instantly as soon as changes to files occur. It is optimal for development purposes, but has a few limitations.
See the guide to help decide: https://github.com/kamsar/Unicorn/wiki/The-Transparent-Sync-Guide
<dataProviderConfiguration enableTransparentSync="false" type="Unicorn.Data.DataProvider.DefaultUnicornDataProviderConfiguration, Unicorn" singleInstance="true" />
UpdateLinkDatabase: If true, the links will be updated for synced items after the sync has completed. If false (default) links are not updated for performance.
Updating links is important if you are syncing user-facing content where link tracking is important. It is not very important for system items (templates/renderings).
UpdateSearchIndex: If true, the search index(es) containing the item will be updated with item changes after the sync has completed. If false, indexing will not be updated for performance.
Updating the index is important for content that relies on indexing, which may include most user-facing content items. Most of the time templates and renderings don't need indexing.
MaxConcurrency: Controls how many threads Unicorn can use when syncing this configuration. Concurrency can usually increase sync speed 30-50% over single threading.
IF YOUR CONFIGURATION INCLUDES TEMPLATES YOU MUST SET THIS TO 1 OR YOUR SYNC WILL HANG INDEFINITELY DUE TO A SITECORE ISSUE
IF YOU ARE ON SITECORE 8.0 U2 OR EARLIER, YOU MUST SET THIS TO 1 DUE TO A SITECORE ISSUE
This value can be set to significantly higher than the number of CPU cores, as these are largely I/O bound.
Use fewer threads for HDDs or slow SQL servers, and more threads for SSDs.
For a SSD workload on a quad-core CPU 16 seems to be a decent number.
NOTE: UpdateLinkDatabase and UpdateSearchIndex also apply to items that are reloaded from disk when using Transparent Sync, as well as normal Sync.
<syncConfiguration updateLinkDatabase="false" updateSearchIndex="false" maxConcurrency="1" type="Unicorn.Loader.DefaultSyncConfiguration, Unicorn" singleInstance="true" />
SHARED SECRET CONFIGURATION EXAMPLE
This is a config file that can be used as a basis to set the Unicorn PowerShell remote API's shared secret
without altering the stock config file. Duplicate this file and set a long, 32+ character secret to enable
invoking Unicorn with the PowerShell API, e.g. for CI.
IMPORTANT: THIS CONFIG PATCH *MUST* RUN AFTER Unicorn.UI.config, or you will receive an error:
"Unable to cast object of type 'System.String' to type 'Unicorn.ControlPanel.Security.IUnicornAuthenticationProvider'."
See the README here for more on setting up remote API: https://github.com/kamsar/Unicorn
Need some randomness? Try here: https://www.random.org/passwords/?num=5&len=24&format=html&rnd=new
Writes the reason why failed automated tool authentications failed to the Sitecore logs.
Will result in writing your shared secret to the logs as part of the signature base,
so disable it unless you're debugging failed authentications.
I make sure that the config transforms locally point to the local serialization folder outside of the wwwroot on my dev box. This helps a lot in structuring your configs on all the environments. Using Octopus, we set the path for the serialization folder dynamically.
For your deployment:
- Package code and serialization separately in to different Nuget Packages. I use Nuspec files with Octopus Deploy.
- Once code is deployed, make sure you remove the Unicorn.DataProvider.config file from the destination CD/CM so that Unicorn does not serialize on those servers.
- Make sure the serialization folder on the destination system is wiped before your add it via Octopus or any other deployment tool.
- Deploy the serialization Nuget package.
- Use PowerShell to sync Unicorn serialized files automatically as part of your deployment process on the CM instances.
- On CD’s remove the Rainbow.config and Project.Unicron.Serialization.config files.
Here is a sample of the Octopus step of sync Unicorn via PowerShell:
$apppath = $OctopusParameters["sitecore.powershellfolder"]
$siteHostName = $OctopusParameters["website.url"]
$siteUrl = "$siteHostName/unicorn.aspx"
Sync-Unicorn -ControlPanelUrl $siteUrl -SharedSecret 'YOURSECREDKEYPLEASEUSEALONGONEANDBEMEEEFRIEND'
Since we deployed this 5 months ago, we have not touched it. We run through a few hundred deploys per week.
From dev to prod, we do not do any manual steps, everything is handled by Octopus and so far we have not yet gotten any Unicorn issues. If you do end up with an odd situation, Kam is reachable on the Sitecore Slack and he is very responsive.
If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).