匯出 (0) 列印
全部展開

針對 Windows Azure 中的 VM 角色開發配接器

更新日期: 2011年3月

[Windows Azure 的 VM 角色功能即將在 2013 年 5 月 15 日淘汰。在淘汰日期過後,VM 角色部署將遭到刪除。 若要繼續推展您現有的應用程式,請使用 Windows Azure 虛擬機器。 如需將虛擬機器用於應用程式的詳細資訊,請參閱 Moving from VM Role to Windows Azure Virtual Machines (從 VM 角色移到 Windows Azure 虛擬機器)

您可以將配接器撰寫成 Windows 服務,以在作業系統啟動時自動啟動,以及使用 Microsoft.WindowsAzure.ServiceRuntime API 來使用 Windows Azure 的執行階段資訊。如果您需要目前 VM 角色執行個體或服務中執行之其他角色執行個體的網路位址資訊、如果您需要寫入本機儲存體資源,或者如果您需要在執行階段讀取服務組態設定或是在其變更時回應,就需要撰寫 Windows 服務。

本節說明如何建立配接器,以示範支援 VM 角色的服務。本節中使用的範例會在作業系統啟動時裝載 Windows Azure 磁碟機,然後設定 Internet Information Services (IIS),以將 HTTP 記錄檔寫入該磁碟機。

若要建立配接器,您必須完成下列工作:

  1. 建立儲存體容器

  2. 建立配接器專案

  3. 加入追蹤角色執行個體組態變更的功能

  4. 定義配接器啟動時發生的事情

  5. 定義配接器停止時發生的事情

  6. 建立配接器的安裝程式

  7. 建立配接器的安裝專案

  8. 加入建置後事件以更正組件不一致的情形

  9. 將組態設定加入雲端服務模型

  10. 安裝配接器

配接器會使用 Blob 儲存體,以協助將記錄資料儲存在 Windows Azure 磁碟機中。您必須能夠存取 Windows Azure 中的儲存體帳戶,而且必須建立讓配接器使用的容器。您可以使用偏好的工具,以您選擇的任何名稱,在 Windows Azure 儲存體中建立容器。當您設定雲端服務模型時,將會使用該容器的名稱。

Visual Studio 2010 提供可建立 Windows 服務的範本。您可以使用此範本建立 VM 角色執行個體的配接器。

  1. 開啟 Visual Studio 2010,依序按一下 [檔案][新增][專案]

  2. [Visual C#] 底下的 [已安裝的範本] 窗格中,按一下 [Windows],然後在中心窗格中,按一下 [Windows 服務]

  3. 輸入方案和配接器專案的名稱,然後按一下 [確定]

  4. 在 [方案總管] 中,以滑鼠右鍵按一下方案,按一下 [組態管理員],確定已為專案選取 [任何 CPU],然後按一下 [關閉]

  5. 在 [方案總管] 中,以您為配接器使用的名稱將 Service1.cs 檔案重新命名。本節中的範例會使用 AdapterName 預留位置,代表您選擇的名稱。

  6. 以滑鼠右鍵按一下專案,按一下 [屬性],在 [應用程式] 頁面上,確定已為 [目標 Framework] 選取 [.NET Framework 3.5]

  7. 在專案屬性的 [發行] 頁面上,按一下 [必要條件],然後確定未選取 [.NET Framework 4 (Client Profile)]

  8. 在 [方案總管] 中,加入下列組件的參考:

    • Microsoft.WindowsAzure.ServiceRuntime.dll

      note附註
      您必須確定這個組件的 [複製到本機] 屬性設為 False

    • Microsoft.WindowsAzure.CloudDrive.dll

    • Microsoft.WindowsAzure.StorageClient.dll

    • Microsoft.Web.Administration.dll

  9. 在 [方案總管] 中,以滑鼠右鍵按一下 AdapterName.cs,然後按一下 [檢視程式碼]

  10. 使用陳述式加入下列程式碼:

    
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;
    using Microsoft.WindowsAzure;
    using Microsoft.Web.Administration;
    using System.IO;
    using System.Threading;
    
  11. 在 [方案總管] 中,以滑鼠右鍵按一下 AdapterName.cs,然後按一下 [檢視設計工具]

  12. [屬性] 窗格中,設定下列屬性:

    • ServiceName - 您可以指定系統識別配接器所用的名稱。

    • (Name) - 您可以指定在程式碼中用來代表配接器物件的名稱。

    • CanShutdown – 您必須將這個屬性值指定為 True,當系統關閉時,配接器才會接到通知。

Program.cs 檔案包含下列程式碼:


static void Main()
{
   ServiceBase[] ServicesToRun;
   ServicesToRun = new ServiceBase[] 
   { 
      new ServiceName() 
   };  
   ServiceBase.Run(ServicesToRun);
}

當角色執行個體的組態變更時,您可以定義執行的作業。例如,您可以變更角色執行個體的組態,以變更用來儲存記錄資料的磁碟機位置。若要執行此作業,您可以使用 RoleEnvironment 事件。

  1. 在 [方案總管] 中,以滑鼠右鍵按一下 AdapterName.cs,然後按一下 [檢視程式碼]

  2. 編輯建構函式來定義組態變更事件。下列程式碼範例示範加入至建構函式的事件定義:

    
    public AdapterName()
    {
       InitializeComponent();
       RoleEnvironment.Changed += RoleEnvironmentChanged;
       RoleEnvironment.StatusCheck += RoleEnvironmentStatusCheck;
    }
    
  3. 加入當「已變更」事件發生時,所要呼叫的 RoleEnvironmentChanged 方法。下列程式碼範例示範 RoleEnvironmentChanged 方法,它會裝載新的 Windows Azure 磁碟機,並設定 IIS 將記錄檔寫入新磁碟機:

    
    private CloudDrive currentDrive;
     
    private void RoleEnvironmentChanged(object sender, RoleEnvironmentChangedEventArgs e)
    {
       if(!e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(
          c => c.ConfigurationSettingName == "AdapterName.BlobPath"))
          return;
    
       try
       {
          // perform a rolling drive change
          var oldDrive = this.currentDrive;
          var newDrive = MountDrive();
          try
          {
             ConfigureWebServer(newDrive.LocalPath);
          }
          catch (Exception)
          {
             UnmountDrive(newDrive);
             throw;
          }
          this.currentDrive = newDrive;
          UnmountDrive(oldDrive);
       }
       catch (Exception ex)
       {
          this.EventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
          throw;
       }
    }
    

    其中,AdapterName 是您為配接器專案提供的名稱。

  4. 加入裝載及卸載 Windows Azure 磁碟機的方法,並加入為 IIS 設定記錄檔位置的方法。下列程式碼範例示範 MountDrive 方法:

    
    private CloudDrive MountDrive()
    {
       // create or mount an instance-specific drive
       var credentials = GetStorageCredentials();
       var driveUri = GetDriveUri();
       var drive = new CloudDrive(driveUri, credentials);
    
       try
       {
          drive.Create(1024);
       }
       catch (Exception ex)
       {
          if (ex.Message != "ERROR_BLOB_ALREADY_EXISTS") throw;
       }
    
       // mount the drive
       string mountPoint = drive.Mount(1024, 
          DriveMountOptions.FixFileSystemErrors | DriveMountOptions.Force);
       this.EventLog.WriteEntry(string.Format("{0} mounted at {1}", drive.Uri, mountPoint));
       return drive;
    }
    
    private Uri GetDriveUri()
    {
       return new Uri(string.Format(
       RoleEnvironment.GetConfigurationSettingValue("AdapterName.BlobPath"),
          RoleEnvironment.CurrentRoleInstance.Id));
    }
    
    private StorageCredentials GetStorageCredentials()
    {
       return new StorageCredentialsAccountAndKey(
       RoleEnvironment.GetConfigurationSettingValue("AdapterName.AccountName"),
       RoleEnvironment.GetConfigurationSettingValue("AdapterName.AccountKey"));
    }
    

    如需使用 CloudDrive API 的詳細資訊,請參閱 CloudDriveAdapterName.BlobPath、AdapterName.AccountName 和 AdapterName.AccountKey 等設定在雲端服務定義檔中定義,並設定在服務組態檔中。如需定義這些設定的詳細資訊,請參閱<將組態設定加入雲端服務模型>。

    下列程式碼範例示範 UnmountDrive 方法:

    
    private void UnmountDrive(CloudDrive drive)
    {
       drive.Unmount();
       this.EventLog.WriteEntry(string.Format("{0} unmounted", drive.Uri));
    }
    
    

    下列程式碼範例示範 ConfigureWebServer 方法:

    
    private void ConfigureWebServer(string drivePath)
    {
       using (var config = new ServerManager())
       {
          var logdir = Path.Combine(drivePath, @"inetpub\logs\LogFiles");
          config.SiteDefaults.LogFile.Directory = logdir;
    
          config.CommitChanges();
    
          this.EventLog.WriteEntry(string.Format("IIS log location set to '{0}'", logdir));
       }
    }
    
    
  5. 加入用來判斷角色執行個體狀態的 RoleEnvironmentStatusCheck 方法。statusCheckWaitHandle 物件是做為訊號之用,可將角色執行個體的忙碌或備妥狀態通知負載平衡器。呼叫物件的 Set 方法是組態變更完成的訊號。下列程式碼範例示範 RoleEnvironmentStatusCheck 方法:

    
    private readonly EventWaitHandle statusCheckWaitHandle = new ManualResetEvent(false);
    private volatile bool busy = true;
    
    private void RoleEnvironmentStatusCheck(object sender, RoleInstanceStatusCheckEventArgs e)
    {
       if (this.busy)
       {
          e.SetBusy();
       }
       statusCheckWaitHandle.Set();
    }
    
    

在此範例中,配接器啟動時會執行下列作業:

  • 初始化磁碟快取

  • 裝載磁碟機

  • 設定 IIS 以使用裝載的磁碟機

  1. 在 [方案總管] 中,以滑鼠右鍵按一下 AdapterName.cs,然後按一下 [檢視程式碼]。尋找當您建立專案時被自動覆寫的 OnStart 方法,並加入程式碼,該程式碼會檢查角色執行個體以確定其執行狀態、在另一個執行緒上執行配接器的作業,然後使用 statusCheckWaitHandle 物件來表示作業已完成。

    
    protected override void OnStart(string[] args)
    {
       /// Windows Azure waits for auto-start services to be fully started 
       /// before sending any traffic.  Service Control Manager (SCM) does
       /// not impose a time limit on startup; the service need only 
       /// request additional time.
    
       if (!RoleEnvironment.IsAvailable) return;
          
       var startThread = new Thread(OnStartInternal);
       startThread.Start();
    
       // wait until a status check has occurred, so that Windows Azure 
       // knows we are working on something.
       WaitForHandle(statusCheckWaitHandle);
    }
    

    下列程式碼範例示範 OnStartInternal 方法,其中會裝載 Windows Azure 磁碟機,並將 IIS 設定變更為使用新磁碟機來寫入記錄資料:

    
    private void OnStartInternal()
    {
       try
       {
          // initialize the drive cache
          string cachePath = RoleEnvironment.GetLocalResource("Data").RootPath;
          CloudDrive.InitializeCache(cachePath, 4096);
          this.EventLog.WriteEntry("initialization succeeded");
    
          // mount the current drive
          this.currentDrive = MountDrive();
    
          // configure IIS
          ConfigureWebServer(this.currentDrive.LocalPath);
    
          this.busy = false;
       }
       catch (Exception ex)
       {
          this.EventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
          throw;
       }
    }
    

    下列程式碼範例示範 WaitForHandle 方法,它會等到狀態檢查進行為止:

    
    private const int ThreadPollTimeInMilliseconds = 1000;
    
    private void WaitForHandle(WaitHandle handle)
    {
       while (!handle.WaitOne(ThreadPollTimeInMilliseconds))
       {
          this.RequestAdditionalTime(ThreadPollTimeInMilliseconds * 2);
       }
    }
    

在此範例中,配接器會重新設定記錄檔位置,並且在磁碟機停止時將其卸載。

  1. 在 [方案總管] 中,以滑鼠右鍵按一下 AdapterName.cs,然後按一下 [檢視程式碼]。尋找當您建立專案時被自動覆寫的 OnStop 方法,並加入程式碼,該程式碼會重新設定記錄檔位置,並卸載磁碟機。

    
    protected override void OnStop()
    {
       OnStopInternal();
    }
    
  2. 下列程式碼範例示範 OnShutdown 方法:

    
    protected override void OnShutdown()
    {
       /// Windows Azure stops sending traffic before shutting down.
       /// Note that some requests may still be executing.
       OnStopInternal();
    }
    
  3. 在執行作業的地方加入 OnStopInternal 方法。

    
    private void OnStopInternal()
    {
       try
       {
          ConfigureWebServer(@"%SystemDrive%");
    
          if (this.currentDrive != null)
          {
             UnmountDrive(this.currentDrive);
             this.currentDrive = null;
          }
       }
       catch (Exception ex)
       {
          this.EventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
          throw;
       }
    }
    
    

在安裝 Windows 服務時,需要執行某些自訂動作,此作業可藉由安裝程式類別來完成。Visual Studio 可以特別為 Windows 服務建立這些安裝程式,並將其加入至您的專案。

  1. 在 [方案總管] 中,以滑鼠右鍵按一下 AdapterName.cs,然後選取 [檢視設計工具]

  2. 按一下設計工具的背景,選取配接器本身,而不是其任何內容。

  3. 以設計工具為焦點,按一下滑鼠右鍵,然後按一下 [加入安裝程式]

    根據預設,會將包含兩個安裝程式的元件類別加入您的專案。該元件名為 ProjectInstaller,而其包含的安裝程式為配接器的安裝程式,以及配接器程序的相關安裝程式。

  4. ProjectInstaller 的 [設計] 檢視中,按一下 [serviceInstaller1]

  5. [屬性] 視窗中,將 ServiceName 屬性設為您的配接器名稱。

  6. StartType 屬性設為 自動

  7. 在設計工具中,按一下 [serviceProcessInstaller1]。將 帳戶 屬性設為 LocalService。這樣會導致配接器在本機服務帳戶上安裝和執行。

  8. 建立專案。

安裝專案會安裝已編譯的專案檔,並執行所需的安裝程式以讓配接器執行。若要建立完整的安裝專案,您必須將專案輸出加入安裝專案,然後加入自訂動作以安裝該程式。

  1. 在 [方案總管] 中,按一下滑鼠右鍵選取您的方案,指向 [加入],然後按一下 [新增專案]

  2. [已安裝的範本] 窗格中,依序展開 [其他專案類型][安裝和部署專案],然後按一下 [Visual Studio 安裝程式]

  3. 在中央窗格中,按一下 [安裝專案]

  4. 輸入安裝專案的名稱,然後按一下 [確定]

  5. 展開 [偵測到的相依性],按兩下 [Microsoft .NET Framework],然後在 [屬性] 窗格中,確定 [版本] 的值為 [.NET Framework 3.5]

  6. 針對下列 [偵測到的相依性] 底下的每一個組件,以滑鼠右鍵按一下組件,然後按一下 [排除]

    • Microsoft.Web.Administration.dll

    • Microsoft.WindowsAzure.ServiceRuntime.dll

    • msshrtmi.dll

    • mswacdmi.dll

現在加入自訂動作,為您的配接器安裝程式檔案。

  1. 在 [方案總管] 中,以滑鼠右鍵按一下安裝專案,指向 [檢視],然後按一下 [自訂動作]

  2. [自訂動作] 編輯器中,以滑鼠右鍵按一下 [自訂動作] 節點,然後選取 [加入自訂動作]

  3. 在清單方塊中按兩下 [應用程式資料夾] 將它開啟,然後選取 [加入輸出]

  4. [加入專案輸出群組] 視窗中,選取 [主要輸出],選取組態的 [(使用中)],然後按一下 [確定]

由於 Visual Studio 會將 32 位元組件插入 .msi 檔案中,但是 Windows Azure 需要 64 位元組件,所以必須執行指令碼來修正不一致的組件。您可以使用 JavaScript 檔案做為建置後事件來更正組件。

  1. 將下列程式碼儲存至安裝專案的根資料夾中,名為 FixMSI.js 的檔案:

    
    // workaround for "BadImageFormatException" issue - see http://msdn.microsoft.com/zh-tw/library/kz0ke5xt.aspx
    
    var msiOpenDatabaseModeTransact = 1;
    var msiViewModifyInsert = 1
    var msiViewModifyUpdate = 2
    var msiViewModifyAssign = 3
    var msiViewModifyReplace = 4
    var msiViewModifyDelete = 6
    
    var filespec = WScript.Arguments(0);
    var frameworkpath = WScript.Arguments(1);
    var installer = WScript.CreateObject("WindowsInstaller.Installer");
    var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
    
    WScript.Echo("Updating file '" + filespec + "' to use a 64-bit custom action...");
    
    Update64Bit();
    
    database.Commit();
    database = null;
    installer = null;
    
    function Update64Bit() {
        var sql;
        var view;
        var record;
        sql = "SELECT * FROM Binary WHERE `Name`='InstallUtil'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        if (record != null) {
            var dataCol = 2;
            record.SetStream(dataCol, frameworkpath + "\\InstallUtilLib.dll");
            view.Modify(msiViewModifyUpdate, record);
        }
        record = null;
        view.close();
        view = null;
    }
    
  2. 在 [方案總管] 中,按一下您先前建立的安裝專案,然後在 [屬性] 窗格中,將下列命令加入 [PostBuildEvent] 屬性:

    
    cd $(ProjectDir) 
    CScript //NoLogo FixMSI.js "$(BuiltOutputPath)" "%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727"
    
  3. 在 [方案總管] 中,以滑鼠右鍵按一下安裝專案,然後按一下 [建立]

為了讓配接器與 Windows Azure 通訊,設定必須定義在雲端服務模型中。

  1. 開啟 VM 角色的 ServiceDefinition.csdef 檔案。

  2. 將下列設定加入 ConfigurationSettings 元素:

    
    <Setting name="AdapterName.BlobPath" />
    <Setting name="AdapterName.AccountName" />
    <Setting name="AdapterName.AccountKey" />
    

    其中 AdapterName 為配接器專案的名稱。

  3. 將下列設定加入 LocalResources 元素:

    
    <LocalStorage name="Data" />
    

    如需可用於服務模型之元素的詳細資訊,請參閱<VirtualMachineRole Schema>。

  4. 儲存檔案。

  1. 開啟 VM 角色的 ServiceConfiguration.cscfg 檔案。

  2. 將下列組態設定加入檔案:

    
    <Setting name="AdapterName.BlobPath" value="http://StorageAccountName.blob.core.windows.net/ContainerName/{0}.vhd" />
    <Setting name="AdapterName.AccountName" value="StorageAccountName" />
    <Setting name="AdapterName.AccountKey" value="StorageAccountKey" />
    

    其中 AdapterName 是您建立的配接器專案名稱。StorageAccountName 是儲存體帳戶的名稱。StorageAccountKey 是儲存體帳戶的主索引鍵。ContainerName 是您先前建立的儲存體容器。如需服務模型組態的詳細資訊,請參閱<Windows Azure Service Configuration Schema>。如需定義和配置設定的詳細資訊,請參閱<建立及部署 VM 角色服務模型>。

  3. 儲存檔案。

您的配接器現在已準備安裝在您上傳至 Windows Azure 的 VHD 上。

在程式碼建立完成,且設定已定義並配置在服務模型之後,您就可以安裝配接器,並部署服務模型封裝。針對 VM 角色,在安裝 Windows Azure 整合元件之後,配接器會安裝在虛擬機器上。

為了讓配接器正確運作,必須啟用數項作業系統功能。在您將上傳至 Windows Azure 的映像中,執行下列命令:

DISM /Online /Enable-Feature /FeatureName:NetFx3 /FeatureName:IIS-WebServerRole /FeatureName:IIS-WebServer /FeatureName:IIS-CommonHttpFeatures /FeatureName:IIS-HttpErrors /FeatureName:IIS-ApplicationDevelopment /FeatureName:IIS-HealthAndDiagnostics /FeatureName:IIS-HttpLogging /FeatureName:IIS-RequestMonitor /FeatureName:IIS-Security /FeatureName:IIS-RequestFiltering /FeatureName:IIS-Performance /FeatureName:IIS-WebServerManagementTools /FeatureName:IIS-StaticContent /FeatureName:IIS-DefaultDocument /FeatureName:IIS-DirectoryBrowsing /FeatureName:IIS-HttpCompressionStatic /FeatureName:IIS-ManagementConsole

若要安裝配接器,請瀏覽至包含 .msi 檔案的資料夾,然後按兩下檔案。此檔案位於您先前建立之安裝專案的 Debug 資料夾中。

另請參閱

社群新增項目

Microsoft 正展開一份線上問卷調查,了解您對於 MSDN 網站的看法。 如果您選擇參加,您離開 MSDN 網站時即會顯示線上問卷調查。

您是否想要參加?
顯示:
© 2014 Microsoft