Modularizar modelos

Concluído

A modularização de modelos é uma prática recomendada que divide modelos grandes e complexos em componentes menores e reutilizáveis. Essa abordagem melhora a capacidade de manutenção, promove a reutilização e torna os modelos mais fáceis de testar e entender.

Porquê modularizar modelos?

Benefícios da modularização:

  • Reutilização: Crie um modelo de rede uma vez e use-o em vários projetos.
  • Manutenabilidade: Atualize um módulo em vez de modificar vários modelos grandes.
  • Colaboração em equipa: Diferentes equipes podem possuir diferentes módulos (rede, segurança, computação).
  • Testes: Teste módulos individuais isoladamente antes de compô-los.
  • Separação de preocupações: Cada modelo se concentra em um domínio de infraestrutura específico.
  • Controle de versão: Rastreie alterações em componentes individuais de forma independente.

Exemplo do mundo real: Crie modelos separados para:

  • Módulo de rede: Redes virtuais, sub-redes, NSGs, tabelas de rotas.
  • Módulo de armazenamento: Contas de armazenamento, contêineres de blob, compartilhamentos de arquivos.
  • Módulo de computação: Máquinas virtuais, conjuntos de disponibilidade, balanceadores de carga.
  • Módulo de segurança: Cofre de chaves, identidades gerenciadas, atribuições RBAC.

Modelos ligados

Os modelos vinculados permitem que você faça referência a arquivos de modelo externos a partir de um modelo principal. Esta é a principal metodologia para criar arquiteturas modulares de modelo ARM.

Como funciona:

  1. Armazene modelos secundários em locais acessíveis (Armazenamento do Azure, GitHub, etc.).
  2. O modelo principal faz referência a modelos externos via URI.
  3. O Resource Manager baixa e executa modelos vinculados durante a implantação.

Sintaxe: Adicione um recurso de implantação ao seu modelo principal:

"resources": [
  {
    "apiVersion": "2022-09-01",
    "name": "linkedTemplate",
    "type": "Microsoft.Resources/deployments",
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/templates/networking.json",
        "contentVersion": "1.0.0.0"
      },
      "parameters": {
        "vnetName": {
          "value": "[parameters('virtualNetworkName')]"
        },
        "location": {
          "value": "[parameters('location')]"
        }
      }
    }
  }
]

Principais propriedades:

  • tipo:Microsoft.Resources/deployments Indica uma implantação aninhada ou vinculada.
  • Modalidade: Modo de implantação (Incremental ou Concluído).
  • templateLink: Aponta para o URI do modelo externo.
  • Parâmetros: Valores passados para o modelo vinculado.

Exemplo completo com vários modelos vinculados:

"resources": [
  {
    "name": "networkingDeployment",
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2022-09-01",
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "[concat(parameters('templateBaseUrl'), '/networking.json')]"
      },
      "parameters": {
        "vnetName": { "value": "[parameters('vnetName')]" }
      }
    }
  },
  {
    "name": "storageDeployment",
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2022-09-01",
    "dependsOn": [
      "[resourceId('Microsoft.Resources/deployments', 'networkingDeployment')]"
    ],
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "[concat(parameters('templateBaseUrl'), '/storage.json')]"
      }
    }
  }
]

Modelos aninhados

Os modelos aninhados permitem incorporar um modelo completo diretamente dentro do modelo principal utilizando a propriedade template em vez de templateLink.

Quando usar modelos aninhados:

  • Cenários simples: Componentes pequenos e independentes que não precisam de arquivos externos.
  • Lógica privada: Lógica de modelo que você não deseja expor externamente.
  • Geração dinâmica: Crie conteúdo de modelo programaticamente durante a implantação.

Desvantagem: Aninhar componentes grandes resulta num ficheiro principal de tamanho considerável, o que dificulta a sua manutenção e leitura.

"resources": [
  {
    "apiVersion": "2022-09-01",
    "name": "nestedStorageTemplate",
    "type": "Microsoft.Resources/deployments",
    "properties": {
      "mode": "Incremental",
      "template": {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "resources": [
          {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2023-01-01",
            "name": "[variables('storageName')]",
            "location": "[parameters('location')]",
            "sku": {
              "name": "Standard_LRS"
            },
            "kind": "StorageV2",
            "properties": {
              "supportsHttpsTrafficOnly": true
            }
          }
        ]
      }
    }
  }
]

Limitações importantes:

Observação

Escopo do modelo aninhado: Os modelos aninhados só podem usar parâmetros e variáveis do modelo principal. Não é possível definir novos parâmetros ou variáveis dentro do próprio modelo aninhado.

Modelos vinculados vs. aninhados:

Característica Modelos vinculados Modelos aninhados
Localização Arquivo externo (URI) Inserido dentro do modelo principal
Reutilização Alto - uso em todos os projetos Baixo - vinculado ao modelo principal
Manutenibilidade Fácil - arquivos separados Mais difícil - incorporado no arquivo principal
Parâmetros Pode definir parâmetros próprios Usa apenas parâmetros de modelo principais
Variáveis Pode definir variáveis próprias Usa apenas variáveis de modelo principais
Tamanho Sem impacto no modelo principal Aumenta o tamanho do modelo principal
Melhor para Arquiteturas modulares de produção Componentes simples e únicos

Recomendação: Use modelos vinculados para cenários de produção e modelos aninhados apenas para componentes simples e não reutilizáveis.

Modos de implementação

Ao implantar modelos, você deve escolher um modo de implantação que determine como o Gerenciador de Recursos lida com os recursos existentes no grupo de recursos de destino.

Três opções de implantação

Modo de validação

Finalidade: Modelo de teste sem fazer alterações.

O que faz:

  • Compila o modelo e verifica a sintaxe JSON.
  • Valida a lógica de implantação (sem dependências circulares).
  • Garante que todos os tipos de recursos e versões de API sejam válidos.
  • Não implanta nenhum recurso.

Quando usar: Antes das implantações de produção para detetar erros antecipadamente.

Exemplo de comando:

az deployment group validate \
  --resource-group myResourceGroup \
  --template-file main.json \
  --parameters @parameters.json

Modo incremental (padrão)

Finalidade: Adicione ou atualize recursos sem afetar os existentes.

O que faz:

  • Implanta recursos definidos no modelo.
  • Deixa os recursos inalterados não definidos no modelo.
  • Atualiza os recursos se as configurações forem alteradas.

Exemplo de cenário:

  • O modelo define VM1, VM2, Storage1.
  • O grupo de recursos tem VM1, VM3, Storage1.
  • Após a implantação: VM1 (atualizado), VM2 (adicionado), VM3 (inalterado), Storage1 (atualizado).

Quando usar:

  • Adicionar novos recursos aos ambientes existentes.
  • Atualizar recursos específicos sem risco para outros.
  • Ambientes de desenvolvimento e teste.

Modo completo

Finalidade: Garantir que o grupo de recursos corresponda exatamente ao template (idempotência).

O que faz:

  • Implanta recursos definidos no modelo.
  • Exclui recursos não definidos no modelo.
  • O grupo de recursos contém APENAS o que está no template.

Exemplo de cenário:

  • O modelo define VM1, VM2, Storage1.
  • O grupo de recursos tem VM1, VM3, Storage1, VM4.
  • Após a implantação: VM1 (atualizado), VM2 (adicionado), Storage1 (atualizado), VM3 (excluído), VM4 (excluído).

Quando usar:

  • Ambientes de produção que exigem um rigoroso controlo estatal.
  • Atingir idempotência (o mesmo resultado em todas as implementações).
  • Remoção de recursos indesejados ou manuais.

Advertência

O modo completo pode excluir recursos. Teste cuidadosamente antes de usar na produção!

Definindo o modo de implantação

CLI do Azure:

# Incremental (default)
az deployment group create \
  --resource-group myResourceGroup \
  --template-file main.json \
  --mode Incremental

# Complete
az deployment group create \
  --resource-group myResourceGroup \
  --template-file main.json \
  --mode Complete

PowerShell::

# Incremental
New-AzResourceGroupDeployment `
  -ResourceGroupName myResourceGroup `
  -TemplateFile main.json `
  -Mode Incremental

# Complete
New-AzResourceGroupDeployment `
  -ResourceGroupName myResourceGroup `
  -TemplateFile main.json `
  -Mode Complete

Melhores práticas

Observação

Um grupo de recursos por implantação: Use grupos de recursos dedicados para cada aplicativo lógico ou ambiente para simplificar o gerenciamento e evitar exclusões acidentais.

Observação

Limitação de modelos vinculados/aninhados: Você só pode usar o modo incremental para modelos vinculados e aninhados. O modo completo não é suportado para implementações secundárias.

Recommendations:

  • Desenvolvimento: Use o modo incremental para flexibilidade e iteração mais rápida.
  • Produção: Utilize o modo Completo com pipelines de CI/CD para assegurar um estado consistente.
  • Antes do modo Concluído: Valide sempre primeiro e teste em ambientes que não sejam de produção.
  • Bloqueios de recursos: Aplique bloqueios a recursos críticos para evitar a exclusão acidental.

Modelos e parâmetros externos

Os modelos externos fornecem a base para arquiteturas de modelo ARM verdadeiramente modulares. Você armazena modelos filho em locais acessíveis e faz referência a eles via URI.

Requisitos de acessibilidade do modelo

O Resource Manager deve ser capaz de acessar modelos vinculados durante a implantação:

O que funciona:

  • Armazenamento de Blobs do Azure: Público ou privado com tokens SAS.
  • GitHub: Repositórios públicos ou privados com tokens de acesso.
  • Endereços HTTPS: Qualquer URL de HTTPS que seja publicamente acessível.
  • Instâncias de contêiner do Azure: Hospedagem de arquivos de modelo em contêineres.

