Exercício – Provisionar recursos do Azure

Concluído

Neste exercício, você vai configurar um fluxo de trabalho de automação para provisionar seus recursos do Terraform.

Acessar um aplicativo de exemplo

Neste exercício, você criará um repositório GitHub com base em um modelo que contém todo o código necessário para o provisionamento do Terraform.

  1. No GitHub, acesse a página principal do repositório:

    https://github.com/MicrosoftDocs/mslearn-java-petclinic-simplified
    
  2. Acima da lista de arquivos, selecione Usar este modelo e, em seguida, clique em Criar um repositório.

    Captura de tela do botão

  3. Na caixa Nome do repositório, insira um nome exclusivo para o repositório. Lembre-se de seguir a convenção de nomenclatura de repositórios GitHub.

  4. Verifique se a opção Privado está selecionada e escolha Criar repositório.

    Captura de tela do botão

Fluxo de trabalho

No diretório do projeto do repositório criado, você verá um diretório chamado terraform e, dentro dele, um arquivo chamado main.tf.

Vamos examinar algumas seções que você poderá usar para definir a configuração do módulo:

  • Provedor: um arquivo de configuração do Terraform começa com a especificação do provedor. Ao usar o Azure, você especificará o provedor do Azure (azurerm) no bloco do provedor.
  • Terraform: a versão do Terraform com a qual você está trabalhando.
  • Dados: obtém dados de serviços existentes.
  • Locais: gera variáveis usando funções e expressões.
  • Recurso: descreve recursos e dependências.
  • Módulo: capacidade de reutilização e abstração de complexidade.

Para provisionar nosso aplicativo e banco de dados, só precisaremos incluir as seções Provedor e Recursos.

Em seguida, abra o arquivo main.tf e examine a estrutura do código e os comentários:

provider "azurerm" {
  version = "=2.20.0"
  features {}
}

# Creates a resource group
resource "azurerm_resource_group" "main" {
  name     = var.resource_group
  location = var.location

  tags = {
    "Terraform" = "true"
  }
}

resource "random_password" "password" {
  length = 32
  special = true
  override_special = "_%@"
}

# Creates a MySQL server
resource "azurerm_mysql_server" "main" {
  name                              = "${azurerm_resource_group.main.name}-mysql-server"
  location                          = azurerm_resource_group.main.location
  resource_group_name               = azurerm_resource_group.main.name

  administrator_login               = "petclinic"
  administrator_login_password      = random_password.password.result

  sku_name   = "B_Gen5_1"
  storage_mb = 5120
  version    = "5.7"
  auto_grow_enabled                 = true
  backup_retention_days             = 7
  geo_redundant_backup_enabled      = false
  infrastructure_encryption_enabled = false
  public_network_access_enabled     = true
  ssl_enforcement_enabled           = true
  ssl_minimal_tls_version_enforced  = "TLS1_2"
}

# The database that your application will use
resource "azurerm_mysql_database" "main" {
  name                = "${azurerm_resource_group.main.name}_mysql_db"
  resource_group_name = azurerm_resource_group.main.name
  server_name         = azurerm_mysql_server.main.name
  charset             = "utf8"
  collation           = "utf8_unicode_ci"
}

# Enables the 'Allow access to Azure services' check box
resource "azurerm_mysql_firewall_rule" "main" {
  name                = "${azurerm_resource_group.main.name}-mysql-firewall"
  resource_group_name = azurerm_resource_group.main.name
  server_name         = azurerm_mysql_server.main.name
  start_ip_address    = "0.0.0.0"
  end_ip_address      = "0.0.0.0"
}

# Creates the plan that the service uses
resource "azurerm_app_service_plan" "main" {
  name                = "${var.application_name}-plan"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  kind                = "Linux"
  reserved            = true

  sku {
    tier = "PremiumV2"
    size = "P1v2"
  }
}

