Microsoft Azure

自动化 Azure 网站的创建、开发和部署

Gyan Jadal

下载代码示例

Microsoft Azure 是一种为您的云使用者创建和部署网站或 API 的快速而简单的方法。关于 Azure 网站的不同方面(包括安全性、部署等)已有不少可供参考的资料。而将这些信息运用于实际实施中始终是一个挑战。在本文中,我将这些方面的信息融为一体,以帮助您快速创建可随时投入使用的 Azure 网站。我将向您详细介绍创建、部署、配置和监视 Azure 网站的整个端到端生命周期。

我首先使用 Visual Studio 2013 创建一个网站,并将其部署到 Azure。然后,我将设置从我的源代码存储库到 Azure 的持续集成,以建立使用 API 密钥或证书的身份验证。最后,我将演示如何使用 Windows PowerShell 创建站点并将其部署到生产环境。

创建 Azure 网站

这是整个过程中最简单的一步。我将创建一个 Azure 网站并添加一个控制器,跳过其内部的业务逻辑以说明关键点。开始之前,我需要 Windows Azure SDK for .NET 2.5(可以从 bit.ly/1GlhJpu 下载)。

在 Visual Studio 2013 中,我将选择空模板来创建新的 ASP.NET Web 应用程序。如果想要使用同一网站公开接口,您可以选择 WebAPI。我选中“AppInsights”和“在 Azure 中托管”复选框。我现在没有选取任何身份验证,因为稍后会添加。我还将配置用于部署到不同环境的 Application Insights。

当提示需要 Azure 网站详细信息时(如图 1 所示),我将输入站点名称并选择区域,然后单击“确定”。

这将设置一个空的网站并将其发布到 Azure。现在,我要向网站添加一些内容,并使用 Open Web Interface for .NET (OWIN) 作为中间件。为了启用 OWIN,我将添加以下 NuGet 包:Microsoft.Owin.Host.SystemWeb 和 Microsoft.AspNet.WebApi.Owin。

配置 Microsoft Azure 网站详细信息
图 1 配置 Microsoft Azure 网站详细信息

安装 NuGet 包后,我右键单击该项目并选择“添加 OWIN”启动类。我将该类命名为 Startup,并将以下代码添加到 Configuration 方法,它将设置控制器路由:

public void Configuration(IAppBuilder app) {
  var config = new HttpConfiguration();
  config.Routes.MapHttpRoute("default", "{controller}/{id}",
    new { id = RouteParameter.Optional});
  app.UseWebApi(config);
}

接下来,我将通过右键单击该项目并单击“添加 Web API 控制器”类添加一个控制器以提供 API。我将此类命名为 MyWebController 并保留生成的代码。接下来,我右键单击“项目”和“发布”。在“设置”选项卡下的发布对话框中,我将选择调试配置,以便站点可以进行远程调试。然后,我单击“下一步”和“发布”。

当我导航到我的 Azure 网站时,将默认调用控制器 Get 方法,返回一个 JSON 字符串作为 ["value1","value2"]。我的网站在 Azure 上启动并运行。到目前为止一切顺利。

现在,我将添加一个客户端应用程序,以调用我刚才在云上公开的网站 API。我创建了一个名为 MyConsoleClient 的新控制台应用程序,并添加了 ASP.NET Web API 2.2 客户端库 NuGet 包。此包可提供我将用于调用该 API 的 HttpClient 对象。以下代码将添加到 main 方法中:

var httpClient = new HttpClient();
var requestMineType = 
  new MediaTypeWithQualityHeaderValue("application/json");
httpClient.DefaultRequestHeaders.Accept.Add(requestMineType);
var httpResponse =
  httpClient.GetAsync(
  "https://MyAzureWebsiteSample.azurewebsites.net/MyWeb").Result;
Console.WriteLine(httpResponse.Content.ReadAsStringAsync().Result);
Console.ReadLine();

现在,我将运行客户端并查看控制器 Get 方法的调用方式以及 ["value1","value2"] 在控制台上的打印方式。我针对我的网站发布了调试配置。尽管您可以本地调试该站点,但在网站仍处于开发阶段时,采用远程方式调试已发布网站有时候很有用。为了调试已发布网站,我转到其门户的“配置”选项卡上启用远程调试,选择使用的 Visual Studio 版本(参见图 2)。

