Início rápido: implementar uma máquina virtual do Azure a partir de um modelo com o Azure SDK for Go

Este início rápido mostra-lhe como implementar recursos a partir de um modelo do Azure Resource Manager com o SDK do Azure para Go. Os modelos são instantâneos de todos os recursos contidos num grupo de recursos do Azure. Ao longo do percurso, irá familiarizar-se com a funcionalidade e as convenções do SDK.

No final deste início rápido, tem uma VM em execução na qual inicia a sessão com um nome de utilizador e palavra-passe.

Nota

Para ver a criação de uma VM no Go que não envolva a utilização de um modelo do Resource Manager, existe um exemplo indispensável que demonstra como criar e configurar todos os recursos da VM com o SDK. A utilização de um modelo neste exemplo permite centrar a atenção nas convenções do SDK sem entrar em grandes pormenores sobre a arquitetura do serviço do Azure.

Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar.

Iniciar o Azure Cloud Shell

O Azure Cloud Shell é uma shell interativa executada no Azure. Tem ferramentas comuns pré-instaladas e configuradas para serem utilizadas com a sua conta. Selecione Copiar para copiar o código, cole-o no Cloud Shell e pressione Enter para executá-lo.

Existem algumas formas de iniciar o Cloud Shell:

Selecione Experimentar no canto superior direito de um bloco de código.

Cloud Shell in this article

Abrir o Cloud Shell no seu browser.

https://shell.azure.com/bash

Selecione o botão Cloud Shell no menu no canto superior direito do portal do Azure.

Cloud Shell in the portal

Se utilizar uma instalação local da CLI do Azure, este início rápido necessita da versão 2.0.28 da CLI ou posterior. Execute az --version para certificar-se de que a sua instalação da CLI cumpre este requisito. Se precisar de instalar ou atualizar, veja Instalar a CLI do Azure.

Instale o Azure SDK para Go

O SDK do Azure para Go é compatível com versões 1.8 e superiores do Go. Para ambientes com Perfis do Azure Stack, a versão 1.9 Go é o requisito mínimo. Se precisar de instalar o Go, siga as instruções de instalação do Go.

Pode transferir o SDK do Azure para Go e as respetivas dependências através de go get.

go get -u -d github.com/Azure/azure-sdk-for-go/...

Aviso

Certifique-se de que capitaliza Azure no URL. Caso contrário, pode causar problemas na importação de maiúsculas e minúsculas ao trabalhar com o SDK. Também terá de capitalizar Azure nas suas declarações de importação.

Criar um principal de serviço

Para iniciar sessão com uma aplicação de forma não interativa no Azure, precisa de um principal de serviço. Os principais de serviço fazem parte do controlo de acesso baseado em funções (RBAC) que cria uma identidade de utilizador exclusiva. Para criar um novo principal de serviço com a CLI, execute o seguinte comando:

az ad sp create-for-rbac --role Contributor \
    --scopes /subscriptions/<subscription_id> \
    --sdk-auth > quickstart.auth

Defina a variável de ambiente AZURE_AUTH_LOCATION para ser o caminho completo para este ficheiro. Em seguida, o SDK localiza e lê as credenciais diretamente a partir deste ficheiro, sem que tenha de fazer quaisquer alterações ou registar informações do principal de serviço.

Obter o código

Obter o código de início rápido e todas as dependências com go get.

go get -u -d github.com/Azure-Samples/azure-sdk-for-go-samples/quickstarts/deploy-vm/...

Não precisa de modificar o código de origem se a variável AZURE_AUTH_LOCATION estiver definida corretamente. Quando o programa é executado, carrega todas as informações de autenticação necessárias a partir daí.

Executar o código

Execute o início rápido com o comando go run.

cd $GOPATH/src/github.com/Azure-Samples/azure-sdk-for-go-samples/quickstarts/deploy-vm
go run main.go

Se a implementação for bem sucedida, vai ver uma mensagem com o nome de utilizador, endereço IP e a palavra-passe para registar na máquina virtual recém-criada. Execute o protocolo SSH nesta máquina para verificar se está operacional.

Limpeza

Limpe os recursos criados durante o início rápido ao eliminar o grupo de recursos com a CLI.

az group delete -n GoVMQuickstart

Elimine também o principal de serviço criado. O ficheiro quickstart.auth contém uma chave JSON para clientId. Copie este valor para a variável de ambiente CLIENT_ID_VALUE e execute o seguinte comando da CLI do Azure:

az ad sp delete --id ${CLIENT_ID_VALUE}

Onde tem de fornecer o valor para CLIENT_ID_VALUE a partir de quickstart.auth.

Aviso

A falha ao excluir a entidade de serviço para este aplicativo o deixa ativo em seu locatário do Microsoft Entra. Embora o nome e a senha da entidade de serviço sejam gerados como UUIDs, certifique-se de seguir as boas práticas de segurança, excluindo todas as entidades de serviço não utilizadas e os Aplicativos Microsoft Entra.

Programe em profundidade

O que o código de início rápido faz está num bloco de variáveis e de várias funções pequenas, cada das quais é abordada aqui.

