Staging or Production Instance?
Asked Answered
D

6

51

Is there anywhere in the service runtime that would tell me if I'm currently running on 'Staging' or 'Production'? Manually modifying the config to and from production seems a bit cumbersome.

Down answered 1/12, 2010 at 19:53 Comment(0)
A
78

You should really not change your configurations when you're based upon if you're in Prod or Staging. Staging area is not designed to be a "QA" environment but only a holding-area before production is deployed.

When you upload a new deployment, current deployment slot where you upload your package to is destroyed and is down for 10-15minutes while upload and start of VM's is happening. If you upload straight into production, that's 15 minutes of production downtime. Thus, Staging area was invented: you upload to staging, test the stuff, and click "Swap" button and your Staging environment magically becomes Production (virtual IP swap). Thus, your staging should really be 100% the same as your production.

What I think you're looking for is QA/testing environment? You should open up a new service for Testing environment with its own Prod/Staging. In this case, you will want to maintain multiple configuration file sets, one set per deployment environment (Production, Testing, etc.)

There are many ways to manage configuration-hell that occurs, especially with Azure that has on top of .config files, its own *.cscfg files. The way I prefer to do it with Azure project is as follows: Setup a small Config project, create folders there that match Deployment types. Inside each folder setup sets of *.config & *.cscfg files that match to particular deployment environment: Debug, Test, Release... these are setup in Visual Studio as well , as build target types. I have a small xcopy command that occurs during every compile of the Config project that copies all the files from Build Target folder of Config project into root folder of the Config project.

Then every other project in the solution, LINKS to the .config or .cscfg file from the root folder of the Config project.

Voila, my configs magically adapt to every build configuration automatically. I also use .config transformations to manage debugging information for Release vs. non-Release build targets.

If you've read all this and still want to get at the Production vs. Staging status at runtime, then: Get deploymentId from RoleEnvironment.DeploymentId Then use Management API with a proper X509 certificate to get at the Azure structure of your Service and call the GetDeployments method (it's rest api but there is an abstraction library).

Hope this helps

Edit: blog post as requested about the setup of configuration strings and switching between environments @ http://blog.paraleap.com/blog/post/Managing-environments-in-a-distributed-Azure-or-other-cloud-based-NET-solution

Addington answered 2/12, 2010 at 0:41 Comment(13)
Hi Igorek, can you please supply us some code samples or step-by-step guidance with it ? I am having also problems with web.config in Azure per environment....Baxie
Eight months later, but here it is: paraleap.com/blog/post/…Addington
@Addington Great blog post! :) I'm tempted to switch to your method in futureWeems
FYI the images are down on your blog. Great info.Columbium
Images have been restored. Appreciate the patienceAddington
This information is great. Can someone point me in the right direction on how to handle external resources like a database while swapping IPs? For example Production code points to the Production database. When I upload Staging code with the productions web.config it does point to the production database, which stills in the old version; the staging application will not work because compatibility .Laverty
Why someone might actually WANT to do what the OP asked: donovanbrown.com/post/2015/02/13/…Cl
@JoshuaDrake point of staging slot in this case is to be able to swap back /very easily/ if something goes wrong. When DB schema changes, as the core underlying reason for ignoring this assumption, would not allow swapping back and thus is not a good example why Staging slot should hold non-production code. For 95% of the time Staging slot holds for "production" code and should be used as such. When DB changes, dont use staging slot at all.Addington
The underlying issue is that Staging is too ambiguous a word. When we used to VIP flip in production we never called it a staging environment, though I understand, and may even appreciate the common English usage, I am not certain that it was the best choice, as is evidenced by the OP, comments on your answer, and the additional upvotes for answers below. Some people use a staging environment for UAT testing, and in that case they want their configuration between staging and production to be different.Cl
I'm not going to argue that Staging is not the best name for the slot... It is not the name that matters, but its purpose. And its purpose is not to be a pre-production environment, but only a last point on the path of pushing Production.Addington
The reason I need to know is I do not want page load times recorded in staging while the site is warming up as it does not effect the users.Thunder
@Addington the link to the blog post is broken. Could you update it, please?Xi
@EvgeniNabokov I have fixed the broken link, per your request.Twi
M
57

