服务运行时中是否有任何地方可以告诉我当前是在“暂存”还是“生产”上运行?在生产环境中手动修改配置似乎有点麻烦。
6 回答
如果您在 Prod 或 Staging 中,您真的不应该更改您的配置。暂存区并非设计为“QA”环境,而只是部署生产之前的暂存区。
当您上传一个新的部署时,您上传包的当前部署槽被破坏,并且在上传和启动虚拟机的过程中关闭 10-15 分钟。如果您直接上传到生产环境,则需要 15 分钟的生产停机时间。因此,Staging 区域被发明了:你上传到 staging,测试这些东西,然后点击“Swap”按钮,你的 Staging 环境神奇地变成了 Production(虚拟 IP 交换)。因此,您的分期实际上应该与您的生产 100% 相同。
我认为您正在寻找的是质量保证/测试环境?您应该为具有自己的 Prod/Staging 的测试环境打开一个新服务。在这种情况下,您将需要维护多个配置文件集,每个部署环境(生产、测试等)一个集
有很多方法可以管理发生的配置地狱,尤其是在 .config 文件之上还有其自己的 *.cscfg 文件的 Azure。我更喜欢使用 Azure 项目的方式如下:设置一个小型 Config 项目,在那里创建与部署类型匹配的文件夹。在每个文件夹中设置与特定部署环境匹配的 *.config 和 *.cscfg 文件集:Debug、Test、Release...这些也是在 Visual Studio 中设置的,作为构建目标类型。我有一个小的 xcopy 命令,该命令在每次编译 Config 项目期间发生,它将所有文件从 Config 项目的 Build Target 文件夹复制到 Config 项目的根文件夹中。
然后解决方案中的每个其他项目,从 Config 项目的根文件夹链接到 .config 或 .cscfg 文件。
瞧,我的配置神奇地自动适应每个构建配置。我还使用 .config 转换来管理发布与非发布构建目标的调试信息。
如果您已经阅读了所有这些并且仍然希望在运行时获得生产与暂存状态,那么:获取deploymentId
然后RoleEnvironment.DeploymentId
使用管理 APIX509 certificate
来获取Azure structure of your Service
并调用该GetDeployments
方法(它是休息 api,但有一个抽象图书馆)。
希望这可以帮助
编辑:关于配置字符串设置和环境切换的博客文章@ http://blog.paraleap.com/blog/post/Managing-environments-in-a-distributed-Azure-or-other-cloud-based -NET-解决方案
有时我希望人们只回答这个问题......而不是解释道德或最佳实践......
微软在这里发布了一个代码示例:https ://code.msdn.microsoft.com/windowsazure/CSAzureDeploymentSlot-1ce0e3b5
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();
}
}
暂存是一个临时部署槽,主要用于无停机升级和回滚升级的能力。
建议不要将您的系统(无论是在代码中还是在配置中)与此类 Azure 细节结合起来。
由于Windows Azure 管理库并感谢@GuaravMantri回答另一个问题,您可以这样做:
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;
}
}
}
解决此问题的一种简单方法是在您的实例中设置一个键来识别它正在运行的环境。
1)在您的生产槽设置:设置它设置>>应用程序设置>>应用程序设置并创建一个名为SLOT_NAME的键和值“生产”。重要提示:检查插槽设置。
2)在你的暂存槽设置:设置它设置>>应用程序设置>>应用程序设置并创建一个名为SLOT_NAME的键和值“staging”。重要提示:检查插槽设置。
从您的应用程序访问变量并确定应用程序正在运行的环境。在 Java 中,您可以访问:
String slotName = System.getenv("APPSETTING_SLOT_NAME");
这里有4点需要考虑
- 只有当您的服务面向外部世界时,VIP 交换才有意义。AKA,当它公开一个 API 并对请求做出反应时。
- 如果您的服务所做的只是从队列中提取消息并处理它们,那么您的服务是主动的,VIP 交换对您来说不是一个好的解决方案。
- 如果您的服务既是被动的又是主动的,您可能需要重新考虑您的设计。也许将服务拆分为 2 个不同的服务。
- Eric 建议在 VIP 交换前后修改 cscfg 文件,如果您的服务的主动部分可以缩短停机时间(因为您首先将暂存和生产都配置为不提取消息,然后执行 VIP 交换,然后更新 Production 的配置以开始拉取消息)。