Práticas recomendadas para modelos do ARM

Veja neste artigo como usar as práticas recomendadas ao criar um modelo do ARM (Azure Resource Manager). Essas recomendações ajudam a evitar problemas comuns durante o uso de um modelo do ARM para implantar uma solução.

Limites de modelo

Limite o tamanho do modelo a 4 MB e cada definição de recurso a 1 MB. Os limites se aplicam ao estado final do modelo depois que ele foi expandido com definições de recursos iterativos e valores para variáveis e parâmetros. O arquivo de parâmetro também é limitado a 4 MB. Você poderá receber um erro com um arquivo de parâmetro ou modelo de menos de 4 MB, se o tamanho total da solicitação for muito grande. Para obter mais informações sobre como simplificar o modelo para evitar uma solicitação grande, confira Resolver erros de tamanho de trabalho excedido.

Você também está limitado a:

  • 256 parâmetros
  • 256 variáveis
  • 800 recursos (incluindo a contagem de cópias)
  • 64 valores de saída
  • Dez locais exclusivos por escopo de assinatura/locatário/grupo de gerenciamento
  • 24.576 caracteres em uma expressão de modelo

Você pode exceder alguns limites de modelo usando um modelo aninhado. Para saber mais, confira Usar modelos vinculados e aninhados ao implantar recursos do Azure. Para reduzir o número de parâmetros, variáveis ou saídas, você pode combinar vários valores em um objeto. Para saber mais, veja Objetos como parâmetros.

Resource group

O grupo de recursos armazena metadados sobre os recursos implantados. Esses metadados são armazenados no local do grupo de recursos.

Se a região do grupo de recursos está temporariamente indisponível, você não pode atualizar os recursos no grupo de recursos porque os metadados não estão disponíveis. Os recursos em outras regiões ainda funcionarão conforme o esperado, mas não será possível atualizá-los. Para minimizar o risco, localize seu grupo de recursos e recursos na mesma região.

Parâmetros

As informações nesta seção podem ser úteis quando você trabalha com parâmetros.

Recomendações gerais para parâmetros

  • Minimize o uso de parâmetros. Em vez disso, use variáveis ou valores literais para propriedades que não precisam ser especificados durante a implantação.

  • Use minúsculas concatenadas para nomes de parâmetro.

  • Use parâmetros para configurações que variam de acordo com o ambiente, como o SKU, o tamanho ou a capacidade.

  • Use parâmetros para nomes de recurso que queira especificar para fácil identificação.

  • Insira uma descrição de cada parâmetro nos metadados.

    "parameters": {
      "storageAccountType": {
        "type": "string",
        "metadata": {
          "description": "The type of the new storage account created to store the VM disks."
        }
      }
    }
    
  • Defina valores padrão para parâmetros que não são confidenciais. Especificando um valor padrão, é mais fácil de implantar o modelo e os usuários do seu modelo veem um exemplo de um valor apropriado. Qualquer valor padrão para um parâmetro deve ser válido para todos os usuários na configuração de implantação padrão.

    "parameters": {
      "storageAccountType": {
        "type": "string",
        "defaultValue": "Standard_GRS",
        "metadata": {
          "description": "The type of the new storage account created to store the VM disks."
        }
      }
    }
    
  • Para especificar um parâmetro opcional, não use uma cadeia de caracteres vazia como um valor padrão. Em vez disso, use um valor literal ou uma expressão de linguagem para construir um valor.

    "storageAccountName": {
       "type": "string",
       "defaultValue": "[concat('storage', uniqueString(resourceGroup().id))]",
       "metadata": {
         "description": "Name of the storage account"
       }
    }
    
  • Use allowedValues com moderação. Usá-lo somente quando você deve verificar se alguns valores não estão incluídos nas opções permitidas. Se você usar allowedValues muito em larga escala, poderá bloquear implantações válidas por não manter sua lista atualizada.

  • Quando um nome de parâmetro em seu modelo corresponde a um parâmetro no comando de implantação do PowerShell, o Resource Manager resolve esse conflito de nomeação adicionando o sufixo FromTemplate para o parâmetro de modelo. Por exemplo, se você incluir um parâmetro nomeado ResourceGroupName no modelo, ele entrará em conflito com o parâmetro ResourceGroupName no cmdlet New-AzResourceGroupDeployment. Durante a implantação, você recebe uma solicitação para fornecer um valor para ResourceGroupNameFromTemplate.

