This presentation will describe an approach to using Sitecore Azure within a Continuous Delivery pipeline.
This is not about Continuous Delivery/Deployment, but about how Sitecore Azure fits into those methodologies.
Continuous Delivery 101
1) ARCHITECTURE
2) CODE
3) TIPS + TRICKS
Example Architecture with Sitecore Azure
Deployment continues as normal, up to the Content Management server that has the Sitecore Azure module installed.
Once code and content is deployed to the Content Management server, then the Sitecore Azure module is invoked via HTTP Requests to start the deployment process, and later the role swap process. The code provides the HTTP Request interface.
Sitecore Azure Deployment and Swap
1) ARCHITECTURE
2) CODE
3) TIPS + TRICKS
Sitecore Azure Terminology
We require a Sitecore context to run the Sitecore Azure commands, therefore we need to intercept HTTP requests via the HttpRequestBegin pipeline. When invoked, the service will find deployments for given subscription, and call 'Upgrade Files' command.
public AzureDeployments GetDeployments()
{
var azureDeployments = new AzureDeployments {
SubscriptionId = _configurationProvider.Settings.SubscriptionId
};
//Get list of environments
IEnumerable environments =
Environments.Environment.GetEnvironments(azureDeployments.SubscriptionId);
if (environments != null)
{
foreach (var environment in environments)
{
//Create new environment
var azureEnvironment = new AzureEnvironment {
EnvironmentId = environment.EnvironmentId,
Environment = environment.DisplayName };
foreach (var deployment in environment.GetDeployments())
{
//Add deployment to collection
azureEnvironment.Deployment.Add(
new AzureDeployment
{
DeploymentId = deployment.ID.ToString(),
Location = deployment.WebRole.Farm.Location.Name,
DeploymentName = deployment.DisplayName,
DeploymentType = deployment.DeploymentType.ToString(),
DeploymentSlot = deployment.DeploymentSlot.ToString(),
HostedServiceName = deployment.HostedServiceName,
Databases = deployment.DatabaseReferences.DisplayName
});
}
//Add environment to collection
azureDeployments.Deployments.Add(azureEnvironment);
}
}
else
{
//Log action
Log.Info(string.Format("No deployments found for Subscription ID : {0}",
_configurationProvider.Settings.SubscriptionId), this);
}
return azureDeployments;
}
public AzureDeployments GetDeployments()
{
var azureDeployments = new AzureDeployments {
SubscriptionId = _configurationProvider.Settings.SubscriptionId
};
//Get list of environments
IEnumerable environments =
Sitecore.Azure.Deployments.Environments.Environment.GetEnvironments(azureDeployments.SubscriptionId);
if (environments != null)
{
foreach (var environment in environments)
{
//Create new environment
var azureEnvironment = new AzureEnvironment {
EnvironmentId = environment.EnvironmentId,
Environment = environment.DisplayName };
foreach (var deployment in environment.GetDeployments())
{
//Add deployment to collection
azureEnvironment.Deployment.Add(
new AzureDeployment
{
DeploymentId = deployment.ID.ToString(),
Location = deployment.WebRole.Farm.Location.Name,
DeploymentName = deployment.DisplayName,
DeploymentType = deployment.DeploymentType.ToString(),
DeploymentSlot = deployment.DeploymentSlot.ToString(),
HostedServiceName = deployment.HostedServiceName,
Databases = deployment.DatabaseReferences.DisplayName
});
}
//Add environment to collection
azureDeployments.Deployments.Add(azureEnvironment);
}
}
else
{
//Log action
Log.Info(string.Format("No deployments found for Subscription ID : {0}",
_configurationProvider.Settings.SubscriptionId), this);
}
return azureDeployments;
}
public void UpdateFiles()
{
//If no subscriptionId passed in parameters then use configuration provided id
var subscriptionId = _configurationProvider.Settings.SubscriptionId;
//Get list of environments
IEnumerable environments =
Sitecore.Azure.Deployments.Environments.Environment.GetEnvironments(subscriptionId);
//Loop through environments and deployments
foreach (var deployment in environments.SelectMany(
environment => AzureDeploymentManager.Current.GetDeployments(environment)))
{
AzureDeploymentManager.Current.UpgradeDeploymentAsync(deployment);
Log.Info(string.Format("Updated deployment : {0}", deployment.DisplayName), this);
}
}
public void UpdateFiles()
{
//If no subscriptionId passed in parameters then use configuration provided id
var subscriptionId = _configurationProvider.Settings.SubscriptionId;
//Get list of environments
IEnumerable environments =
Sitecore.Azure.Deployments.Environments.Environment.GetEnvironments(subscriptionId);
//Loop through environments and deployments
foreach (var deployment in environments.SelectMany(
environment => AzureDeploymentManager.Current.GetDeployments(environment)))
{
AzureDeploymentManager.Current.UpgradeDeploymentAsync(deployment);
Log.Info(string.Format("Updated deployment : {0}", deployment.DisplayName), this);
}
}
public void SwapDeployments()
{
//If no subscriptionId passed in parameters then use configuration provided id
var subscriptionId = _configurationProvider.Settings.SubscriptionId;
//Get list of environments
IEnumerable environments =
Sitecore.Azure.Deployments.Environments.Environment.GetEnvironments(subscriptionId);
//Loop through environments and deployments
foreach (var deployment in environments.SelectMany(environment => AzureDeploymentManager.Current.GetDeployments(environment)))
{
AzureDeploymentManager.Current.SwapAsync(deployment);
Log.Info(string.Format("Swapped deployment : {0}", deployment.DisplayName), this);
}
}
public void SwapDeployments()
{
//If no subscriptionId passed in parameters then use configuration provided id
var subscriptionId = _configurationProvider.Settings.SubscriptionId;
//Get list of environments
IEnumerable environments =
Sitecore.Azure.Deployments.Environments.Environment.GetEnvironments(subscriptionId);
//Loop through environments and deployments
foreach (var deployment in environments.SelectMany(environment => AzureDeploymentManager.Current.GetDeployments(environment)))
{
AzureDeploymentManager.Current.SwapAsync(deployment);
Log.Info(string.Format("Swapped deployment : {0}", deployment.DisplayName), this);
}
}
Deployment Success!
1) ARCHITECTURE
2) CODE
3) TIPS + TRICKS
Sitecore Azure does not provide any alerting out of the box. When used in a CD pipeline, this means that the final deployment could fail (or succeed) without alerting anyone.
To get around this, add a pipeline processor into the 'UpgradeDeployment' pipeline.
<UpgradeDeployment patch:source="Sitecore.Azure.config">
<processor type="Sitecore.Azure.Pipelines.DeployAndRun.Azure.ResolveSources, Sitecore.Azure"/>
<processor type="Sitecore.Azure.Pipelines.DeployAndRun.Azure.CreatePackage, Sitecore.Azure"/>
<processor type="Sitecore.Azure.Pipelines.DeployAndRun.Azure.Upload, Sitecore.Azure"/>
<processor type="Sitecore.Azure.Pipelines.UpgradeDeployment.Upgrade, Sitecore.Azure"/>
<processor type="Sitecore.Azure.Pipelines.UpgradeDeployment.WaitForInitialization, Sitecore.Azure"/>
<processor type="Sitecore.Azure.Pipelines.DeployAndRun.Azure.Finalize, Sitecore.Azure"/>
Add processor for monitoring here
</UpgradeDeployment>
<SwapAzureDeployment patch:source="Sitecore.Azure.config">
<processor type="Sitecore.Azure.Pipelines.SwapAzureDeployment.SwapAzureDeployment, Sitecore.Azure"/>
Add processor for monitoring here
</SwapAzureDeployment>
Thanks for listening!
@brooksyd2dbs
dbs@sitecore.net