Não faz mais sentido em 2017 configurar um servidor sem algum sistema de orquestração. A própria ideia de configurar um servidor talvez esteja caindo em desuso. Não faz mais sentido se logar em um servidor Linux por SSH e instalar pacotes como se você estivesse na sua máquina de trabalho. Temos ferramentas para versionar, organizar e automatizar cada passo. E a preocupação com a orquestração não é um papel apenas de um DevOPS mas um papel que precisa ser apropriado por qualquer desenvolvedor.

O propósito deste tutorial é o de criar uma VM Azure através de Resource Manager Templates via Chef. Não é necessário nenhum conhecimento prévio de ARM Templates ou de Chef, mas quem conhece um ou outro também pode se beneficiar.

Porque alguém criaria uma VM via Chef, usando um tutorial com uma dezena de passos quando posso criar uma VM pelo portal do Azure ou numa simples linha de comando usando Azure Cli?

E se você precisar criar não uma, mas 5, 10 VMs? E se essas VMs não forem idênticas mas com configurações específicas, como você organiza a configuração de cada VM? Numa planilha? E se você tivesse um repositório onde pudesse replicar toda a sua infra estrutura em poucos minutos? E se você puder manter tudo isso versionado, num Git por exemplo? E mesmo que seja uma única VM, ter as características desta VM salvas num repositório versionado com a possibilidade de o ambiente poder ser recriado a qualquer momento já não é uma vantagem suficiente?

As possibilidades são infinitas. E como os recipes são em Ruby, você tem em mãos todas as possibilidades lógicas que uma linguagem de alto nível oferece.

  • Nossa VM vai ser criada usando Chef em local-mode, ou seja, apenas através de sua máquina de trabalho.
  • Esse tutorial deve funcionar em qualquer Sistema Operacional. Como o Powershell aceita tanto barras simples (/) quanto invertidas (\), nos comandos comuns mantive as barras simples, em nome da simplicidade.
  • Se você usa Bash on Windows ou Cygwin pode acompanhar o tutorial seguindo os passos de UNIX, sem medo.
  • No universo UNIX, chamamos de diretório o que no Windows se chama de pasta. Quando ler diretório, entenda como pasta.

    Para quem curte uma discussão filosófica, o Stack Overflow é sempre um ponto de partida.

  • No Mac, se você não tiver o comando wget pode usar o curl para fazer downloads por linha de comando. A sintaxe é bem simples:
    curl -O [url]

Requisitos:

  1. Instale o ChefDK: https://downloads.chef.io/chefdk
  2. Instale o plugin chef-provisioning-azurerm
    chef gem install chef-provisioning-azurerm
  3. Instale o Python Azure CLI 2.0 ou Powershell Azure SDK para configurar as credenciais para o Chef.
    • Num shell UNIX:

      Você precisa de Python PIP (digite pip, veja se o comando existe). Caso não tenha siga uma destas instruções para alguma distro Linux. Claro que com Bash on Windows você deve seguir as instruções de Ubuntu. Para Mac, um simples sudo easy_install pip pode ser o suficiente. Ou use MacPorts ou Homebrew. No Cygwin você precisa de python-setuptools para então instalar o pip via easy_install pip.

      pip install --user azure-cli

      Acrescente o diretório bin de instalação do python local na variável PATH do usuário.

      echo 'PATH=~/.local/bin:$PATH' >> ~/.bashrc
      source ~/.bashrc
    • No Windows, Azure Powershell.

      Os detalhes podem ser encontrados aqui.

      A instalação do módulo azurerm precisa ser executada com uma instância de Powershell como Administrador. Abra uma nova janela, selecionando através do menu Executar como administrador.

      Install-Module AzureRM

      Se receber o prompt abaixo, digite Y ou A:

      Untrusted repository
      You are installing the modules from an untrusted repository. If you trust this repository, change its
      InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from      'PSGallery'?
      [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): Y

      Altere a política de execução para Bypass

      Set-ExecutionPolicy -ExecutionPolicy Bypass

      Feche essa janela como administrador, retorne à janela comum de Powershell e importe o módulo que acabamos de instalar:

      Import-Module AzureRM