Variáveis, constantes e tipos

Uma vez que o início rápido é autónomo, utiliza constantes e variáveis globais.

const (
    resourceGroupName     = "GoVMQuickstart"
    resourceGroupLocation = "eastus"

    deploymentName = "VMDeployQuickstart"
    templateFile   = "vm-quickstart-template.json"
    parametersFile = "vm-quickstart-params.json"
)

// Information loaded from the authorization file to identify the client
type clientInfo struct {
    SubscriptionID string
    VMPassword     string
}

var (
    ctx        = context.Background()
    clientData clientInfo
    authorizer autorest.Authorizer
)

Os valores são declarados, o que dá os nomes dos recursos criados. A localização também está especificada aqui, que pode alterar para ver como as implementações se comportam noutros datacenters. Nem todos os datacenters têm todos os recursos necessários disponíveis.

O tipo clientInfo contém as informações carregadas a partir do ficheiro de autenticação para configurar os clientes no SDK e definir a palavra-passe da VM.

As constantes templateFile e parametersFile apontam para os ficheiros necessários para a implementação. O valor authorizer será configurado pelo SDK do Go para autenticação e a variável ctx é um Contexto do Go para as operações de rede.

Autenticação e inicialização

A função init configura a autenticação. Dado que a autenticação é uma condição prévia para tudo o que está no início rápido, faz sentido tê-la como parte da inicialização. Também carrega algumas informações necessárias a partir do ficheiro de autenticação para configurar os clientes e a VM.

func init() {
    var err error
    authorizer, err = auth.NewAuthorizerFromFile(azure.PublicCloud.ResourceManagerEndpoint)
    if err != nil {
        log.Fatalf("Failed to get OAuth config: %v", err)
    }

    authInfo, err := readJSON(os.Getenv("AZURE_AUTH_LOCATION"))
    clientData.SubscriptionID = (*authInfo)["subscriptionId"].(string)
    clientData.VMPassword = (*authInfo)["clientSecret"].(string)
}

Primeiro, auth.NewAuthorizerFromFile é chamado para carregar as informações de autenticação a partir do ficheiro que se encontra em AZURE_AUTH_LOCATION. Em seguida, este ficheiro é carregado manualmente pela função readJSON (omitida aqui) para solicitar os dois valores necessários à execução do resto do programa: o ID de subscrição do cliente e o segredo do principal de serviço, que também é utilizado para a palavra-passe da VM.

Aviso

Para manter este início rápido simples, a palavra-passe do principal de serviço é reutilizada. Na produção, certifique-se de que nunca reutiliza uma palavra-passe que dê acesso aos seus recursos do Azure.

Fluxo de operações em main()

A função main é simples, apenas indica o fluxo de operações e realiza uma verificação de erros.

func main() {
    group, err := createGroup()
    if err != nil {
        log.Fatalf("failed to create group: %v", err)
    }
    log.Printf("Created group: %v", *group.Name)

    log.Printf("Starting deployment: %s", deploymentName)
    result, err := createDeployment()
    if err != nil {
        log.Fatalf("Failed to deploy: %v", err)
    }
    if result.Name != nil {
        log.Printf("Completed deployment %v: %v", deploymentName, *result.Properties.ProvisioningState)
    } else {
        log.Printf("Completed deployment %v (no data returned to SDK)", deploymentName)
    }
    getLogin()
}

Os passos que o código executa são, por ordem:

  • Criar o grupo de recursos para o qual implementar (createGroup)
  • Criar a implementação dentro deste grupo (createDeployment)
  • Obter e apresentar informações de início de sessão para a VM implementada (getLogin)

Criar o grupo de recursos

A função createGroup cria o grupo de recursos. Ao olhar para o fluxo e argumentos de chamada demonstra a forma como as interações de serviço estão estruturadas no SDK.

func createGroup() (group resources.Group, err error) {
    groupsClient := resources.NewGroupsClient(clientData.SubscriptionID)
    groupsClient.Authorizer = authorizer

        return groupsClient.CreateOrUpdate(
                ctx,
                resourceGroupName,
                resources.Group{
                        Location: to.StringPtr(resourceGroupLocation)})
}

O fluxo geral de interação com um serviço do Azure é:

  • Criar o cliente com o método service.New*Client(), em que * é o tipo de recursos de service com o qual quer interagir. Esta função recebe sempre um ID de subscrição.
  • Defina o método de autorização para o cliente, permitindo que interaja com a API remota.
  • Faça a chamada de método no cliente correspondente à API remota. Os métodos do cliente do serviço normalmente aceitam o nome do recurso e um objeto de metadados.

A função to.StringPtr é utilizada para realizar uma conversão de tipo aqui. Os parâmetros dos métodos de SDK quase exclusivamente aceitam ponteiros, pelo que são fornecidos métodos de conveniência para facilitar as conversões de tipo. Veja a documentação do módulo autorest/to para obter a lista completa de conversores de conveniência e o respetivo comportamento.

