Exportar (0) Imprimir
Expandir Tudo

Desenvolver um adaptador para uma função VM no Windows Azure

Atualizado: março de 2011

[O recurso da função VM do Windows Azure está para ser retirado em 15 de maio de 2013. Depois da data de baixa, implantações da função VM serão excluídas. Para avançar com seus aplicativos existentes, você pode usar as Máquinas Virtuais do Windows Azure. Para obter mais informações sobre como usar Máquinas Virtuais para seu aplicativo, consulte Moving from VM Role to Windows Azure Virtual Machines (Mudando de Função VM para Máquinas Virtuais do Windows Azure).

Você pode escrever um adaptador como um serviço do Windows que seja iniciado automaticamente quando o sistema operacional for iniciado e que use a API Microsoft.WindowsAzure.ServiceRuntime para utilizar informações de tempo de execução do Windows Azure. Talvez seja necessário escrever um serviço do Windows se você precisar de informações de endereço de rede para a instância da função VM atual ou para outras instâncias de função em execução em seu serviço, se você precisar gravar em um recurso de armazenamento local ou se você precisar ler definições de configuração do serviço em tempo de execução ou responder quando elas forem alteradas.

Esta seção mostra como criar um adaptador que demonstra os serviços que oferecem suporte a uma função VM. O exemplo usado nesta seção monta uma unidade do Windows Azure quando o sistema operacional é iniciado e, em seguida, configura o IIS (Internet Information Services - Serviços de Informações da Internet) para gravar arquivos de log HTTP na unidade.

Para criar um adaptador, você deve concluir as seguintes tarefas:

  1. Criar um contêiner de armazenamento

  2. Criar o projeto do adaptador

  3. Adicionar a capacidade de acompanhar as alterações na configuração da instância da função

  4. Definir o que acontece quando o adaptador é iniciado

  5. Definir o que acontece quando o adaptador é parado

  6. Criar os instaladores para o adaptador

  7. Criar um projeto de instalação para o adaptador

  8. Adicionar um evento pós-compilação para corrigir inconsistências de assembly

  9. Adicionar definições de configuração para o modelo de serviço de nuvem

  10. Instalar o adaptador

O adaptador usa o armazenamento de blob para facilitar o armazenamento de dados de log na unidade do Windows Azure. Você deve ter acesso a uma conta de armazenamento no Windows Azure e deve criar um contêiner que será usado pelo adaptador. Você pode usar sua ferramenta preferencial para criar um contêiner no armazenamento do Windows Azure com qualquer nome que desejar. Você usará o nome do contêiner quando configurar o modelo de serviço de nuvem.

O Visual Studio 2010 fornece um modelo para criar um serviço do Windows. Você pode usar esse modelo para criar o adaptador para suas instâncias da função VM.

  1. Abra o Visual Studio 2010, clique em Arquivo, Novo e Projeto.

  2. No painel Modelos Instalados sob Visual C#, clique em Windows e, em seguida, no painel central, clique em Serviço Windows.

  3. Digite um nome para a solução e o projeto do adaptador e clique em OK.

  4. No Gerenciador de Soluções, clique com o botão direito do mouse na solução, clique em Gerenciador de Configurações, verifique se a opção Qualquer CPU está selecionada para o projeto e, em seguida, clique em Fechar.

  5. No Gerenciador de Soluções, renomeie o arquivo Service1.cs com o nome que você está usando para o adaptador. Os exemplos nesta seção usam o espaço reservado AdapterName, que representa o nome escolhido por você.

  6. Clique com o botão direito do mouse no projeto e clique em Propriedades; na página Aplicativo, certifique-se de que .NET Framework 3.5 esteja selecionado para Estrutura de Destino.

  7. Na página Publicar das propriedades do projeto, clique em Pré-requisitos e certifique-se de que .NET Framework 4 (Client Profile) não esteja selecionado.

  8. No Gerenciador de Soluções, adicione referências para os seguintes assemblies:

    • Microsoft.WindowsAzure.ServiceRuntime.dll

      noteObservação
      Você deve assegurar que a propriedade Copy Local desse assembly esteja definida como False.

    • Microsoft.WindowsAzure.CloudDrive.dll

    • Microsoft.WindowsAzure.StorageClient.dll

    • Microsoft.Web.Administration.dll

  9. No Gerenciador de Soluções, clique com o botão direito do mouse em AdapterName.cs e clique em Exibir Código.

  10. Adicione o seguinte usando instruções:

    
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;
    using Microsoft.WindowsAzure;
    using Microsoft.Web.Administration;
    using System.IO;
    using System.Threading;
    
  11. No Gerenciador de Soluções, clique com o botão direito do mouse em AdapterName.cs e clique em Exibir Designer.

  12. No painel Propriedades, defina as seguintes propriedades:

    • ServiceName - Você pode especificar o nome pelo qual o adaptador será identificado no sistema.

    • (Name) - Você pode especificar o nome usado no código para representar o objeto do adaptador.

    • CanShutdown – Você deve especificar o valor dessa propriedade como True para que o adaptador seja notificado quando o sistema estiver desligando.

O arquivo Program.cs contém o código a seguir:


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

Você pode definir as operações que são executadas quando a configuração de uma instância de função é alterada. Por exemplo, você pode alterar o local de uma unidade em que os dados de log estão sendo armazenados mudando a configuração da instância da função. Para fazer isso, você deve usar os eventos de RoleEnvironment.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse em AdapterName.cs e clique em Exibir Código.

  2. Edite o construtor para definir os eventos de alteração de configuração. O exemplo de código a seguir mostra as definições de evento adicionadas ao construtor:

    
    public AdapterName()
    {
       InitializeComponent();
       RoleEnvironment.Changed += RoleEnvironmentChanged;
       RoleEnvironment.StatusCheck += RoleEnvironmentStatusCheck;
    }
    
  3. Adicione o método RoleEnvironmentChanged que é chamado quando ocorre o evento Changed. O exemplo de código a seguir mostra o método RoleEnvironmentChanged, que monta uma nova unidade do Windows Azure e configura o IIS para gravar arquivos de log na nova unidade:

    
    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;
       }
    }
    

    Em que AdapterName é o nome que você forneceu para o projeto do adaptador.

  4. Adicione os métodos que montam e desmontam a unidade do Windows Azure e adicione o método para configurar o local do arquivo de log para o IIS. O exemplo de código a seguir mostra o método 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"));
    }
    

    Para obter mais informações sobre como usar a API CloudDrive, consulte CloudDrive. As configurações AdapterName.BlobPath, AdapterName.AccountName e AdapterName.AccountKey são definidas no arquivo de definição de serviço de nuvem e no arquivo de configuração do serviço. Para obter mais informações sobre como definir essas configurações, consulte Adicionar definições de configuração para o modelo de serviço de nuvem.

    O exemplo de código a seguir mostra o método UnmountDrive:

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

    O exemplo de código a seguir mostra o método 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. Adicione o método RoleEnvironmentStatusCheck que é usado para determinar o estado da instância da função. O objeto statusCheckWaitHandle é usado como um sinal para informar o balanceador de carga que a instância da função está ocupada ou pronta. A chamada do método Set do objeto é o sinal de que a alteração da configuração foi concluída. O exemplo de código a seguir mostra o método 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();
    }
    
    

