Desenvolvimento de ações de script com o HDInsight

Saiba como personalizar o cluster do HDInsight com scripts do Bash. As ações de script são uma forma de personalizar o HDInsight durante ou após a criação do cluster.

O que são ações de script

As ações de script são scripts do Bash que o Azure executa nos nós do cluster para fazer alterações de configuração ou instalar software. Uma ação de script é executada como raiz e fornece direitos de acesso total aos nós de cluster.

As ações de script podem ser aplicadas através dos seguintes métodos:

Utilize este método para aplicar um script... Durante a criação do cluster... Num cluster em execução...
Portal do Azure
Azure PowerShell
CLI Clássica do Azure  
HDInsight .NET SDK
Modelo do Azure Resource Manager  

Para obter mais informações sobre como utilizar estes métodos para aplicar ações de script, veja Personalizar clusters do HDInsight com ações de script.

Melhores práticas para o desenvolvimento de scripts

Quando desenvolve um script personalizado para um cluster do HDInsight, existem várias práticas recomendadas a ter em conta:

Importante

As ações de script têm de ser concluídas dentro de 60 minutos ou o processo falha. Durante o aprovisionamento de nós, o script é executado em simultâneo com outros processos de configuração e configuração. A concorrência para recursos como o tempo da CPU ou a largura de banda de rede pode fazer com que o script dedure mais tempo a concluir do que no seu ambiente de desenvolvimento.

Direcionar a versão do Apache Hadoop

Diferentes versões do HDInsight têm versões diferentes de serviços e componentes do Hadoop instalados. Se o script esperar uma versão específica de um serviço ou componente, só deve utilizar o script com a versão do HDInsight que inclui os componentes necessários. Pode encontrar informações sobre versões de componentes incluídas no HDInsight com o documento de controlo de versões de componentes do HDInsight .

Verificar a versão do sistema operativo

Diferentes versões do HDInsight dependem de versões específicas do Ubuntu. Podem existir diferenças entre as versões do SO que tem de verificar no script. Por exemplo, poderá ter de instalar um binário associado à versão do Ubuntu.

Para verificar a versão do SO, utilize lsb_release. Por exemplo, o seguinte script demonstra como referenciar um ficheiro tar específico consoante a versão do SO:

OS_VERSION=$(lsb_release -sr)
if [[ $OS_VERSION == 14* ]]; then
    echo "OS version is $OS_VERSION. Using hue-binaries-14-04."
    HUE_TARFILE=hue-binaries-14-04.tgz
elif [[ $OS_VERSION == 16* ]]; then
    echo "OS version is $OS_VERSION. Using hue-binaries-16-04."
    HUE_TARFILE=hue-binaries-16-04.tgz
fi

Direcionar a versão do sistema operativo

O HDInsight baseia-se na distribuição do Ubuntu Linux. Diferentes versões do HDInsight dependem de diferentes versões do Ubuntu, que podem alterar o comportamento do script. Por exemplo, o HDInsight 3.4 e anterior baseiam-se em versões do Ubuntu que utilizam o Upstart. As versões 3.5 e superiores baseiam-se no Ubuntu 16.04, que utiliza Systemd. Systemd e Upstart dependem de comandos diferentes, pelo que o script deve ser escrito para trabalhar com ambos.

Outra diferença importante entre o HDInsight 3.4 e 3.5 é que JAVA_HOME agora aponta para Java 8. O código seguinte demonstra como determinar se o script está em execução no Ubuntu 14 ou 16:

OS_VERSION=$(lsb_release -sr)
if [[ $OS_VERSION == 14* ]]; then
    echo "OS version is $OS_VERSION. Using hue-binaries-14-04."
    HUE_TARFILE=hue-binaries-14-04.tgz
elif [[ $OS_VERSION == 16* ]]; then
    echo "OS version is $OS_VERSION. Using hue-binaries-16-04."
    HUE_TARFILE=hue-binaries-16-04.tgz