Mãos à obra!

    1. Crie um repositório Chef.

      Eu costumo criar meus ambientes de trabalho em ~/Projects. Mas você pode organizar de outra forma, em outro diretório. O nome do repositório Chef também fica a critério de cada um.

      cd ~/Projects
      chef generate repo chef-repo

      Para facilitar, vamos exportar uma variável temporária para a raiz do repositório.

      • Num shell UNIX:
        export CHEF_REPO=~/Projects/chef-repo
      • No Powershell:
        $CHEF_REPO = "~\Projects\chef-repo"

      No decorrer do tutorial vamos usar a localização de diretórios a partir desta variável, $CHEF_REPO.

    2. Crie um diretório .chef dentro do repositório que acabamos de criar.
      mkdir $CHEF_REPO/.chef
    3. Crie o arquivo knife.rb. Este é um arquivo de configuração básico do nosso ambiente de Chef local. Use o seu editor favorito.
      # $CHEF_REPO/.chef/knife.rb
      log_level                :info
      current_dir = File.dirname(__FILE__)
      node_name                "provisioner"
      client_key               "#{current_dir}/dummy.pem"
      validation_key           "#{current_dir}/dummy.pem"
      validation_client_name   "validator"
      
    4. Vamos criar uma chave SSH. Ela vai ser nossa forma de autenticação para a nova VM.

      É importante que o nome das chaves que você for criar corresponda às variáveis no arquivo $CHEF_REPO/.chef/knife.rb. Vamos referenciar a chave publica por este arquivo logo mais no recipe.

      • Nos UNIX:
        cd $CHEF_REPO/.chef
        ssh-keygen -f dummy.pem
      • No Windows, se você não tiver um OpenSSH ou não quiser instalar um, pode instalar o PuTTY:
        https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html

        Execute PuTTYgen. Clique em generate. Deixe os valores padrão, ou pelo menos adicione uma senha. Clique em Save private key. Escolhe um nome. Aqui estamos usando dummy mas o critério é seu. Navegue até a pasta .chef dentro do nosso repositório chef e salve sua chave privada.

        Clique em Save public key. Por coerência, use o mesmo nome mas acrescente uma extensão, que por convenção estamos chamando de .ppk.pub. No nosso exemplo é dummy.ppk.pub.

        Volte ao Powershell e liste o conteúdo de $CHEF_REPO/.chef. O comando deve te listar três arquivos.

        PS C:\Users\aline\Projects\chef-repo\.chef> dir
        
        
            Directory: C:\Users\aline\Projects\chef-repo\.chef
        
        
        Mode                LastWriteTime         Length Name
        ----                -------------         ------ ----
        -a----       22/06/2017     20:13           1460 dummy.ppk
        -a----       22/06/2017     20:13            477 dummy.ppk.pub
        -a----       22/06/2017     20:13            252 knife.rb
                    
    5. Crie as credenciais de acesso ao Azure pelo Chef.
      • UNIX
        az login

        Siga os passos, se autentique no navegador. Quando terminar execute:

        az account list

        Tenha certeza que a assinatura (subscription) que você vai utilizar esteja com o valor IsDefault para true.

        Substitua a subscription ID do comando anterior com SUA_SUBSCRIPTION_ID no parâmetro scopes a seguir.

        az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/SUA_SUBSCRIPTION_ID"

        Crie o arquivo ~/.azure/credentials neste formato:

        [SUA_SUBSCRIPTION_ID]
        client_id = "48b9bba3-YOUR-GUID-HERE-90f0b68ce8ba"
        client_secret = "your-client-secret-here"
        tenant_id = "9c117323-YOUR-GUID-HERE-9ee430723ba3"

        Sendo:

        SUA_SUBSCRIPTION_ID, a subscription ID utilizada anteriormente.

        client_id, o valor de AppId.

        client_secret, o valor de Password.

        tenant_id, o valor de tenant.

      • Windows Powershell
        Login-AzureRmAccount

        Verifique se a subscription corrente é a subscription que você realmente pretende trabalhar.

        (Get-AzureRmContext).Subscription

        Anote o Name e a Id da sua subscription. A Id vamos usar logo mais no recipe.

        Faça o download do script e execute.

        Invoke-WebRequest -URI https://gist.githubusercontent.com/sjkp/186d36334b27656a05cd/raw/6acba8599e0906e7fc1957195cd5f7204673d952/New-AzureRmServicePrincipal.ps1 -OutFile New-AzureRmServicePrincipal.ps1
        .\New-AzureRmServicePrincipal.ps1

        Ele pede subscriptionName, que mencionei logo acima.

        Observe que é o nome, não a ID. E ele pede uma senha, que vai ser a senha que irá utilizar para seu APP. Gere uma senha ramdomica complexa, já que ela vai ficar salva numa variável de ambiente.

        Pelo Powershell vamos adicionar as seguintes variáveis:

        AZURE_CLIENT_ID com o valor de Service Principal Id.
        AZURE_CLIENT_SECRET com o valor da senha que você criou.
        AZURE_TENANT_ID com o valor de Tenant Id.

        Aqui adicionamos as variáveis no Powershell corrente:

        $Env:AZURE_CLIENT_ID = "48b9bba3-YOUR-GUID-HERE-90f0b68ce8ba"
        $Env:AZURE_CLIENT_SECRET = "your-client-secret-here"
        $Env:AZURE_TENANT_ID = "9c117323-YOUR-GUID-HERE-9ee430723ba3"
                    

        E aqui adicionamos permanentemente nas variáveis de usuário:

        [Environment]::SetEnvironmentVariable("AZURE_CLIENT_ID", $AZURE_CLIENT_ID, "User")
        [Environment]::SetEnvironmentVariable("AZURE_CLIENT_SECRET", $AZURE_CLIENT_SECRET, "User")
        [Environment]::SetEnvironmentVariable("AZURE_TENANT_ID", $AZURE_TENANT_ID, "User")
    6. Crie um cookbook para nosso recipe, ou seja, nossa receita de criação de uma VM Azure.
      cd $CHEF_REPO/cookbooks
      chef generate cookbook chef-azure
    7. Vamos criar o recipe propriamente. Use seu editor favorito e edite o arquivo $CHEF_REPO/cookbooks/chef-azure/recipes/default.rb
      # cookbooks/chef-azure/recipes/default.rb
      #
      # Cookbook:: chef-azure
      # Recipe:: default
      #
      # Copyright:: 2017, Aline Freitas, All Rights Reserved.
      
      require 'chef/provisioning/azurerm'
      with_driver 'AzureRM:SUA_SUBSCRIPTION_ID'
      
      azure_resource_group 'chefrg' do
        location 'East US'
        tags businessUnit: 'DEV'
      end
      
      azure_resource_template 'MyDeployment' do
        resource_group 'chefrg'
        template_source "#{Chef::Config[:cookbook_path]}/#{cookbook_name}/files/azuredeploy.json"
        parameters adminUsername: 'ubuntu',
                   sshKeyData: File::read("#{Chef::Config[:validation_key]}.pub")
      end
      • O campo with_driver 'AzureRM:SUA_SUBSCRIPTION_ID' precisa ser corrigido com a sua SUBSCRIPTION ID que usamos outras vezes.
      • adminUsername pode ser substituído por outro nome de usuário a sua escolha.
      • Como informei antes, sshKeyData lê a chave pela localização da chave privada no arquivo $CHEF_REPO/.chef/knife.rb acrescido da extensão .pub. Adapte ao seu cenário se for necessário.
    8. Precisamos acrescentar o template da nossa VM.

      Aqui vamos utilizar um template bem simples, que cria uma VM Ubuntu usando uma chave SSH como método de autenticação.

      mkdir $CHEF_REPO/cookbooks/chef-azure/files
      cd $CHEF_REPO/cookbooks/chef-azure/files
      • UNIX
        wget https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-sshkey/azuredeploy.json
      • Powershell
        Invoke-WebRequest -URI https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vm-sshkey/azuredeploy.json -OutFile azuredeploy.json
    9. E por fim vamos executar a criação do nosso ambiente.
      cd $CHEF_REPO
      chef-client -o chef-azure -z

      O chef-azure aqui no comando é o nome do nosso cookbook. Lembre-se de substituir se o cookbook for criado com outro nome.

    10. Agora podemos nos logar na nossa nova VM.

      Em um cenário de produção, o nome da VM seria dado como um parâmetro, ou gerado automaticamente através de algum critério do usuário. No caso deste template, como ele é bem simples, apenas para demonstração, o nome da VM é hardcoded: sshvm.

      • UNIX

        Precisamos novamente do azure-cli para obter o IP da nossa VM.

        az vm list-ip-addresses -n sshvm

        O output vai ser algo assim:

        VirtualMachine        PublicIPAddresses    PrivateIPAddresses
        ----------------      -------------------  --------------------
        sshvm                 91.169.135.236       10.0.1.35

         

        Então se logar é bem simples. Lembre-se do nosso recipe, o nome de usuário utilizado foi ubuntu.

        ssh -i $CHEF_REPO/.chef/dummy.pem.pub ubuntu@91.169.135.236
      • Powershell

        Como tivemos que abrir uma nova instância de powershell, talvez você precise se logar novamente.

        Import-Module AzureRM
        Login-AzureRmAccount

        E no snippet abaixo informe o nome do Resource Group utilizado na criação da sua VM. No exemplo nosso foi chefrg.

        Como o template é bem simples, apenas para demonstração, o nome da VM é hardcoded: sshvm.

        $vm = Get-AzureRmVM -Name "sshvm" -ResourceGroupName "chefrg"
        $NIC = Get-AzureRmNetworkInterface  | where { $_.Id -eq $vm.NetworkProfile.NetworkInterfaces[0].Id }
        Get-AzureRmPublicIpAddress | where {$_.Id -eq $NIC.IpConfigurations[0].PublicIpAddress.Id} | Select IpAddress

        O output vai ser algo assim.

        IpAddress
        ---------
        91.169.135.236
      • PuTTY

        Para se logar, abra o PuTTY. Pelo menu Category do lado esquerdo navegue para Connection -> SSH -> Auth.

        Em Private key for authentication navegue até a nossa chave, que chamamos de dummy.

        No mesmo menu Category, clique no primeiro item, Session.

        Em Host Name (or IP Address) insira no formato usuário@IP.

        No nosso exemplo fica: ubuntu@91.169.135.236.

      Se você conseguiu se logar e receber um shell prompt, parabéns!