Neste exemplo, o adaptador executa as seguintes operações quando é iniciado:

  • Inicializar o cache da unidade

  • Montar a unidade

  • Configurar o ISS para usar a unidade montada

  1. No Gerenciador de Soluções, clique com o botão direito do mouse em AdapterName.cs e clique em Exibir Código. Localize o método OnStart que foi automaticamente substituído quando você criou o projeto e adicione o código que verifica a instância da função para garantir que ela esteja em execução, executa as operações do adaptador em um thread separado e, em seguida, sinaliza que as operações foram concluídas usando o objeto 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);
    }
    

    O exemplo de código a seguir mostra o método OnStartInternal, no qual a unidade do Windows Azure é montada e a configuração do IIS é alterada para usar a nova unidade para gravar dados de log:

    
    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;
       }
    }
    

    O exemplo de código a seguir mostra o método WaitForHandle que aguarda até a ocorrência de uma verificação de status:

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

Neste exemplo, o adaptador reconfigura o local do arquivo de log e desmonta a unidade quando ela é parada.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse em AdapterName.cs e clique em Exibir Código. Localize o método OnStop que foi automaticamente substituído quando você criou o projeto e adicione o código que reconfigura o local do arquivo de log e desmonta a unidade.

    
    protected override void OnStop()
    {
       OnStopInternal();
    }
    
  2. O exemplo de código a seguir mostra o método OnShutdown:

    
    protected override void OnShutdown()
    {
       /// Windows Azure stops sending traffic before shutting down.
       /// Note that some requests may still be executing.
       OnStopInternal();
    }
    
  3. Adicione o método OnStopInternal, no qual as operações são executadas.

    
    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;
       }
    }
    
    

Algumas ações personalizadas devem ocorrer durante a instalação de um serviço do Windows, e isso pode ser feito pela classe Installer. O Visual Studio pode criar esses instaladores especificamente para um serviço do Windows e adicioná-los ao seu projeto.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse em AdapterName.cs e selecione Exibir Designer.

  2. Clique no plano de fundo do designer para selecionar o próprio adaptador, em vez de qualquer um de seus conteúdos.

  3. Com o foco no designer, clique com o botão direito do mouse e, em seguida, clique em Adicionar Instalador.

    Por padrão, uma classe de componente que contém dois instaladores é adicionada ao seu projeto. O componente é chamado de ProjectInstaller e os instaladores que ele contém são para o seu adaptador e para o processo associado do adaptador.

  4. No modo Design de ProjectInstaller, clique em serviceInstaller1.

  5. Na janela Propriedades, defina a propriedade ServiceName com o nome de seu adaptador.

  6. Defina a propriedade StartType como Automatic.

  7. No designer, clique em serviceProcessInstaller1. Defina a propriedade Account como LocalService. Isso fará com que o adaptador seja instalado e execute em uma conta de serviço local.

  8. Crie o projeto.