# Creates the service definition
resource "azurerm_app_service" "main" {
  name                = var.application_name
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  app_service_plan_id = azurerm_app_service_plan.main.id
  https_only          = true

  site_config {
    always_on        = true
    linux_fx_version = "JAVA|8-jre8"
  }

  # Contains application-specific environment variables
  app_settings = {
    "WEBSITES_ENABLE_APP_SERVICE_STORAGE" = "false"

    "SPRING_PROFILES_ACTIVE"     = "mysql"
    "SPRING_DATASOURCE_URL"      = "jdbc:mysql://${azurerm_mysql_server.main.fqdn}:3306/${azurerm_mysql_database.main.name}?useUnicode=true&characterEncoding=utf8&useSSL=true&useLegacyDatetimeCode=false&serverTimezone=UTC"
    "SPRING_DATASOURCE_USERNAME" = "${azurerm_mysql_server.main.administrator_login}@${azurerm_mysql_server.main.name}"
    "SPRING_DATASOURCE_PASSWORD" = azurerm_mysql_server.main.administrator_login_password
  }
}

Configurar o fluxo de trabalho do GitHub Actions com o Terraform

Vamos fornecer acesso ao fluxo de trabalho do GitHub à sua conta do Azure.

Na CLI do Azure, crie uma entidade de serviço executando o seguinte comando:

Importante

Substitua <yourServicePrincipalName> pelo nome da entidade de serviço que você deseja usar.

az ad sp create-for-rbac --name "<yourServicePrincipalName>" --role contributor --scopes /subscriptions/<subscriptionId> --sdk-auth

O comando anterior retorna o JSON a seguir. Copie-o para uso na próxima etapa:

{
  "clientId": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX",
  "clientSecret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "subscriptionId": "XXXXXXXXX-XXXXX-XXXX-XXXX-XXXXXXXXXXXXX",
  "tenantId": "XXXXXXXX-XXXXX-XXXX-XXXX-XXXXXXXXXXX",
  ...
}

Segredos do GitHub

Seu repositório GitHub tem um recurso chamado Segredos, em que você pode armazenar informações confidenciais que são usadas pelo Terraform para se autenticar no Azure.

Depois que você criar as IDs necessárias e o segredo na etapa anterior, a próxima etapa nesta unidade será adicioná-los ao repositório de segredos no projeto do GitHub.

Para este exercício, você precisará armazenar os seguintes segredos:

  • AZURE_CLIENT_ID
  • AZURE_CLIENT_SECRET
  • AZURE_SUBSCRIPTION_ID
  • AZURE_TENANT_ID

Para armazenar os segredos, acesse o repositório do GitHub com fork, selecione Configurações, clique em Segredos e variáveis e selecione Ações no painel esquerdo.

Crie quatro segredos usando os valores retornados da criação da entidade de serviço.

Lembre-se de armazenar os segredos sem as aspas (" "), conforme mostrado na seguinte captura de tela:

Captura de tela que mostra os segredos armazenados no painel Segredos em Configurações do GitHub.

Arquivo de fluxo de trabalho

Dentro do diretório do projeto, há um diretório chamado .github/workflows e, dentro dele, um arquivo chamado main.yml.

O arquivo main.yml é um fluxo de trabalho do GitHub. Ele usa o segredo configurado para implantar o aplicativo na sua assinatura do Azure.

No arquivo de fluxo de trabalho main.yml, você encontrará o seguinte conteúdo:

name: TERRAFORM

on:
  push:
    branches: [ main ]
    paths:
    - 'terraform/**'
  pull_request:
    branches: [ main ]
    paths:
    - 'terraform/**'

  workflow_dispatch:
jobs:
  terraform:
    runs-on: ubuntu-latest

    env:
      ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
      ARM_CLIENT_SECRET: ${{secrets.AZURE_CLIENT_SECRET}}
      ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}

    defaults:
      run:
        working-directory: ./terraform
    steps:
      - uses: actions/checkout@v2

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v1

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan

      - name: Terraform Apply
        run: terraform apply -auto-approve

Esse fluxo de trabalho executará as seguintes ações:

  • Verifica se a configuração está formatada corretamente.
  • Gera um plano para cada solicitação de pull.
  • Dispara a configuração quando os arquivos do diretório terraform são atualizados.

Observação

Dispare também o fluxo de trabalho do GitHub Actions acessando a opção Ações, selecionando o fluxo de trabalho do Terraform e escolhendo Executar Trabalhos existentes novamente.