Sometimes I wish people would just answer the question.. not explain ethics or best practices...

Microsoft has posted a code sample doing exactly this here: https://code.msdn.microsoft.com/windowsazure/CSAzureDeploymentSlot-1ce0e3b5

image showing Staging instance

image showing Production instance

protected void Page_Load(object sender, EventArgs e) 
{ 
    // You basic information of the Deployment of Azure application. 
    string deploymentId = RoleEnvironment.DeploymentId; 
    string subscriptionID = "<Your subscription ID>"; 
    string thrumbnail = "<Your certificate thumbnail print>"; 
    string hostedServiceName = "<Your hosted service name>"; 
    string productionString = string.Format(
        "https://management.core.windows.net/{0}/services/hostedservices/{1}/deploymentslots/{2}",
        subscriptionID, hostedServiceName, "Production"); 
    Uri requestUri = new Uri(productionString); 

    // Add client certificate. 
    X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
    store.Open(OpenFlags.OpenExistingOnly); 
    X509Certificate2Collection collection = store.Certificates.Find(
        X509FindType.FindByThumbprint, thrumbnail, false); 
    store.Close(); 

    if (collection.Count != 0) 
    { 
        X509Certificate2 certificate = collection[0]; 
        HttpWebRequest httpRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri); 
        httpRequest.ClientCertificates.Add(certificate); 
        httpRequest.Headers.Add("x-ms-version", "2011-10-01"); 
        httpRequest.KeepAlive = false; 
        HttpWebResponse httpResponse = httpRequest.GetResponse() as HttpWebResponse;

        // Get response stream from Management API. 
        Stream stream = httpResponse.GetResponseStream(); 
        string result = string.Empty; 
        using (StreamReader reader = new StreamReader(stream)) 
        { 
            result = reader.ReadToEnd();
        } 
        if (result == null || result.Trim() == string.Empty) 
        {
            return;
        }
        XDocument document = XDocument.Parse(result); 
        string serverID = string.Empty; 
        var list = from item
                   in document.Descendants(XName.Get("PrivateID",
                       "http://schemas.microsoft.com/windowsazure")) 
                   select item; 

        serverID = list.First().Value; 
        Response.Write("Check Production: "); 
        Response.Write("DeploymentID : " + deploymentId
            + " ServerID :" + serverID); 
        if (deploymentId.Equals(serverID)) 
            lbStatus.Text = "Production"; 
        else 
        { 
            // If the application not in Production slot, try to check Staging slot. 
            string stagingString = string.Format(
                "https://management.core.windows.net/{0}/services/hostedservices/{1}/deploymentslots/{2}",
                subscriptionID, hostedServiceName, "Staging"); 
            Uri stagingUri = new Uri(stagingString); 
            httpRequest = (HttpWebRequest)HttpWebRequest.Create(stagingUri); 
            httpRequest.ClientCertificates.Add(certificate); 
            httpRequest.Headers.Add("x-ms-version", "2011-10-01"); 
            httpRequest.KeepAlive = false; 
            httpResponse = httpRequest.GetResponse() as HttpWebResponse; 
            stream = httpResponse.GetResponseStream(); 
            result = string.Empty; 
            using (StreamReader reader = new StreamReader(stream)) 
            { 
                result = reader.ReadToEnd();
            } 
            if (result == null || result.Trim() == string.Empty) 
            {
                return;
            }
            document = XDocument.Parse(result); 
            serverID = string.Empty; 
            list = from item
                   in document.Descendants(XName.Get("PrivateID",
                       "http://schemas.microsoft.com/windowsazure")) 
                   select item; 

            serverID = list.First().Value; 
            Response.Write(" Check Staging:"); 
            Response.Write(" DeploymentID : " + deploymentId
                + " ServerID :" + serverID); 
            if (deploymentId.Equals(serverID)) 
            {
                lbStatus.Text = "Staging";
            }
            else 
            {
                lbStatus.Text = "Do not find this id";
            }
        } 
        httpResponse.Close(); 
        stream.Close(); 
    } 
}
Mohn answered 29/10, 2014 at 18:26 Comment(1)
"Sometimes I wish people would just answer the question.. not explain ethics or best practices... " - Amen brotherArmadillo
E
8