fi
...
if [[ $OS_VERSION == 16* ]]; then
    echo "Using systemd configuration"
    systemctl daemon-reload
    systemctl stop webwasb.service    
    systemctl start webwasb.service
else
    echo "Using upstart configuration"
    initctl reload-configuration
    stop webwasb
    start webwasb
fi
...
if [[ $OS_VERSION == 14* ]]; then
    export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
elif [[ $OS_VERSION == 16* ]]; then
    export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
fi

Pode encontrar o script completo que contém estes fragmentos em https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh.

Para obter a versão do Ubuntu que é utilizada pelo HDInsight, veja o documento de versão do componente do HDInsight .

Para compreender as diferenças entre Systemd e Upstart, veja Systemd for Upstart users (Systemd for Upstart users).

Fornecer ligações estáveis para recursos de script

O script e os recursos associados têm de permanecer disponíveis ao longo da duração do cluster. Estes recursos são necessários se forem adicionados novos nós ao cluster durante as operações de dimensionamento.

A melhor prática é transferir e arquivar tudo numa conta de Armazenamento do Azure na sua subscrição.

Importante

A conta de armazenamento utilizada tem de ser a conta de armazenamento predefinida para o cluster ou um contentor público só de leitura em qualquer outra conta de armazenamento.

Por exemplo, os exemplos fornecidos pela Microsoft são armazenados na https://hdiconfigactions.blob.core.windows.net/ conta de armazenamento. Esta localização é um contentor público só de leitura mantido pela equipa do HDInsight.

Utilizar recursos pré-compilados

Para reduzir o tempo necessário para executar o script, evite operações que compilam recursos a partir do código fonte. Por exemplo, pré-compile recursos e armazene-os num blob de conta de Armazenamento do Azure no mesmo datacenter que o HDInsight.

Certifique-se de que o script de personalização do cluster é idempotente

Os scripts têm de ser idempotentes. Se o script for executado várias vezes, deverá devolver sempre o cluster ao mesmo estado.

Por exemplo, um script que modifica os ficheiros de configuração não deve adicionar entradas duplicadas se for executado várias vezes.

Garantir a elevada disponibilidade da arquitetura do cluster

Os clusters do HDInsight baseados em Linux fornecem dois nós principais que estão ativos no cluster e as ações de script são executadas em ambos os nós. Se os componentes instalados esperarem apenas um nó principal, não instale os componentes em ambos os nós principais.

Importante

Os serviços fornecidos como parte do HDInsight foram concebidos para efetuar a ativação pós-falha entre os dois nós principais, conforme necessário. Esta funcionalidade não é expandida para componentes personalizados instalados através de ações de script. Se precisar de elevada disponibilidade para componentes personalizados, tem de implementar o seu próprio mecanismo de ativação pós-falha.

Configurar os componentes personalizados para utilizar o armazenamento de Blobs do Azure

Os componentes instalados no cluster podem ter uma configuração predefinida que utiliza o armazenamento do Sistema de Ficheiros Distribuído do Apache Hadoop (HDFS). O HDInsight utiliza o Armazenamento do Azure ou Data Lake Storage como o armazenamento predefinido. Ambos fornecem um sistema de ficheiros compatível com HDFS que persiste nos dados, mesmo que o cluster seja eliminado. Poderá ter de configurar os componentes instalados para utilizar o WASB ou o ADL em vez do HDFS.

Para a maioria das operações, não precisa de especificar o sistema de ficheiros. Por exemplo, o seguinte copia o ficheiro hadoop-common.jar do sistema de ficheiros local para o armazenamento de clusters:

hdfs dfs -put /usr/hdp/current/hadoop-client/hadoop-common.jar /example/jars/

Neste exemplo, o hdfs comando utiliza de forma transparente o armazenamento de clusters predefinido. Para algumas operações, poderá ter de especificar o URI. Por exemplo, adl:///example/jars para Azure Data Lake Storage Gen1, abfs:///example/jars para Data Lake Storage Gen2 ou wasb:///example/jars para o Armazenamento do Azure.