Recomendações de segurança para parâmetros

  • Sempre use parâmetros para nomes de usuário e senhas (ou segredos).

  • Use securestring para todos os segredos e senhas. Se você passar dados confidenciais em um objeto JSON, use o tipo secureObject. Os parâmetros de modelo com os tipos securestring ou secure object não podem ser lidos após a implantação de recursos.

    "parameters": {
      "secretValue": {
        "type": "securestring",
        "metadata": {
          "description": "The value of the secret to store in the vault."
        }
      }
    }
    
  • Não forneça valores padrão para nomes de usuário, senhas ou qualquer valor que requer um tipo secureString.

  • Não forneça valores padrão para as propriedades que aumentam a área de superfície de ataque do aplicativo.

Recomendações de local para parâmetros

  • Use um parâmetro para especificar o local de recursos e defina o valor padrão para resourceGroup().location. Fornecer um parâmetro de local permite que os usuários do modelo especifiquem um local em que eles tenham permissão para implantar.

    "parameters": {
       "location": {
         "type": "string",
         "defaultValue": "[resourceGroup().location]",
         "metadata": {
           "description": "The location in which the resources should be deployed."
         }
       }
    }
    
  • Não especifique allowedValues para o parâmetro de local. Os locais que você especificar podem não estar disponíveis em todas as nuvens.

  • Use o valor do parâmetro de local para recursos que provavelmente estarão no mesmo local. Essa abordagem minimiza o número de vezes que os usuários são solicitados a fornecer informações de local.

  • Para obter recursos que não estão disponíveis em todos os locais, use um parâmetro separado ou especifique um valor de local literal.

Variáveis

As seguintes informações podem ser úteis quando você trabalha com variáveis:

  • Use minúsculas concatenadas para nomes de variáveis.

  • Use variáveis para valores que você precisa usar mais de uma vez em um modelo. Se um valor for usado apenas uma vez, um valor embutido em código facilita a leitura do modelo.

  • Use variáveis para valores que você construir de um arranjo complexo de funções de modelo. O modelo é mais fácil de ler quando a expressão complexa aparece somente em variáveis.

  • Não é possível usar a função reference na seção variables do modelo. A função reference deriva seu valor do estado de runtime do recurso. No entanto, as variáveis são resolvidas durante a análise inicial do modelo. Crie valores que precisam da função reference diretamente na seção resources ou outputs do modelo.

  • Inclua variáveis em nomes de recurso que devem ser exclusivos.

  • Use uma loop de cópia em variáveis para criar um padrão repetido de objetos JSON.

  • Remover variáveis não utilizadas.

Versão da API

Defina a propriedade apiVersion como uma versão da API embutida em código para o tipo de recurso. Ao criar um modelo, é recomendável usar a versão mais recente da API para o tipo de recurso. Para determinar os valores disponíveis, consulte referência de modelo.

Quando o modelo estiver funcionando conforme o esperado, é recomendável continuar usando a mesma versão da API. Ao usar a mesma versão de API, você não precisa se preocupar com alterações significativas que podem ser introduzidas em versões posteriores.

Não use um parâmetro para a versão da API. Os valores e as propriedades do recurso podem variar de acordo com a versão da API. O IntelliSense em um editor de código não pode determinar o esquema correto quando a versão da API é definida como um parâmetro. Se você passar uma versão de API que não corresponde às propriedades em seu modelo, a implantação falhará.

Não use variáveis para a versão da API.

Dependências de recursos