Staging is a temporary deployment slot used mainly for no-downtime upgrades and ability to roll back an upgrade.

It is advised not to couple your system (either in code or in config) with such Azure specifics.

Elmer answered 2/12, 2010 at 6:53 Comment(6)
That's great and fine, except when your services are pulling jobs out of a queue and causing side-effects before you swap VIPs unless you have a way to tell them not to do that when they're in staging. In that case, you need a way to tell your service not to do things like that until it gets to Production.Tumer
Exactly, which is the problem I have. My worker role gets events from my service bus queue when a new message arrives. I don't want it hooking up to the "real" production queue until it gets to the "real" production environment, so you aren't the only one with this issue.Gabbard
This has been Microsoft's stance all along, and while ideal and purist, doesn't work for the reasons stated above. We simply modify the cscfg pre- and post- VIP swap with a value that indicates the slot of the instance. Simple, reliable, and easy.Regression
Jaxidian is quite right; Azure in the new portal currently has a "Slot Setting" checkbox for App Settings that will make the particular application setting "stick" to that slot. In our case, we have an "AzureSlotName" setting which we set to "production", we make it "stick to the slot", and then just test for that.Nuli
As far as I can see (I've just spent some time Googling it), the concept of slot stickiness exists only in web apps, not in cloud services.Regin
Also see: donovanbrown.com/post/2015/02/13/… for why someone may care.Cl
G
6

Since Windows Azure Management Libraries and thanks to @GuaravMantri answer to another question you can do it like this :

using System;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Azure;
using Microsoft.WindowsAzure.Management.Compute;
using Microsoft.WindowsAzure.Management.Compute.Models;

namespace Configuration
{
    public class DeploymentSlotTypeHelper
    {
        static string subscriptionId = "<subscription-id>";
        static string managementCertContents = "<Base64 Encoded Management Certificate String from Publish Setting File>";// copy-paste it
        static string cloudServiceName = "<your cloud service name>"; // lowercase
        static string ns = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration";

        public DeploymentSlot GetSlotType()
        {
            var managementCertificate = new X509Certificate2(Convert.FromBase64String(managementCertContents));
            var credentials = new CertificateCloudCredentials(subscriptionId, managementCertificate);

            var computeManagementClient = new ComputeManagementClient(credentials);
            var response = computeManagementClient.HostedServices.GetDetailed(cloudServiceName);
            return response.Deployments.FirstOrDefault(d => d.DeploymentSlot == DeploymentSlot.Production) == null ? DeploymentSlot.Staging : DeploymentSlot.Production;
        }
    }
}
Goodfornothing answered 29/6, 2015 at 11:51 Comment(0)
M
5

An easy way to solve this problem is setting at your instances an key to identify which environment it is running.

1) Set at your production slot: Set it Settings >> Application settings >> App settings And create a key named SLOT_NAME and value "production". IMPORTANT: check Slot setting.

2) Set at your staging slot: Set it Settings >> Application settings >> App settings And create a key named SLOT_NAME and value "staging". IMPORTANT: check Slot setting.

Access from your application the variable and identify which environment the application is running. In Java you can access:

String slotName = System.getenv("APPSETTING_SLOT_NAME");
Muldrow answered 3/3, 2016 at 14:55 Comment(1)
This works only for App Services - NOT Cloud ServicesViscount
J
1

Here are 4 points to consider

  1. VIP swap only makes sense when your service faces the outside world. AKA, when it exposes an API and reacts to requests.
  2. If all your service does is pull messages from a queue and process them, then your services is proactive and VIP swap is not a good solution for you.
  3. If your service is both reactive and proactive, you may want to reconsider your design. Perhaps split the service into 2 different services.
  4. Eric's suggestion of modifying the cscfg files pre- and post- VIP swap is good if the proactive part of your service can take a short down time (Because you first configure both Staging and Production to not pull messages, then perform VIP Swap, and then update Production's configuration to start pulling messages).
Jeanniejeannine answered 24/10, 2014 at 17:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.