Escrever informações para STDOUT e STDERR

O HDInsight regista a saída do script que é escrita em STDOUT e STDERR. Pode ver estas informações com a IU da Web do Ambari.

Nota

O Apache Ambari só está disponível se o cluster for criado com êxito. Se utilizar uma ação de script durante a criação do cluster e a criação falhar, veja Resolver problemas de ações de script para outras formas de aceder a informações registadas.

A maioria dos utilitários e pacotes de instalação já escreve informações em STDOUT e STDERR. No entanto, poderá querer adicionar registos adicionais. Para enviar texto para STDOUT, utilize echo. Por exemplo:

echo "Getting ready to install Foo"

Por predefinição, echo envia a cadeia para STDOUT. Para direcioná-lo para STDERR, adicione >&2 antes echode . Por exemplo:

>&2 echo "An error occurred installing Foo"

Em vez disso, redireciona as informações escritas para STDOUT para STDERR (2). Para obter mais informações sobre o redirecionamento de E/S, consulte https://www.tldp.org/LDP/abs/html/io-redirection.html.

Para obter mais informações sobre a visualização de informações registadas por ações de script, veja Resolver problemas de ações de scripts.

Guardar ficheiros como ASCII com terminações de linha LF

Os scripts bash devem ser armazenados como formato ASCII, com linhas terminadas por LF. Os ficheiros armazenados como UTF-8 ou que utilizem CRLF como terminação da linha podem falhar com o seguinte erro:

$'\r': command not found
line 1: #!/usr/bin/env: No such file or directory

Utilizar a lógica de repetição para recuperar de erros transitórios

Ao transferir ficheiros, instalar pacotes com apt-get ou outras ações que transmitem dados através da Internet, a ação pode falhar devido a erros transitórios de rede. Por exemplo, o recurso remoto com o qual está a comunicar pode estar em processo de ativação pós-falha para um nó de cópia de segurança.

Para tornar o script resiliente a erros transitórios, pode implementar a lógica de repetição. A função seguinte demonstra como implementar a lógica de repetição. Volta a tentar a operação três vezes antes de falhar.

#retry
MAXATTEMPTS=3

retry() {
    local -r CMD="$@"
    local -i ATTMEPTNUM=1
    local -i RETRYINTERVAL=2

    until $CMD
    do
        if (( ATTMEPTNUM == MAXATTEMPTS ))
        then
                echo "Attempt $ATTMEPTNUM failed. no more attempts left."
                return 1
        else
                echo "Attempt $ATTMEPTNUM failed! Retrying in $RETRYINTERVAL seconds..."
                sleep $(( RETRYINTERVAL ))
                ATTMEPTNUM=$ATTMEPTNUM+1
        fi
    done
}

Os exemplos seguintes demonstram como utilizar esta função.

retry ls -ltr foo

retry wget -O ./tmpfile.sh https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh

Métodos auxiliares para scripts personalizados

Os métodos auxiliares da ação de script são utilitários que pode utilizar ao escrever scripts personalizados. Estes métodos estão contidos no https://hdiconfigactions.blob.core.windows.net/linuxconfigactionmodulev01/HDInsightUtilities-v01.sh script. Utilize o seguinte para transferi-los e utilizá-los como parte do script:

# Import the helper method module.
wget -O /tmp/HDInsightUtilities-v01.sh -q https://hdiconfigactions.blob.core.windows.net/linuxconfigactionmodulev01/HDInsightUtilities-v01.sh && source /tmp/HDInsightUtilities-v01.sh && rm -f /tmp/HDInsightUtilities-v01.sh

Os seguintes programadores de ajuda disponíveis para utilização no script:

