I want to deploy my code in a consistent, repetitive and automated manner. I want to be able to deploy it easily on a blank copy of Sitecore, and blow the whole thing away. I also want to minimize the amount of prerequisites in my computer. In my opinion the easiest way to achieve this is a containerised solution like Docker.
Annoyingly, Sitecore does not provide, yet, a ready-made image, but the community always comes to the rescue. I know several people have brewed their own recipes. When the other day I wanted to play with Sitecore 9 but I had no SQL server and no IIS in my computer I resorted to Per Manniche Bering's repo. I followed his simple instructions, extracting the right bits from the XM1 zip, let the computer work for a while and Sitecore 9 was up and running.
This was just the start - I then wanted to be able to deploy code. Usually you could use his image as a base to create a custom one. You could copy your source, compile, maybe using another image (the so-called builder pattern), de-serialize items, or install packages and essentially get your solution running. This is good for a CI, or a deployment set-up. For development, though, I would like a more agile method that does not require me to re-build the image every time.
Per's other repo Socker, which allows you to run Sitecore v8 on Docker, shows you how to do this. He basically shares the solution files and has a script monitoring changes and replicating them on the webroot folder.
There are other ways of achieving the same result. I will show a very simple solution that would allow me to work from Visual Studio, just like I am used to. The aim is that I can deploy from Visual Studio, and at most wait for the app to restart if I have deploy new DLLs.
The basic strategy involves:
- Configure Visual Studio to deploy to a folder
- Use Unicorn for serialization
- Share the deploy and serialization folders between the host and container
- Inside the image, copy the contents of the deploy folder to the webroot
Configure Visual studio deploy (publish)
This is just a standard publish profile (Publish... option in the Web Application project). Simply select a suitable folder location. I named my publish profile DeployToFolder.
Set up Unicorn
Install the Unicorn Nuget package. Configure which items should be serialized and a convenient serialization folder. Since we are going to be inside the container, this could be simply
Create a docker-compose file with the volume share
Next I will use the docker-compose file from Per's repository as a base but I will make a few changes. I will remove the context for the build, as I will assume the images have already been built and are available in my machine.
I will then set up the volume shares
cm: image: sc9xm1cm depends_on: - sql ports: - 80:80 links: - sql volumes: - type: bind source: ./output target: c:/output - type: bind source: ./serialization target: c:/serialization
Copy deploy folder to web root
Whenever I then deploy in Visual Studio, all the compilation artifacts will be available inside the container in the
c:\output folder. I just need to copy those to the webroot (in Per's images is
c:\inetpub\sc). This is a simple task for Robocopy.
docker exec [name of container] robocopy \output \inetpub\sc /S /XX
This is still a bit manual, as I have to publish in Visual Studio and then I have to invoke robocopy on the container. I could do better by having the publish process invoke the robocopy command automatically. Theoretically there is an AfterPublish task just for this purpose. Unfortunately it seems to be broken from Visual Studio, and also from invoking msbuild through the command line.
I had to settle for a slight hack. I added the following task to my project file:
<Target Name="DeployToDocker" AfterTargets="PipelineDeployPhase"> <Exec Command="docker exec itemrendererdemo_cm_1 robocopy \output \inetpub\sc /S /XX" IgnoreExitCode="true"/> </Target>
and invoke it through the command line
msbuild /p:DeployOnBuild=true /p:PublishProfile=DeployToFolder
Running this command will compile, deploy and then copy to the the webroot in the container. Robocopy is also intelligent enough not to copy unchanged files, so it won't force an app restart if I am simply changing a csthml or a css file.
Still, it would be good to get this to work from Visual Studio directly. This is why I configured an External Tool
I can then bind a keyboard shortcut to it, or add it as a button to a toolbar.
A full example is available from the ItemRendererDemo repository.