Disparar um fluxo de trabalho

Em seguida, no repositório, dispare a ação do GitHub desta forma:

  1. No editor de texto interno do GitHub ou em um editor de sua escolha, edite terraform/variables.tf da seguinte maneira:

    a. Altere "CHANGE_ME_RESOURCE_GROUP" para o nome de grupo de recursos desejado.
    b. Altere "CHANGE_ME_APP_NAME" para o nome de aplicativo desejado. Verifique se o nome do aplicativo é exclusivo.

    variable "resource_group" {
      description = "The resource group"
      default = "CHANGE_ME_RESOURCE_GROUP"
    }
    
    variable "application_name" {
      description = "The Spring Boot application name"
      default     = "CHANGE_ME_APP_NAME"
    }
    
    variable "location" {
      description = "The Azure location where all resources in this example should be created"
      default     = "westeurope"
    }
    
  2. Fazer commit de suas alterações.

Verificar o build do GitHub Actions

  1. No repositório, selecione Ações e o fluxo de trabalho TERRAFORM no painel esquerdo.

  2. Na lista de etapas, verifique se os comandos Terraform Init, Terraform Plan e Terraform Validate foram disparados.

    Captura de tela que exibe os resultados da execução do fluxo de trabalho do Terraform.

  3. Na lista de etapas, expanda Terraform Apply e verifique se:

  • O Terraform criou os recursos e exibe a URL da instância do Azure.

  • A instância de aplicativo do Azure está publicamente disponível.

    Captura de tela que mostra que a instância de aplicativo do Azure está disponível publicamente.

Próximas etapas

No próximo exercício, você usará o GitHub Actions para implantar um aplicativo de exemplo do Spring Boot.

Configurar o nome do aplicativo e o grupo de recursos do Azure

No repositório GitHub, edite os nomes de recursos do Azure executando a seguinte ação:

  1. No editor de texto interno do GitHub ou em um editor de sua escolha, edite terraform/variables.tf da seguinte maneira:

    a. Altere "<CHANGE_ME_RESOURCE_GROUP>" para o nome de grupo de recursos desejado.
    b. Altere "<CHANGE_ME_APP_NAME>" para o nome de aplicativo desejado. Verifique se o nome do aplicativo é exclusivo.

    variable "resource_group" {
      description = "The resource group"
      default = "<CHANGE_ME_RESOURCE_GROUP>"
    }
    
    variable "application_name" {
      description = "The Spring Boot application name"
      default     = "CHANGE_ME_APP_NAME"
    }
    
    variable "location" {
      description = "The Azure location where all resources in this example should be created"
      default     = "westeurope"
    }
    
  2. Confirmar as alterações

Criar um pipeline do Azure para provisionar seus recursos do Terraform

Em nosso projeto do Azure DevOps, criaremos dois pipelines separados para provisionamento e build/implantação. O pipeline de provisionamento cria os recursos do Azure que serão liberados por meio do pipeline de build/implantação mais tarde.

Vamos criar o primeiro pipeline de provisionamento:

  1. Escolha sua organização e selecione Novo projeto.

  2. Especifique os parâmetros a seguir.

    Parâmetro Descrição
    Nome do projeto Obrigatório
    Descrição Opcional
    Visibilidade Escolha Privado
    Avançado
    Controle de versão Escolha GIT
    Processo do item de trabalho Escolha Básico
  3. Selecione Criar projeto para criar o projeto e abrir uma página de boas-vindas.

Captura de tela que mostra o novo formulário do projeto do Azure.

Configurar a conexão de serviço do pipeline do Azure

Vamos dar ao pipeline do Azure acesso à sua conta do Azure.

  1. No Azure DevOps, abra a página Conexões de serviço na página de configurações do projeto

  2. Escolha Criar conexão de serviço, selecione Azure Resource Manager e clique em Avançar.

  3. Selecione Entidade de serviço (automático) e clique em Avançar.

  4. Especifique os parâmetros a seguir.

    Parâmetro Descrição
    Scope level Selecione Assinatura do Azure
    Subscription Selecione sua assinatura do Azure existente
    Grupo de recursos Deixe esse campo em branco para permitir que os usuários acessem todos os recursos definidos na assinatura
    Nome da Conexão Obrigatórios. O nome que você usará para se referir a essa conexão de serviço nas propriedades da tarefa. Esse nome não é o nome da sua assinatura do Azure.
  5. Selecione Salvar para criar a conexão.