Ao decidir quais são as dependências a serem definidas, use as seguintes diretrizes:

  • Use a função reference e passe o nome de recurso para definir uma dependência implícita entre os recursos que precisam compartilhar uma propriedade. Não adicione elemento dependsOn explícito quando você já tiver definido uma dependência implícita. Essa abordagem reduz o risco de ter dependências desnecessárias. Para ver um exemplo de como definir uma dependência implícita, confira as funções de referência e lista.

  • Defina um recurso filho como dependente do recurso pai.

  • Recursos com o elemento condition definido como false são removidos automaticamente da ordem de dependência. Defina as dependências como se o recurso estivesse sempre implantado.

  • Coloque as dependências em cascata sem defini-las explicitamente. Por exemplo, sua máquina virtual depende de uma interface de rede virtual e a interface de rede virtual depende de uma rede virtual e de endereços IP públicos. Portanto, a máquina virtual é implantados depois que todos os três recursos, mas não definir explicitamente a máquina virtual como todos os três recursos dependentes. Essa abordagem esclarece a ordem de dependência e facilita a alteração do modelo mais tarde.

  • Se um valor pode ser determinado antes da implantação, tente implantar o recurso sem uma dependência. Por exemplo, se um valor de configuração precisa do nome de outro recurso, talvez não seja necessário uma dependência. Este guia nem sempre funciona porque alguns recursos verificar a existência de outro recurso. Se você receber um erro, adicione uma dependência.

Recursos

As seguintes informações podem ser úteis quando você trabalha com recursos:

  • Para ajudar outros colaboradores a entender a finalidade do recurso, especifique comments para cada recurso no modelo.

    "resources": [
      {
        "name": "[variables('storageAccountName')]",
        "type": "Microsoft.Storage/storageAccounts",
        "apiVersion": "2019-06-01",
        "location": "[resourceGroup().location]",
        "comments": "This storage account is used to store the VM disks.",
          ...
      }
    ]
    

    Se o modelo do ARM estiver armazenado em um arquivo .jsonc, haverá suporte para comentários usando a sintaxe //, conforme mostrado aqui.

    "resources": [
      {
        // This storage account is used to store the VM disks.
        "name": "[variables('storageAccountName')]",
        "type": "Microsoft.Storage/storageAccounts",
        "apiVersion": "2019-06-01",
        "location": "[resourceGroup().location]",
          ...
      }
    ]
    

    Para mais detalhes sobre comentários e metadados, confira Entender a estrutura e a sintaxe de modelos do ARM.

  • Se você usar um ponto de extremidade público em seu modelo (como um ponto de extremidade público de Armazenamento de Blobs do Azure), o namespace não deverá ser embutido em código. Use a função reference para recuperar dinamicamente o namespace. Você pode usar essa abordagem para implantar o modelo em ambientes de namespace públicos diferentes, sem alterar manualmente o ponto de extremidade no modelo. Defina a mesma versão da API que você está usando para a conta de armazenamento no modelo.

    "diagnosticsProfile": {
      "bootDiagnostics": {
        "enabled": "true",
        "storageUri": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').primaryEndpoints.blob]"
      }
    }
    

    Se a conta de armazenamento for implantada no mesmo modelo que você está criando e o nome da conta de armazenamento não for compartilhado com outro recurso no modelo, você não precisará especificar o namespace do provedor ou apiVersion ao referenciar o recurso. O exemplo a seguir mostra a sintaxe simplificada.

    "diagnosticsProfile": {
      "bootDiagnostics": {
        "enabled": "true",
        "storageUri": "[reference(variables('storageAccountName')).primaryEndpoints.blob]"
      }
    }
    

    Também é possível referenciar uma conta de armazenamento existente que esteja em outro grupo de recursos.

    "diagnosticsProfile": {
      "bootDiagnostics": {
        "enabled": "true",
        "storageUri": "[reference(resourceId(parameters('existingResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('existingStorageAccountName')), '2019-06-01').primaryEndpoints.blob]"
      }
    }
    
  • Atribua endereços IP públicos a uma máquina virtual somente quando um aplicativo exigir. Para se conectar a uma máquina virtual para fins administrativos ou de gerenciamento, use regras NAT de entrada, um gateway de rede virtual ou um jumpbox.

    Para saber mais sobre como se conectar às máquinas virtuais, confira:

  • A propriedade domainNameLabel dos endereços IP públicos precisa ser exclusiva. O valor domainNameLabel deve ter entre 3 e 63 caracteres e seguir as regras especificadas por esta expressão regular: ^[a-z][a-z0-9-]{1,61}[a-z0-9]$. Como a função uniqueString gera uma cadeia de caracteres 13 caracteres, o parâmetro dnsPrefixString é limitado a 50 caracteres.

    "parameters": {
      "dnsPrefixString": {
        "type": "string",
        "maxLength": 50,
        "metadata": {
          "description": "The DNS label for the public IP address. It must be lowercase. It should match the following regular expression, or it will raise an error: ^[a-z][a-z0-9-]{1,61}[a-z0-9]$"
        }
      }
    },
    "variables": {
      "dnsPrefix": "[concat(parameters('dnsPrefixString'),uniquestring(resourceGroup().id))]"
    }
    
  • Ao adicionar uma senha a uma extensão de script personalizado, use a propriedade commandToExecute na propriedade protectedSettings.

    "properties": {
      "publisher": "Microsoft.Azure.Extensions",
      "type": "CustomScript",
      "typeHandlerVersion": "2.0",
      "autoUpgradeMinorVersion": true,
      "settings": {
        "fileUris": [
          "[concat(variables('template').assets, '/lamp-app/install_lamp.sh')]"
        ]
      },
      "protectedSettings": {
        "commandToExecute": "[concat('sh install_lamp.sh ', parameters('mySqlPassword'))]"
      }
    }
    

    Observação

    Para garantir que os segredos sejam criptografados quando passados como parâmetros a VMs e extensões, use a propriedade protectedSettings das extensões relevantes.

  • Especifique valores explícitos para propriedades que têm valores padrão que podem mudar ao longo do tempo. Por exemplo, se você estiver implantando um cluster do AKS, poderá especificar ou omitir a propriedade kubernetesVersion. Se você não especificá-la, o cluster será padronizado para a versão secundária N-1 e o patch mais recente. Quando você implanta o cluster usando um modelo do ARM, esse comportamento padrão pode não ser o esperado. Reimplantar o modelo pode fazer com que o cluster seja atualizado para uma nova versão do Kubernetes inesperadamente. Em vez disso, considere a possibilidade de especificar um número de versão explícito e alterá-lo manualmente quando você estiver pronto para atualizar o cluster.