为 Microsoft Azure 网站启用远程调试
图 2 为 Microsoft Azure 网站启用远程调试

为了远程调试该网站和我的控制台客户端,我在 GetAsync 行上放置了一个断点。接下来,我打开服务器资源管理器,右键单击该网站并选中“附加调试器”,如图 3 所示。

将调试器附加到已发布网站
图 3 将调试器附加到已发布网站

现在,我可以单步执行代码、从我的计算机上远程调试网站并将我的更改提交到源代码存储库。

设置持续集成

现在,我将完成我的站点与源代码存储库的集成以实现持续集成 (CI)。每当您向存储库签入代码时,就会生成网站项目并自动部署到 Azure,这难道不酷吗?Azure 网站的“集成源控件”功能使您可以轻松地将您的源代码存储库链接到 Azure 网站以实现持续集成。在 Azure 门户中,我导航到该网站的主页选项卡并单击源控件中的“设置部署”,如图 4 所示。

从源控件设置部署
图 4 从源控件设置部署

根据您使用的源控件提供程序,您可以从 Visual Studio Online、本地 Git 存储库、GitHub 等选项中进行选择。由于我的代码位于 Visual Studio Online 存储库中,因此我在下一个屏幕上进行了相应选择。接下来,我输入我的 Visual Studio Online 帐户名称并授权我的帐户。我需要同意允许从 Azure 到我的 Visual Studio Online 帐户的连接请求。然后,我选择存储库名称,这是我的团队项目名称。单击“下一步”后就会在我的 Azure 网站和 Visual Studio Online 团队项目之间建立链接。

在 Visual Studio 的团队资源管理器中的“生成”选项中,我现在应当看到为我创建的作为 MyAzureWebsite­Sample_CD 的生成定义,因此我可以右键单击并编辑该定义。默认情况下,常规选项卡上的队列处理已禁用,因此我将其设为“已启用”。在“生成/项目”下的进程参数中,我浏览并选择要构建的解决方案。

此时,我将在“进程”选项卡中对进程参数进行一些其他更改。在“进程”选项卡上时,查看部署参数。这是针对生成定义设置到 Azure 服务的集成的位置。如果您在存储库中有多个项目,将部署按字母顺序排在第一的网站。若要避免此问题,请确保您为其启用 CI 的每个网站都有一个单独的解决方案。签入代码或者右键单击,然后对生成进行排队。您应看到网站正在生成并发布到了 Azure。

您可以通过单击该网站的“部署”选项卡验证持续集成是否正常工作,如图 5 所示。在这里,您将看到 CI 生成中最近一次的成功部署。

持续集成中的部署历史
图 5 持续集成中的部署历史

配置身份验证

Azure 网站现在已准备好进行开发、添加业务功能并获得 CI 的好处。您需要为该站点设置身份验证,以便您可以对使用者进行身份验证和授权。对于此设置有着不同的方案,您可通过 bit.ly/1CHVni3 进行详细了解。

在我为自己的 Azure 网站设置身份验证之前,我需要将 Authorize 属性添加到我的控制器并发布该站点。运行客户端访问此站点将返回以下消息:

{"Message": "Authorization has been denied for this request."}

在这里,我将在我的 Azure 网站上启用身份验证并更新控制台客户端,以提供 API 密钥或证书凭据进行身份验证。身份验证和令牌生成将委派给 Azure Active Directory (AAD)。图 6 显示了客户端、AAD 和服务之间的身份验证工作流。

Azure Active Directory 身份验证工作流
图 6 Azure Active Directory 身份验证工作流

对于 AAD 身份验证,客户端和网站都应在 AAD 上注册相应的应用程序条目。为此,我导航到门户上的 Active Directory 选项卡,选择 org. 目录并单击“应用程序”。接下来,我选择“添加应用程序/添加我的组织正在开发的应用程序”,并输入该网站的名称。

在本例中,我输入 MyAzureWebsiteSample,然后选择 Web 应用程序或 Web API 选项并单击“下一步”。在下一个屏幕上,我为登录 URL 输入一个地址以供在 MyAzureWebsiteSample.azurewebsites.net 上打开我的网站时使用,并输入 [mydomain].onmicrosoft.com/MyAzureWebsiteSample 作为应用程序 ID URI,然后单击“确定”。这将为网站创建 AAD 应用程序。接下来,我将客户端应用程序条目添加到 AAD,重复相同的步骤。对于登录 URL 和应用程序 ID URI,我输入 http://myconsoleclient。