Um projeto de instalação instala os arquivos de projeto compilados e executa os instaladores necessários para executar o adaptador. Para criar um projeto de instalação completo você deve adicionar a saída do projeto ao projeto de instalação e, em seguida, adicionar uma ação personalizada para instalar o programa.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse para selecionar sua solução, aponte para Adicionar e clique em Novo Projeto.

  2. No painel Modelos Instalados, expanda Outros tipos de projetos e Projetos de implantação e instalação e clique em Instalador do Visual Studio.

  3. No painel central, clique em Projeto de Instalação.

  4. Insira um nome para o projeto de instalação e clique em OK.

  5. Expanda Dependências Detectadas, clique duas vezes em Microsoft .NET Framework e, no painel Propriedades, verifique se o valor de Versão é .NET Framework 3.5.

  6. Para cada um dos seguintes assemblies sob Dependências Detectadas, clique com o botão direito do mouse no assembly e clique em Excluir:

    • Microsoft.Web.Administration.dll

    • Microsoft.WindowsAzure.ServiceRuntime.dll

    • msshrtmi.dll

    • mswacdmi.dll

Agora, adicione uma ação personalizada para instalar o arquivo de programa para o seu adaptador.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto de instalação, aponte para Exibir e clique em Ações personalizadas.

  2. No editor Ações personalizadas, clique com o botão direito do mouse no nó Ações personalizadas e selecione Adicionar ação personalizada.

  3. Clique duas vezes em Pasta de Aplicativo na caixa de listagem para abri-la e selecione Adicionar Saída.

  4. Na janela Adicionar Grupo de Saída de Projeto, selecione Saída Primária e (Ativo) para a configuração e, em seguida, clique em OK.

O Visual Studio injeta assemblies de 32 bits no arquivo .msi, mas o Windows Azure exige assemblies de 64 bits e, por isso, um script deve ser executado para corrigir os assemblies inconsistentes. Você pode usar um arquivo JavaScript como um evento pós-compilação para corrigir os assemblies.

  1. Salve o código a seguir em um arquivo chamado FixMSI.js na pasta raiz do projeto de instalação:

    
    // workaround for "BadImageFormatException" issue - see http://msdn.microsoft.com/pt-br/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. No Gerenciador de Soluções, clique no projeto de instalação que você criou anteriormente e, no painel Propriedades, adicione o seguinte comando à propriedade PostBuildEvent:

    
    cd $(ProjectDir) 
    CScript //NoLogo FixMSI.js "$(BuiltOutputPath)" "%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727"
    
  3. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto de instalação e clique em Compilar.

Para que o adaptador se comunique com o Windows Azure, as configurações devem ser definidas no modelo de serviço de nuvem.

  1. Abra o arquivo ServiceDefinition.csdef da função VM.

  2. Adicione as configurações a seguir ao elemento ConfigurationSettings:

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

    Em que AdapterName é o nome do projeto do adaptador.

  3. Adicione a configuração a seguir ao elemento LocalResources:

    
    <LocalStorage name="Data" />
    

    Para obter mais informações sobre os elementos que podem ser usados no modelo de serviço, consulte VirtualMachineRole Schema.

  4. Salve o arquivo.

  1. Abra o arquivo ServiceConfiguration.cscfg da função VM.

  2. Adicione as definições de configuração a seguir ao arquivo:

    
    <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" />
    

    Em que AdapterName é o nome do projeto do adaptador que você criou. StorageAccountName é o nome de sua conta de armazenamento. StorageAccountKey é a chave primária de sua conta de armazenamento. ContainerName é o contêiner de armazenamento que você criou anteriormente. Para obter mais informações sobre a configuração do modelo de serviço, consulte Windows Azure Service Configuration Schema. Para obter mais informações sobre como definir configurações, consulte Criar e implantar o modelo de serviço da função VM.

  3. Salve o arquivo.

Agora, o adaptador está pronto para ser instalado no VHD que você está carregando no Windows Azure.

Depois que o código é criado e as configurações são definidas no modelo de serviço, você pode instalar o adaptador e implantar o pacote de modelo do serviço. Para uma função VM, o adaptador é instalado na máquina virtual depois que os Componentes de Integração do Windows Azure são instalados.

Para que o adaptador funcione corretamente, vários recursos do sistema operacional devem ser habilitados. Na imagem que será carregada no Windows Azure, execute o seguinte comando:

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

Para instalar o adaptador, navegue até a pasta que contém o arquivo .msi e clique duas vezes no arquivo. Esse arquivo está localizado na pasta de depuração do projeto de instalação que você criou anteriormente.

Consulte Também

Contribuições da comunidade

Mostrar:
© 2015 Microsoft