Comentários

Além da propriedade comments, há suporte para comentários usando a sintaxe //. Para mais detalhes sobre comentários e metadados, confira Entender a estrutura e a sintaxe de modelos do ARM. Você pode optar por salvar arquivos JSON que contêm comentários // usando a extensão de arquivo .jsonc para indicar que o arquivo JSON contém comentários. O serviço ARM também aceitará comentários em qualquer arquivo JSON, incluindo arquivos de parâmetros.

Ferramentas do ARM no Visual Studio Code

Trabalhar com modelos do ARM é muito mais fácil com as Ferramentas do ARM (Azure Resource Manager) para Visual Studio Code. Essa extensão dá suporte a idiomas, snippets de recursos e preenchimento automático de recursos para ajudá-lo a criar e validar modelos do Azure Resource Manager. Para saber mais e instalar a extensão, confira Ferramentas do ARM (Azure Resource Manager).

Usar o kit de ferramentas de teste

O kit de ferramentas de teste do modelo do ARM é um script que verifica se o modelo usa práticas recomendadas. Quando o modelo não está em conformidade com as práticas recomendadas, ele retorna uma lista de avisos com as alterações sugeridas. O kit de ferramentas de teste ajuda você a aprender como implementar práticas recomendadas em seu modelo.

Depois de concluir o modelo, execute o kit de ferramentas de teste para ver se há como melhorar a implementação. Para saber mais, confira Usar kit de ferramentas de teste do modelo do ARM.

Próximas etapas