Criar o pipeline de provisionamento

Importante

Os pré-requisitos deste módulo exigiam que você instalasse a extensão Terraform Azure Pipelines. Se você ainda não o instalou, o pipeline não será executado.

Depois de configurar seu projeto e a conexão com o Azure, você precisará criar um pipeline do Azure para provisionar seus recursos do Terraform.

No Azure DevOps, acesse o projeto, selecione Pipelines no menu à esquerda e, em seguida, selecione Criar Pipeline.

  1. Na guia "Conectar", selecione "GitHub" (arquivo YAML).
  2. Se precisar autorizar o acesso ao GitHub, insira suas credenciais do GitHub e aprove o acesso para o Azure Pipelines com os privilégios solicitados.
  3. Na guia "Selecionar", escolha o repositório do GitHub que contém o modelo.
  4. Selecione Configurar pipeline na guia Inventário.
  5. Na guia "Configurar", escolha o uso de um "Arquivo YAML existente do Azure Pipelines".
  6. No caminho, selecione "/azuredevops/provision.yml"
  7. Selecione Continuar para acessar a guia Examinar e examine o pipeline.

Captura de tela que mostra o formato do novo pipeline do Azure.

Na tela "Examinar o YAML do pipeline", vamos inspecionar o arquivo YAML que usaremos para criar o pipeline.

name: Provision Resources

trigger: none

pool:
  vmImage: 'ubuntu-latest'

steps:

# Initialize the Terraform environment and bind to your Service Connection
- task: TerraformTaskV1@0
  inputs:
    provider: 'azurerm'
    command: 'init'
    workingDirectory: $(Build.Repository.LocalPath)/terraform
    backendServiceArm: $(serviceConnection)
    backendAzureRmResourceGroupName: $(serviceConnection)
    backendAzureRmStorageAccountName: $(serviceConnection)
    backendAzureRmContainerName: 'tfstate'
    backendAzureRmKey: 'tf/terraform.tfstate'

# Apply the Terraform config and deploy to Azure
- task: TerraformTaskV1@0
  inputs:
    provider: 'azurerm'
    command: 'apply'
    workingDirectory: $(Build.Repository.LocalPath)/terraform
    backendAzureRmContainerName: 'tfstate'
    backendAzureRmKey: 'tf/terraform.tfstate'
    environmentServiceNameAzureRM: $(serviceConnection)

Vamos examinar alguns dos campos usados na configuração:

  • serviceConnection: a conexão de serviço do Azure Pipeline configurada anteriormente
  • command: o comando de fluxo de trabalho do Terraform: init ou apply
  • backendAzure: campos obrigatórios que são necessários em um ambiente de equipe para armazenar o estado compartilhado.\

Antes de você salvar e executar o pipeline, precisamos adicionar a variável que será associada à conexão de serviço:

  1. Selecione Variáveis (canto superior direito) e adicione uma variável chamada "serviceConnection" usando como valor o nome da conexão de serviço.
  2. Escolha OK (canto inferior direito) para salvar a variável.

Captura de tela que mostra a nova variável da entidade de serviço.

Por fim, selecione "Executar" (canto superior direito) para salvar e executar o pipeline

Inspecionar a execução de pipeline

Em Trabalhos, rastreie o processo de build em cada uma das etapas.

À medida que o pipeline é executado, observe a primeira fase init e a segunda fase apply do Terraform passarem da cor azul (Em execução) para verde (Concluído). Selecione as fases para observar o pipeline em ação.

Captura de tela que mostra a execução do novo pipeline do Azure.

Dica

Verifique seu email. Você já pode ter recebido uma notificação de build com os resultados da execução. Use essas notificações para saber se cada build é aprovado ou falha.

Próximas etapas

No próximo exercício, você usará o Azure Pipelines para compilar e implantar seu aplicativo Spring Boot de exemplo.