Utilização do programa auxiliar Descrição
download_file SOURCEURL DESTFILEPATH [OVERWRITE] Transfere um ficheiro do URI de origem para o caminho de ficheiro especificado. Por predefinição, não substitui um ficheiro existente.
untar_file TARFILE DESTDIR Extrai um ficheiro tar (com -xf) para o diretório de destino.
test_is_headnode Se o script tiver sido executado num nó principal do cluster, devolve 1; caso contrário, 0.
test_is_datanode Se o nó atual for um nó de dados (trabalho), devolva um 1; caso contrário, 0.
test_is_first_datanode Se o nó atual for o primeiro nó de dados (worker) (denominado workernode0) devolver um 1; caso contrário, 0.
get_headnodes Devolva o nome de domínio completamente qualificado dos nós principais no cluster. Os nomes são delimitados por vírgulas. É devolvida uma cadeia vazia com o erro .
get_primary_headnode Obtém o nome de domínio completamente qualificado do nó principal principal. É devolvida uma cadeia vazia com o erro .
get_secondary_headnode Obtém o nome de domínio completamente qualificado do nó principal secundário. É devolvida uma cadeia vazia com o erro .
get_primary_headnode_number Obtém o sufixo numérico do nó principal primário. É devolvida uma cadeia vazia com o erro .
get_secondary_headnode_number Obtém o sufixo numérico do nó principal secundário. É devolvida uma cadeia vazia com o erro .

Padrões de utilização comuns

Esta secção fornece orientações sobre como implementar alguns dos padrões de utilização comuns que pode encontrar ao escrever o seu próprio script personalizado.

Transmitir parâmetros para um script

Em alguns casos, o script pode exigir parâmetros. Por exemplo, poderá precisar da palavra-passe de administrador do cluster ao utilizar a API REST do Ambari.

Os parâmetros transmitidos para o script são conhecidos como parâmetros posicionais e são atribuídos para $1 o primeiro parâmetro, $2 para o segundo e assim sucessivamente. $0 contém o nome do próprio script.