由于这是客户端应用程序,它不必是物理的 URL;有效的 URI 就足够了。现在,我想要让客户端在经过身份验证后即可访问 MyAzureWebsiteSample 应用程序。为此,在“配置”选项卡上,在“其他应用程序的权限”部分中,我单击“添加应用程序”,此操作将打开一个弹出窗口。我选择“显示其他”并搜索 MyAzureWebsiteSample,然后选择它并单击“确定”。返回到“配置”选项卡,“委派权限”中是访问 MyAzureWebsiteSample 的权限(参见图 7)。将其勾选,然后单击“添加应用程序”。

在客户端应用程序上设置权限以访问 Azure Active Directory 中的 Azure 网站
图 7 在客户端应用程序上设置权限以访问 Azure Active Directory 中的 Azure 网站

此外,我会记录客户端应用程序条目的 ClientId,因为很快就会用到。如果您想要使用 API 密钥进行身份验证,则密钥将在此配置页上创建。因为我使用的是证书身份验证,所以我需要将我的证书与 AAD 中的客户端应用程序条目相关联。为此,我将使用 Windows PowerShell 的 Azure AD 模块来自动化此过程。您可以在 bit.ly/1D4gt8j 下载此模块。

我将运行以下 Windows PowerShell 命令以从本地计算机导入 .cer 文件,并将证书上载至客户端应用程序条目:

Connect-msolservice
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate
$cer.Import("$pwd\MyConsoleClientCert.cer")
$binCert = $cer.GetRawCertData()
$credValue = [System.Convert]::ToBase64String($binCert);
New-MsolServicePrincipalCredential -AppPrincipalId "<client id>" -Type asymmetric -Value $credValue -StartDate $cer.GetEffectiveDateString() -EndDate $cer.GetExpirationDateString() -Usage verify

在此命令中的 clientid 来自我上一步中的复制。若要验证证书是否已成功上载,可运行以下提供 clientid 的 cmdlet :

Get-MsolServicePrincipalCredential -AppPrincipalId "<clientid>" -ReturnKeyValues 1

这将显示与该 clientid 关联的所有证书。在本例中,其将显示一个。我在 AAD 中完成了对我的应用程序的设置。下一步是启用我将使用 AAD 进行身份验证的网站和客户端。首先,我将更新要针对 AAD 设置的 MyAzureWebsiteSample 项目。我将添加以下与身份验证相关的 OWIN 安全 NuGet 包:Microsoft.Owin.Security 和 Microsoft.Owin.Security.ActiveDirectory。

在 MyAzureWebsiteSample 的 Startup 类中,我将以下代码添加到 Configuration 方法中:

app.UseWindowsAzureActiveDirectoryBearerAuthentication(
  new WindowsAzureActiveDirectoryBearerAuthenticationOptions {
    TokenValidationParameters = new TokenValidationParameters
      {
        ValidAudience = "https://[mydomain].onmicrosoft.com/MyAzureWebsiteSample",
        ValidateAudience = true,
      },
      Tenant = "[mydomain].onmicrosoft.com"
});

您需要将 [mydomain] 替换为您的 AAD 目录域的名称。这将告诉网站针对指定的受众 URI 使用 ADD 身份验证。客户端访问该服务将需要提供此 URI 以从 AAD 中获取令牌。在客户端控制台上,我针对身份验证逻辑使用 Active Directory 身份验证库(也称为 ADAL),并将 MyConsoleClient NuGet 包添加到控制台应用程序。

ADAL

在客户端中,我将使用 ADAL 提供的 API 来通过提供证书凭据从 AAD 获取令牌。我使用图 8 中的代码替换了之前添加的代码,其中包括身份验证。

图 8 添加身份验证到 API

var httpClient = new HttpClient();
var requestMineType = new MediaTypeWithQualityHeaderValue("application/json");
  httpClient.DefaultRequestHeaders.Accept.Add(requestMineType);
var authContext = new  AuthenticationContext(
  "https://login.windows.net/[mydomain].onmicrosoft.com");
var clientAssertionCertificate = new ClientAssertionCertificate("<clientId>",
  GetX509CertObject("CN=MyClientConsoleCert"));
var authResult = authContext.AcquireTokenAsync(
  "https://[mydomain].onmicrosoft.com/MyAzureWebsiteSample",
  clientAssertionCertificate).Result;