O método groupsClient.CreateOrUpdate devolve um ponteiro para um tipo de dados que representa o grupo de recursos. Um valor de retorno direto deste tipo indica uma operação de curto-prazo que deverá ser síncrona. Na secção seguinte, verá um exemplo de uma operação de longa duração e como interagir com ela.

Executar a implementação

Uma vez criado o grupo de recursos, é o momento de executar a implementação. Este código é dividido em várias secções mais pequenas para dar ênfase a partes diferentes da sua lógica.

func createDeployment() (deployment resources.DeploymentExtended, err error) {
    template, err := readJSON(templateFile)
    if err != nil {
        return
    }
    params, err := readJSON(parametersFile)
    if err != nil {
        return
    }
    (*params)["vm_password"] = map[string]string{
        "value": clientData.VMPassword,
    }
        // ...

Os ficheiros de implementação são carregados por readJSON, cujos detalhes são ignorados aqui. Esta função devolve um *map[string]interface{}, o tipo utilizado para construir os metadados para a chamada de implementação dos recursos. A palavra-passe da VM também é definida manualmente nos parâmetros da implementação.

        // ...

    deploymentsClient := resources.NewDeploymentsClient(clientData.SubscriptionID)
    deploymentsClient.Authorizer = authorizer

    deploymentFuture, err := deploymentsClient.CreateOrUpdate(
        ctx,
        resourceGroupName,
        deploymentName,
        resources.Deployment{
            Properties: &resources.DeploymentProperties{
                Template:   template,
                Parameters: params,
                Mode:       resources.Incremental,
            },
        },
    )
    if err != nil {
        return
    }

Este código segue o mesmo padrão da criação do grupo de recursos. É criado um novo cliente, dada a capacidade de autenticar com o Azure e, em seguida, é chamado um método. O método tem inclusive o mesmo nome (CreateOrUpdate) do método correspondente para os grupos de recursos. Este padrão é utilizado em todo o SDK. Os métodos que realizam trabalho semelhante costumam ter o mesmo nome.

A grande diferença está no valor de retorno do método deploymentsClient.CreateOrUpdate. Este valor é do tipo Futuro, que segue o padrão de design futuro. Os futuros representam uma operação de longa duração no Azure que pode consultar, cancelar ou bloquear após a respetiva conclusão.

        //...
    err = deploymentFuture.Future.WaitForCompletion(ctx, deploymentsClient.BaseClient.Client)
    if err != nil {
        return
    }
    return deploymentFuture.Result(deploymentsClient)
}

Neste exemplo, o melhor a fazer é aguardar que a operação seja concluída. Aguardar por um futuro requer um objeto de contexto e o cliente que criou o Future. Existem duas possíveis origens do erro: um erro causado do lado do cliente ao tentar invocar o método, e uma resposta de erro do servidor. A última opção é devolvida como parte da chamada deploymentFuture.Result.

Obter o endereço IP atribuído

Para fazer alguma coisa com a VM recém-criada, necessita do endereço IP atribuído. Os endereços IP são os seus próprios recursos do Azure, vinculados aos recursos do Controlador de Interface de Rede (NIC).

func getLogin() {
    params, err := readJSON(parametersFile)
    if err != nil {
        log.Fatalf("Unable to read parameters. Get login information with `az network public-ip list -g %s", resourceGroupName)
    }

    addressClient := network.NewPublicIPAddressesClient(clientData.SubscriptionID)
    addressClient.Authorizer = authorizer
    ipName := (*params)["publicIPAddresses_QuickstartVM_ip_name"].(map[string]interface{})
    ipAddress, err := addressClient.Get(ctx, resourceGroupName, ipName["value"].(string), "")
    if err != nil {
        log.Fatalf("Unable to get IP information. Try using `az network public-ip list -g %s", resourceGroupName)
    }

    vmUser := (*params)["vm_user"].(map[string]interface{})

    log.Printf("Log in with ssh: %s@%s, password: %s",
        vmUser["value"].(string),
        *ipAddress.PublicIPAddressPropertiesFormat.IPAddress,
        clientData.VMPassword)
}

Este método depende das informações armazenadas no ficheiro de parâmetros. O código pode consultar diretamente a VM para obter o seu NIC, consultar o NIC para obter o seu recurso de IP e depois consultar o recurso de IP diretamente. Trata-se de uma longa cadeia de dependências e operações a resolver, o que a torna dispendiosa. Dado que a informação de JSON é local, pode ser carregada como alternativa.

O valor para o utilizador da VM também é carregado a partir do JSON. A palavra-passe da VM foi carregada anteriormente a partir do ficheiro de autenticação.

Próximos passos

Neste início rápido, utilizou um modelo existente e implementou-o através do Go. Em seguida, ligou-se à VM recém-criada por SSH.

Para saber mais sobre o trabalho com máquinas virtuais no ambiente do Azure com o Go, veja Exemplos de computação no Azure para o Go ou Exemplos de gestão de recursos do Azure para o Go.

Para saber mais sobre os métodos de autenticação disponíveis no SDK e os tipos de autenticação que suportam, veja Autenticação com o SDK do Azure para Go.