Implantar instâncias de contêiner do Azure com um contêiner de inicialização
Às vezes, você precisa fazer certas tarefas antes que um aplicativo seja iniciado. Por exemplo, talvez seja necessário configurar determinados serviços para aceitar conectividade de entrada do contêiner ou injetar segredos do Cofre de Chaves do Azure em um volume. Você pode implementar essas tarefas de validação ou inicialização de pré-requisitos com contêineres de inicialização (init).
Os contêineres de inicialização são um exemplo do padrão de sidecar, mas os contêineres de inicialização são executados antes do início de qualquer outro contêiner no grupo de contêineres. Os contêineres de aplicativos no grupo de contêineres são iniciados somente depois que qualquer contêiner de inicialização definido conclui com êxito suas tarefas. Os contêineres init das Instâncias de Contêiner do Azure são o mesmo conceito dos contêineres init do Kubernetes.
Seu cliente deseja acessar sua API usando um FQDN (nome de domínio totalmente qualificado) em vez de um endereço IP. Eles também querem garantir que o FQDN não seja alterado se recriarem o grupo de contêineres. Nesta unidade, você usa um contêiner init para atualizar o DNS (Sistema de Nomes de Domínio) para que os clientes sempre possam acessar a API usando o nome de domínio em vez de um endereço IP.
O diagrama a seguir mostra a topologia do contêiner de inicialização de Instâncias de Contêiner:
O contêiner init recupera o endereço IP alocado para o contêiner do aplicativo e atualiza a entrada DNS que os clientes de API usam para alcançar o contêiner. O contêiner init e o contêiner do aplicativo compartilham a mesma pilha de rede, portanto, o endereço IP visível para o contêiner init é o mesmo que o contêiner do aplicativo usa.
Criar o script de inicialização e a zona DNS
Primeiro, você cria uma entidade de serviço do Azure que o contêiner init usa para recuperar o endereço IP do aplicativo e atualizar o DNS, porque você não pode usar identidades gerenciadas em um contêiner init. Neste exemplo, você atribui a função de Colaborador da entidade de serviço para simplificar. Em ambientes de produção, talvez você queira ser mais restritivo.
No Azure Cloud Shell no portal do Azure, execute o seguinte código para criar a entidade de serviço:
# Create service principal for authentication scope=$(az group show -n $rg --query id -o tsv) new_sp=$(az ad sp create-for-rbac --scopes $scope --role Contributor --name acilab -o json) sp_appid=$(echo $new_sp | jq -r '.appId') && echo $sp_appid sp_tenant=$(echo $new_sp | jq -r '.tenant') && echo $sp_tenant sp_password=$(echo $new_sp | jq -r '.password')
Crie a zona DNS privada do Azure para clientes de aplicativos acessarem a instância de contêiner e associe a zona à rede virtual.
# Create Azure DNS private zone and records dns_zone_name=contoso.com az network private-dns zone create -n $dns_zone_name -g $rg az network private-dns link vnet create -g $rg -z $dns_zone_name -n contoso --virtual-network $vnet_name --registration-enabled false
Nota
Essa zona DNS é diferente da zona DNS criada na unidade anterior, que a instância de contêiner usou para acessar o Banco de Dados SQL do Azure.
Há muitas maneiras de injetar um script em um contêiner init. Nesse caso, você usa um compartilhamento de Arquivos do Azure para armazenar o script. Execute o código a seguir para criar o script de inicialização, criar um compartilhamento de Arquivos do Azure e carregar o script no compartilhamento.
# Create script for init container storage_account_name="acilab$RANDOM" az storage account create -n $storage_account_name -g $rg --sku Standard_LRS --kind StorageV2 storage_account_key=$(az storage account keys list --account-name $storage_account_name -g $rg --query '[0].value' -o tsv) az storage share create --account-name $storage_account_name --account-key $storage_account_key --name initscript init_script_filename=init.sh init_script_path=/tmp/ cat <<EOF > ${init_script_path}${init_script_filename} echo "Logging into Azure..." az login --service-principal -u \$SP_APPID -p \$SP_PASSWORD --tenant \$SP_TENANT echo "Finding out IP address..." # my_private_ip=\$(az container show -n \$ACI_NAME -g \$RG --query 'ipAddress.ip' -o tsv) && echo \$my_private_ip my_private_ip=\$(ifconfig eth0 | grep 'inet addr' | cut -d: -f2 | cut -d' ' -f 1) && echo \$my_private_ip echo "Deleting previous record if there was one…" az network private-dns record-set a delete -n \$HOSTNAME -z \$DNS_ZONE_NAME -g \$RG -y echo "Creating DNS record..." az network private-dns record-set a create -n \$HOSTNAME -z \$DNS_ZONE_NAME -g \$RG az network private-dns record-set a add-record --record-set-name \$HOSTNAME -z \$DNS_ZONE_NAME -g \$RG -a \$my_private_ip EOF az storage file upload --account-name $storage_account_name --account-key $storage_account_key -s initscript --source ${init_script_path}${init_script_filename}
O script de inicialização usa a CLI do Azure para executar os comandos que descobrem o endereço IP da instância do contêiner e criam um registro A na zona DNS privada. O script autentica usando o ID do aplicativo principal de serviço e o segredo que ele espera encontrar como variáveis de ambiente.
Implantar o grupo de contêineres com o contêiner init
Agora você pode criar um arquivo YAML que se baseia nos arquivos usados em unidades anteriores. Observe esses itens no seguinte código YAML:
- Agora há uma
initContainers
seção. - O
initContainer
usa a imagem, que já tem amicrosoft/azure-cli:latest
CLI do Azure instalada. - O contêiner init executa um script armazenado na pasta /mnt/init/, que é montada a partir de um volume de Arquivos do Azure.
- O grupo de recursos, o nome da instância do contêiner e as credenciais da entidade de serviço são passados como variáveis de ambiente.
- O segredo da entidade de serviço é passado como uma variável de ambiente seguro.
- O resto das definições de YAML do recipiente permanecem inalteradas em relação às unidades anteriores.
Crie o arquivo YAML executando o seguinte código:
# Create YAML aci_subnet_id=$(az network vnet subnet show -n $aci_subnet_name --vnet-name $vnet_name -g $rg --query id -o tsv) aci_yaml_file=/tmp/acilab.yaml cat <<EOF > $aci_yaml_file apiVersion: '2023-05-01' location: $location name: $aci_name properties: subnetIds: - id: $aci_subnet_id initContainers: - name: azcli properties: image: mcr.microsoft.com/azure-cli:latest command: - "/bin/sh" - "-c" - "/mnt/init/$init_script_filename" environmentVariables: - name: RG value: $rg - name: SP_APPID value: $sp_appid - name: SP_PASSWORD secureValue: $sp_password - name: SP_TENANT value: $sp_tenant - name: DNS_ZONE_NAME value: $dns_zone_name - name: HOSTNAME value: $aci_name - name: ACI_NAME value: $aci_name volumeMounts: - name: initscript mountPath: /mnt/init/ containers: - name: nginx properties: image: nginx ports: - port: 443 protocol: TCP resources: requests: cpu: 1.0 memoryInGB: 1.5 volumeMounts: - name: nginx-config mountPath: /etc/nginx - name: sqlapi properties: image: erjosito/yadaapi:1.0 environmentVariables: - name: SQL_SERVER_FQDN value: $sql_server_fqdn - name: SQL_SERVER_USERNAME value: $sql_username - name: SQL_SERVER_PASSWORD secureValue: $sql_password ports: - port: 8080 protocol: TCP resources: requests: cpu: 1.0 memoryInGB: 1 volumeMounts: volumes: - secret: ssl.crt: "$ssl_crt" ssl.key: "$ssl_key" nginx.conf: "$nginx_conf" name: nginx-config - name: initscript azureFile: readOnly: false shareName: initscript storageAccountName: $storage_account_name storageAccountKey: $storage_account_key ipAddress: ports: - port: 443 protocol: TCP type: Private osType: Linux tags: null type: Microsoft.ContainerInstance/containerGroups EOF
Verifique o arquivo YAML gerado para verificar se a substituição de variáveis funcionou corretamente.
# Check YAML file more $aci_yaml_file
Crie as instâncias de contêiner. Essas instâncias demoram um pouco mais para serem criadas porque o contêiner init é executado antes do aplicativo e dos contêineres NGINX serem iniciados.
# Deploy ACI az container create -g $rg --file $aci_yaml_file
Verifique se o contêiner init criou um registro A na zona DNS Privado do Azure:
# Verify A records in the Azure Private DNS zone az network private-dns record-set a list -z $dns_zone_name -g $rg --query '[].{RecordName:name,IPv4Address:aRecords[0].ipv4Address}' -o table
Use os pontos de extremidade da API SQL para testar se o contêiner está acessível. Você usa o nome de domínio para acessar o contêiner, não seu endereço IP.
# Test aci_fqdn=${aci_name}.${dns_zone_name} && echo $aci_fqdn ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "nslookup $aci_fqdn" ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "curl -ks https://$aci_fqdn/api/healthcheck" ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "curl -ks https://$aci_fqdn/api/sqlversion" ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "curl -ks https://$aci_fqdn/api/sqlsrcip"
Você pode inspecionar os logs de instância de contêiner individuais para cada contêiner. Por exemplo, execute o seguinte código para acessar os logs de contêiner init:
# Init container logs az container logs -n $aci_name -g $rg --container-name azcli
Para evitar cobranças contínuas, exclua o grupo de recursos do Azure para limpar todos os recursos criados para esta unidade e módulo.
# Clean up module az group delete -n $rg -y --no-wait