O que não funciona:

  • Arquivos locais: Ficheiros no seu computador ou rede local.
  • File:// protocolo: Caminhos do sistema de arquivos local.
  • HTTP (não seguro): Apenas HTTPS é suportado.

templateLink: Faz referência a um arquivo de modelo externo.

parâmetrosLink: Faz referência a um arquivo de parâmetro externo (alternativa aos parâmetros embutidos).

Importante

Não é possível usar parâmetros embutidos e parametersLink simultaneamente. Escolha uma abordagem.

Exemplo completo com templateLink:

"resources": [
  {
    "name": "linkedStorageDeployment",
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2022-09-01",
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/templates/storage.json?sv=2021-06-08&sr=b&sig=ABC123...&se=2025-12-31T23:59:59Z&sp=r",
        "contentVersion": "1.0.0.0"
      },
      "parameters": {
        "storageAccountName": {
          "value": "[variables('storageAccountName')]"
        },
        "location": {
          "value": "[parameters('location')]"
        },
        "sku": {
          "value": "Standard_GRS"
        }
      }
    }
  }
]

Componentes-chave:

  • URI: URL HTTPS completo para o modelo vinculado (inclui token SAS se estiver usando armazenamento privado).
  • contentVersion: Versão do modelo vinculado (deve corresponder ao que está no arquivo de modelo vinculado).
  • Parâmetros: Valores passados para o modelo vinculado (podem fazer referência aos parâmetros/variáveis principais do modelo).

Usando arquivos de parâmetros externos

Alternativa aos parâmetros em linha:

{
  "name": "linkedDeployment",
  "type": "Microsoft.Resources/deployments",
  "apiVersion": "2022-09-01",
  "properties": {
    "mode": "Incremental",
    "templateLink": {
      "uri": "https://mystorageaccount.blob.core.windows.net/templates/main.json"
    },
    "parametersLink": {
      "uri": "https://mystorageaccount.blob.core.windows.net/parameters/prod.json"
    }
  }
}

Benefícios:

  • Separe arquivos de parâmetros por ambiente (dev.json, staging.json, prod.json).
  • Parâmetros sensíveis armazenados de forma segura em arquivos de parâmetros.
  • Mais fácil de gerenciar implantações em vários ambientes.

Protegendo modelos externos

Os modelos externos não precisam ser públicos. Você pode armazená-los em contas de armazenamento privado e usar tokens SAS (Assinatura de Acesso Compartilhado) para acesso seguro.

Etapas para proteger modelos

  1. Armazenar modelos no Armazenamento de Blobs privado do Azure:
# Create storage account and container
az storage account create \
  --name mytemplatestorage \
  --resource-group myResourceGroup \
  --location eastus \
  --sku Standard_LRS

az storage container create \
  --name templates \
  --account-name mytemplatestorage \
  --public-access off
  1. Carregue arquivos de modelo:
az storage blob upload \
  --account-name mytemplatestorage \
  --container-name templates \
  --name networking.json \
  --file ./templates/networking.json
  1. Gerar um token SAS com uma data de expiração:
# Create SAS token valid for 30 days
az storage blob generate-sas \
  --account-name mytemplatestorage \
  --container-name templates \
  --name networking.json \
  --permissions r \
  --expiry 2025-12-31T23:59:59Z \
  --https-only \
  --output tsv
  1. Use o token SAS na URI do templateLink:
"templateLink": {
  "uri": "https://mytemplatestorage.blob.core.windows.net/templates/networking.json?sv=2021-06-08&sr=b&sig=ABC123...&se=2025-12-31T23:59:59Z&sp=r"
}

Considerações de segurança

Registro de token SAS:

  • Mesmo que o token seja passado com segurança, o URI (incluindo o token SAS) é registrado em operações de implantação.
  • Os registos de implementação são visíveis para qualquer pessoa com acesso de leitura ao grupo de recursos.

Práticas recomendadas para segurança:

  • Definir datas de validade: Crie tokens SAS por tempo limitado (30-90 dias).
  • Use permissões de leitura apenas: Os tokens SAS devem conceder apenas permissão de leitura (r).
  • Rode tokens regularmente: Gere novos tokens e atualize modelos periodicamente.
  • Use o Azure Key Vault: Armazene tokens SAS no Cofre de Chaves e faça referência a eles em modelos.
  • Identidades gerenciadas: Considere o uso de identidades gerenciadas para acesso ao modelo em vez de tokens SAS.
  • Pontos finais privados: Utilize pontos finais privados do Azure Storage para uma segurança de rede adicional.

Exemplo com referência ao Key Vault:

"templateLink": {
  "uri": "[concat('https://mytemplatestorage.blob.core.windows.net/templates/networking.json', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), 'storageAccountSasToken')).secretValue)]"
}

Essa abordagem mantém os tokens SAS fora do código do modelo e dos registos de implementação.