Os valores transmitidos ao script como parâmetros devem ser colocados entre plicas ('). Ao fazê-lo, garante que o valor transmitido é tratado como um literal.

Definir variáveis de ambiente

A definição de uma variável de ambiente é efetuada pela seguinte instrução:

VARIABLENAME=value

No exemplo anterior, VARIABLENAME é o nome da variável . Para aceder à variável, utilize $VARIABLENAME. Por exemplo, para atribuir um valor fornecido por um parâmetro posicional como uma variável de ambiente denominada PASSWORD, utilizaria a seguinte instrução:

PASSWORD=$1

Em seguida, o acesso subsequente às informações poderia utilizar $PASSWORD.

As variáveis de ambiente definidas no script só existem no âmbito do script. Em alguns casos, poderá ter de adicionar variáveis de ambiente ao nível do sistema que irão persistir após a conclusão do script. Para adicionar variáveis de ambiente ao nível do sistema, adicione a variável a /etc/environment. Por exemplo, a seguinte instrução adiciona HADOOP_CONF_DIR:

echo "HADOOP_CONF_DIR=/etc/hadoop/conf" | sudo tee -a /etc/environment

Acesso a localizações onde os scripts personalizados estão armazenados

Os scripts utilizados para personalizar um cluster têm de ser armazenados numa das seguintes localizações:

  • Uma conta de Armazenamento do Azure associada ao cluster.

  • Uma conta de armazenamento adicional associada ao cluster.

  • Um URI legível publicamente. Por exemplo, um URL para dados armazenados no OneDrive, Dropbox ou outro serviço de alojamento de ficheiros.

  • Uma conta Azure Data Lake Storage associada ao cluster do HDInsight. Para obter mais informações sobre como utilizar Azure Data Lake Storage com o HDInsight, veja Início Rápido: Configurar clusters no HDInsight.

    Nota

    O principal de serviço que o HDInsight utiliza para aceder Data Lake Storage tem de ter acesso de leitura ao script.

Os recursos utilizados pelo script também têm de estar publicamente disponíveis.

Armazenar os ficheiros numa conta de Armazenamento do Azure ou Azure Data Lake Storage fornece acesso rápido, tal como na rede do Azure.

Nota

O formato URI utilizado para referenciar o script difere consoante o serviço que está a ser utilizado. Para contas de armazenamento associadas ao cluster do HDInsight, utilize wasb:// ou wasbs://. Para URIs legíveis publicamente, utilize http:// ou https://. Para Data Lake Storage, utilize adl://.

Lista de verificação para implementar uma ação de script

Eis os passos a seguir ao preparar a implementação de um script:

  • Coloque os ficheiros que contêm os scripts personalizados num local acessível pelos nós de cluster durante a implementação. Por exemplo, o armazenamento predefinido para o cluster. Os ficheiros também podem ser armazenados em serviços de alojamento legíveis publicamente.
  • Verifique se o script é idempotente. Fazê-lo permite que o script seja executado várias vezes no mesmo nó.
  • Utilize um diretório de ficheiros /tmp temporário para manter os ficheiros transferidos utilizados pelos scripts e, em seguida, limpe-os após a execução dos scripts.
  • Se as definições ao nível do SO ou os ficheiros de configuração do serviço Hadoop forem alterados, poderá querer reiniciar os serviços do HDInsight.

Como executar uma ação de script

Pode utilizar ações de script para personalizar clusters do HDInsight com os seguintes métodos:

  • Portal do Azure
  • Azure PowerShell
  • Modelos do Azure Resource Manager
  • O SDK .NET do HDInsight.

Para obter mais informações sobre como utilizar cada método, veja Como utilizar a ação de script.

Exemplos de scripts personalizados

A Microsoft fornece scripts de exemplo para instalar componentes num cluster do HDInsight. Veja Instalar e utilizar o Hue em clusters do HDInsight como uma ação de script de exemplo.

Resolução de problemas

Seguem-se erros que pode encontrar ao utilizar scripts que desenvolveu:

Erro: $'\r': command not found. Por vezes, seguido de syntax error: unexpected end of file.

Causa: este erro é causado quando as linhas num script terminam com CRLF. Os sistemas Unix esperam apenas LF à medida que a linha termina.

Este problema ocorre com mais frequência quando o script é criado num ambiente do Windows, uma vez que CRLF é uma linha comum que termina para muitos editores de texto no Windows.

Resolução: se for uma opção no seu editor de texto, selecione Formato Unix ou LF para a linha que termina. Também pode utilizar os seguintes comandos num sistema Unix para alterar o CRLF para um LF:

Nota

Os seguintes comandos são aproximadamente equivalentes, uma vez que devem alterar as terminações da linha CRLF para LF. Selecione um com base nos utilitários disponíveis no seu sistema.

Comando Notas
unix2dos -b INFILE O ficheiro original é efetuado uma cópia de segurança com um . Extensão BAK
tr -d '\r' < INFILE > OUTFILE OUTFILE contém uma versão com apenas finais LF
perl -pi -e 's/\r\n/\n/g' INFILE Modifica diretamente o ficheiro
sed 's/$'"/`echo \\\r`/" INFILE > OUTFILE OUTFILE contém uma versão com apenas finais LF.

Erro: line 1: #!/usr/bin/env: No such file or directory.

Causa: este erro ocorre quando o script foi guardado como UTF-8 com uma Marca de Encomenda byte (BOM).

Resolução: guarde o ficheiro como ASCII ou como UTF-8 sem um BOM. Também pode utilizar o seguinte comando num sistema Linux ou Unix para criar um ficheiro sem o BOM:

awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}{print}' INFILE > OUTFILE

Substitua INFILE pelo ficheiro que contém o BOM. OUTFILE deve ser um novo nome de ficheiro, que contém o script sem o BOM.

Passos seguintes