httpClient.DefaultRequestHeaders.Authorization =
  new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
var httpResponse =
  httpClient.GetAsync(
  "https://MyAzureWebsiteSample.azurewebsites.net/MyWeb").Result;
Console.WriteLine(httpResponse.Content.ReadAsStringAsync().Result);
Console.ReadLine();

您需要用您自己的 clientid 和证书名称来替换我的 clientid 和证书名称。我已将证书检索代码提取到 GetX509CertObject 方法中,以读取证书存储并创建 X509Certificate 对象。如果您使用 APIKey 而不是证书身份验证,则您将构造传入 clientId 和门户中记录下的 APIKey 的 ClientCredential 对象,而不是传递 ClientAssertionCertificate 对象。如果没有提供客户端凭据来获取令牌,则会收到输入 AAD 租户用户凭据的提示。

我运行图 8 中的代码来对客户端进行身份验证,调用 MyAzureWebsiteSample 控制器方法和打印 ["value1","value2"]。控制器上会显示我可以用来进一步授权客户端的客户端声明。

自动化部署

迄今为止,我使用开发环境部署 Azure 网站。只需签入代码就可部署该网站,或右键单击,它就会发布 - 就是这么简单。

但是,对于 QA 或生产环境并不是如此。若要从 Visual Studio 进行部署,这种方式可能不可行。现在,我将介绍如何使用 Windows PowerShell 自动化到任何环境的部署。我同样可以从门户执行所有这些步骤,但这也将涉及许多手动步骤。

Azure PowerShell 提供了用于创建网站、存储等 Azure 资源的 cmdlet。我将突出介绍我的自动化脚本中的几个重要方面。本文附带的源代码下载中提供了完整的脚本。Azure PowerShell 中的资源管理器模式允许您通过逻辑方式将多个资源(如网站、redis 缓存、SQL Azure 和其他资源)分组为资源组。我使用 Switch-azuremode cmdlet 在 ResourceManager 模式和 ServiceManagement 模式之间切换我的 Azure PowerShell 环境。

下面的代码说明了脚本中值得注意的几点。首先,Add-azureaccount 会显示一个提示我登录我的 Azure 帐户的交互式窗口。Select-azuresubscription 设置当前订阅。然后,我切换到 ResourceManager 模式,新建一个 ResourceGroup 并将我的网站添加为新资源:

$SubscriptionId = "<subscriptionid>"
Add-AzureAccount
Select-AzureSubscription -SubscriptionId $SubscriptionId -Current
Switch-AzureMode -Name AzureResourceManager
$myResourceGroup = New-AzureResourceGroup -Name "MyResourceGroup" -Location "West US"
$mywebsite = New-AzureResource -Name "MyAzureWebsiteSample"
  -ResourceType "Microsoft.Web/sites" -ResourceGroupName "MyResourceGroup"
  -Location "West US" -ApiVersion "2014-04-01" -PropertyObject @{}

我将资源类型用作 Microsoft.Web/sites。有其他您可以使用 New-resource cmdlet 创建的资源类型,例如 Microsoft.Sql/servers/databases。在此代码段中,我将创建一个与我的网站关联的 AzureStorageAccount,以存储诊断跟踪。在这里,我没有使用 ResourceManager cmdlet。我在我的 ResourceGroup 外部创建了 AzureStorageAccount。此时,尚不支持将存储帐户添加到 ResourceGroups。若要在存储中创建表,我需要获取上下文。我通过传入 storageAccountKey 获取上下文。用户无需详细了解 StorageAccountKey 是如何从一个 cmdlet 传递到另一个 cmdlet 的:

$myStorage = New-AzureStorageAccount -StorageAccountName "MyStorageAccount"
  -Location "West US"
$storageAccountKey = Get-AzureStorageKey -StorageAccountName "MyStorageAccount"
$context = New-AzureStorageContext -StorageAccountName "MyStorageAccount"
  -StorageAccountKey $storageAccountKey.Primary
$logTable = New-AzureStorageTable -Name $MyStorageTableName -Context $context

Enable-AzureWebsiteApplicationDiagnostic cmdlet 将使用我提供的存储帐户启用诊断:

Enable-AzureWebsiteApplicationDiagnostic -Name "MyAzureWebsiteSample"
  -Verbose -LogLevel Information -TableStorage
  -StorageAccountName "MyStorageAccount" –StorageTableName $MyStorageTableName

对于任何网站,在 web.config 的 AppSettings 中都有一些特定于环境的设置。下面的代码段将向您演示如何根据要部署的环境替换 Azure 网站的 Appsettings。这些设置将覆盖网站的 web.config 中存在的值:

$appSettings = @{
  "CurrentEnv" = “Test”;
  "ida:Audience" = “https://[mydomain].onmicrosoft.com/MyAzureWebsiteSample”;
  "ida:ClientId" = "8845acba-0820-4ed5-8926-5652s5353s662";
  "ida:Tenant" = "[mydomain].onmicrosoft.com";
  "any:other" = "some other setting";
} 
Set-AzureWebsite -Name “MyAzureWebsiteSample” -AppSettings $appSettings

通过调用 Set-AzureWebsite 在网站上创建并设置密钥值的集合。这将覆盖 web.config 中的设置。您稍后还可以从门户进行更改。

迄今为止,我设置了我的网站的基础结构。现在,我希望发布我的服务中的应用程序逻辑。我将使用 Publish-­AzureWebsiteProject cmdlet 来执行此作业。我需要提供我的站点名称和作为我的项目生成输出的一部分而生成的包:

Publish-AzureWebsiteProject -Package "<packagepath>" -Name "MyAzureWebsiteSample"

我从我的生成输出获取包路径:

drop\_PublishedWebsites\MyAzureWebsiteSample_Package\MyAzureWebsiteSample.zip

该脚本还会将该证书上载至 AAD。您可以从本文附带的代码下载中下载完整的脚本。您还可以查看 bit.ly/1zTBeQo 以了解 Azure 网站门户提供的丰富功能,在从开发到集成再到生产部署环境这一过程中,您可以使用这些功能管理网站设置和密钥。

启用 Application Insights

当您的网站部署至生产环境后,您可通过遥测了解该站点在缩放和性能需求方面的表现。Application Insights 为 Azure 部署的资源提供遥测解决方案。为了启用 Application Insights,我不得不将其选为站点模板的一部分。这会向项目添加必要的 NuGet 包和 ApplicationInsights.config 文件(其中包含检测密钥)。现在,在发布站点时,ApplicationInsights 资源将创建并与配置文件中的密钥链接。

对于生产环境,在新门户中创建 ApplicationInsights 资源。此时,门户上没有可用于设置 AppInsights 的 Azure PowerShell cmdlet。从属性中,记下检测密钥。您需要将此密钥添加到 ApplicationInsights.config 文件中,然后再发布网站,以便确保其随站点一起部署。

但是,在站点发布期间没有办法更新此文件。您可以通过不依赖于 ApplicationInsights.config 文件中的密钥来绕过这个问题。相反,将该密钥添加到 Appsettings。如此,您可以针对每个环境将其重写。站点如何知道要使用此密钥?对此,我更新了我的网站中的启动代码,以从 web.config 中读取密钥并在 App Insights 配置对象中进行设置:

Microsoft.ApplicationInsights.Extensibility.
  TelemetryConfiguration.Active.InstrumentationKey = "<read key from appsettings>";

我还将此密钥从我的 ApplicationInsights.config 文件删除,因为已不再需要。现在,我将该密钥传递到我的自动化 Azure PowerShell 脚本。这将在站点部署期间更新 appsettings。设置了 Application Insights 后,您可以在门户上或通过安装监视代理查看性能数据。

总结

本文从开发环境一直到生产环境逐步介绍了 Azure 网站的创建以及在 Azure 中设置身份验证和自动部署。在使用 Azure PowerShell 以及增强的新门户 (portal.azure.com) 提供丰富和强大的 API 方面,Azure 取得了长足的进步。

您可以对此设置进行扩展,以添加您自己的资源,如 SQL Azure 或其他存储资源。使用这里提及的技术,您应该能够快速启动新的 Azure 网站、设置身份验证并自动化到任何环境的部署。


Gyan Jadal 是一位效力于 Microsoft 的软件工程师。在为基于 Azure 和企业本地系统的应用程序设计和开发解决方案方面,他有着丰富的经验。可通过电子邮件 gjadal@microsoft.com 与他联系。

衷心感谢以下 Microsoft 技术专家对本文的审阅:Mani Sengodan