Connexion à ADLS Gen2 depuis Hadoop (HDP) et NiFi (HDF)

LEONARD Gauthier

By LEONARD Gauthier

5 nov. 2020

Alors que les projets Data construits sur le cloud deviennent de plus en plus répandus, un cas d’utilisation courant consiste à interagir avec le stockage cloud à partir d’une plate-forme Big Data on-premise déjà existante. Microsoft Azure a récemment introduit Data Lake Storage Gen2, qui repose sur Azure Blob et offre une gestion des données sur Azure qui se rapproche fortement de celle de HDFS. Ce produit étant assez récent (GA en Feb. 2019), la connexion à ADLS Gen2 à partir de HDP et HDF n’est pas encore prise en charge dans les versions publiques.

Dans cet article, nous allons voir de quelle manière écrire des données dans ADLS Gen2 en utilisant :

Obtenir l’accès à ADLS Gen2

Azure Data Lake Storage Gen2 prend en charge les mêmes options d’autorisation que le stockage Azure Blob. Dans cet article, nous accèderons à ADLS en utilisant un principal de service, ce qui nous laisse avec 3 options :

  • En utilisant un OAuth access token pour s’authentifier avec l’utilisateur / mot de passe, nous utiliserons cette méthode avec DistCp
  • En utilisant une Shared Account Key, qui équivaut à un mot de passe administrateur au niveau du compte de stockage et n’est pas recommandé
  • En utilisant une Shared Access Signature (SAS), nous utiliserons cette méthode avec NiFi

Créer un service principal dans Azure AD

Premièrement, nous aurons besoin de créer un service principal dans notre instance Azure Directory (tenant). Dans les faits, nous allons créer un objet application, qui aura un service principal pour chaque tenant sur lequel il est utilisé :

  1. Ouvrir le portail Azure
  2. Aller dans le tableau de bord Azure Active Directory (vous pouvez le trouver à l’aide de la bare de recherche)

    1. Aller dans App registrationsNew registration
    2. Renseigner uniquement le champ Name (e.g. hdp-hdf-adls-app) et cliquer sur Register
  3. Une fois l’applciation créée, elle apparaît dans “Owned applications”
  4. Afin de pouvoir s’authentifier en tant que service principal, nous aurons besoin d’un secret

    1. Allez dans your-appCertificates & secrets
    2. Générer un nouveau secret client et sauvegarder le afin de pouvoir la réutiliser plus tard

Donner accés à un compte de stockage ADLS

Dans cet article, nous allons donner tous les droits d’accès à notre service principal sur le compte de stockage (pour une gestion plus précise des accès veuillez vous référer à Gérer les droits d’accès à l’aide de RBAC) :

  1. Aller dans votre compte de stockage -> Access Controle (IAM)
  2. Assigner le rôle Storage Blob Data Contributor à votre application

Copier des données depuis HDP en utilisant DistCp

La connexion à ADLS Gen2 depuis Hadoop est supporté seulement depuis Hadoop 3.2.0. Par conséquent, cela n’est pas possible sur les versions HDP publiques, qui embarquent seulement jusqu’à la version 3.1.1 de Hadoop sans backport de cette fonctionnalité.

Rassembler les binaires nécessaires

Pour écrire des données dans ADLS Gen2, nous aurons besoin d’utiliser :

  • Les binaires Hadoop 3.3.0 pour la CLI Hadoop et MapReduce2
  • Le jar hadoop-azure
  • Le jar wildfly-openssl pour sécuriser la connexion à ADLS

Les commandes suivantes téléchargent et chargent les binaires hadoop dans HDFS (nécessite le package jq) :

# First create a directory to store all this stuff
mkdir distcp-to-adls
cd !$

# Fill in those properties
user=$USER
hadoop_version=3.3.0

# Download urls
hadoop_azure_jar="https://repo1.maven.org/maven2/org/apache/hadoop/hadoop-azure/$hadoop_version/hadoop-azure-$hadoop_version.jar"
wildfly_openssl_jar=https://repo1.maven.org/maven2/org/wildfly/openssl/wildfly-openssl/1.0.7.Final/wildfly-openssl-1.0.7.Final.jar

# Create the HDFS working directory
hdfs_dir="/user/$user/.distcp-adls"
hdfs dfs -mkdir -p "$hdfs_dir"
hdfs dfs -rm -r -f "$hdfs_dir/*"

# Get Hadoop prefered mirror url
hadoop_path="hadoop/common/hadoop-$hadoop_version/hadoop-$hadoop_version.tar.gz"
hadoop_mirror=$(curl "https://www.apache.org/dyn/closer.cgi/$hadoop_path&asjson=1" | jq -r '.preferred')
hadoop_url="$hadoop_mirror$hadoop_path"

# Download Hadoop 3.3.0 binaries
mkdir lib
wget -P lib "$hadoop_url" && wget -P lib "$hadoop_azure_jar" && wget -P lib "$wildfly_openssl_jar"

# Rename root directory in Hadoop binary to match DistCp internal behavior
cd lib && tar -xzf "hadoop-$hadoop_version.tar.gz"
mv "hadoop-$hadoop_version" hadoop
tar -czf mapreduce.tar.gz hadoop && cd ..

# Put Hadoop binary in HDFS for use in DistCp
hdfs dfs -put lib/mapreduce.tar.gz "$hdfs_dir"

# Gather only needed Hadoop conf files
mkdir hadoop-conf
cp /etc/hadoop/conf/*-site.xml hadoop-conf

Si tous à fonctionner correctement, vous devais retourver :

  • Tous les binaires dans ./lib :

    ls -1 lib
    hadoop
    hadoop-3.3.0.tar.gz
    hadoop-azure-3.3.0.jar
    mapreduce.tar.gz
    wildfly-openssl-1.0.7.Final.jar
  • Les binaires Hadoop sont mapreduce.tar.gz dans HDFS /user/MY_USERNAME/.distcp-adls :

    hdfs dfs -ls /user/leonardg/.distcp-adls
    Found 1 items
    -rw-r--r--   3 leonardg users  500735363 2020-09-24 19:14 /user/leonardg/.distcp-adls/mapreduce.tar.gz

Stocker les identifiants dans un Hadoop CredentialProvider

Afin de ne pas stocker les identifiants de notre service principal en texte brut, utilisons un Hadoop CredentialProvider dans lequel nous pourrons stocker le endpoint OAuth, l’application (client) ID et le secret de l’application :

# Fill in those properties (find them on Azure Portal)
tenant=mycompany.onmicrosoft.com
app_id=MY_APP_ID

# Don't store the app secret in your history
read -s app_secret

# Store credentials in a Hadoop credential provider
cred_provider="$hdfs_dir/adls2keyfile.jceks"
oauth_endpoint="https://login.microsoftonline.com/$tenant/oauth2/token"

hdfs dfs -rm -f "$cred_provider"
hadoop credential create fs.azure.account.oauth2.client.endpoint \
  -provider "jceks://hdfs$cred_provider" -value "$oauth_endpoint"
hadoop credential create fs.azure.account.oauth2.client.id \
  -provider "jceks://hdfs$cred_provider" -value "$app_id"
hadoop credential create fs.azure.account.oauth2.client.secret \
  -provider "jceks://hdfs$cred_provider" -value "$app_secret"

Si tous s’est déroulé correctement, vous devriez retrouver les 3 propriétés dans votre CredentialProvider :

hadoop credential list -provider "jceks://hdfs$cred_provider"
Listing aliases for CredentialProvider: jceks://hdfs/user/leonardg/.distcp-adls/adls2keyfile.jceks
fs.azure.account.oauth2.client.id
fs.azure.account.oauth2.client.endpoint
fs.azure.account.oauth2.client.secret

Copier des fichiers avec DistCp

Maintenant que tous est corrèctement configuré, nous pouvons copier un fichier depuis HDFS vers ADLS avec DistCp :

# Fill in those properties
user=$USER
hdfs_dir="/user/$user/.distcp-adls"
hdfs_cp_dir=/path/to/dir/in/hdfs
storage_account=ADLS_STORAGE_ACCOUNT
container=ADLS_CONTAINER
adls_cp_dir=path/to/copy/dir

adls_cp_url="abfss://$container@$storage_account.dfs.core.windows.net/$adls_cp_dir"

lib/hadoop/bin/hadoop \
  --config "./hadoop-conf" \
  distcp \
  -Dfs.azure.account.auth.type=OAuth \
  -Dfs.azure.account.oauth.provider.type=org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider \
  -Dhdp.version="$hdp_version" \
  -Dmapreduce.application.framework.path="$hdfs_dir/mapreduce.tar.gz#mr-framework" \
  -Dhadoop.security.credential.provider.path="jceks://hdfs$hdfs_dir/adls2keyfile.jceks" \
  -libjars "./lib/hadoop-azure-3.3.0.jar,./lib/wildfly-openssl-1.0.7.Final.jar" \
  "$hdfs_cp_dir" "$adls_cp_url"

Écrire des données avec Nifi

Des processors natifs ADLS Gen2 ont été ajoutés à Nifi dans la version 1.12.0 (NIFI-7103). Bien qu’il serait possible d’intéragir avec ADLS Gen2 en utilisant les processors HDFS, cela implique de stocker l’account key du compte de stockage en texte brut dans le fichier core-site.xml, ce qui n’est bien sûr pas recommandé. Nous utiliserons donc les nouveaux processors natifs.

Importer les processors nécessaires

Premièrement, nous avons besoin d’ajouter le nouveaux processors à notre instance Nifi (note : vous n’avez pas besoin de mettre à jour votre cluster Nifi, la procédure suivante a été testée sur Nifi 1.9.0) :

  1. Télécharger le binaire Nifi 1.12.0 depuis le site web officiel
  2. Extraire l’archive. Les 2 NARs qui nous intéressent sont nifi-azure-nar-1.12.0.nar et nifi-azure-services-api-nar-1.12.0.nar. Vous les trouverez dans le répertoire lib.
  3. Sur chacun des noeuds Nifi :

    1. Localiser la home Nifi (e.g. /usr/hdf/current/nifi sur HDF)
    2. Chercher les NARs Azure dans le répertoire lib :

      ls -l /usr/hdf/current/nifi/lib | grep azure
      nifi-azure-nar-1.9.0.3.4.1.1-4.nar
    3. Supprimer les NARs Azure existants (faire un backup)
    4. Copier les 2 NARs Azure de Nifi 1.12.0 mentionnés dans l’étapes 2. vers le répertoire lib
    5. Assurez-vous que le propriétaire des fichiers soit bien l’utilisateur nifi :

      chown nifi:nifi /usr/hdf/current/nifi/lib/nifi-azure-*
  4. Redémarrer le cluster Nifi (via Ambari sur HDF)
  5. Vérifier que les nouveaux composants sont bien disponibles (e.g. PutAzureDataLakeStorage) :
    Azure Processors

Générer une Shared Access Signature

Note : Dans la documentation Azure française, “Shared Access Signature” est traduit par “Signature d’accès partagé (SAP)“.

Un ADLSCredentialsControllerService est utilisé par Nifi pour stocker les identifiants d’accès à ADLS. Il faut, soit une account key, soit un token SAS pour s’authentifier. Même si les identifiants sont chiffrés par Nifi, nous allons utiliser la méthode SAS qui est recommandée par Microsoft.

Générons une user delegation SAS pour notre container ADLS. Une user delegation SAS utilise un compte Active Directory afin de signer la SAS (au lieu d’une account key pour les account/service SAS). Cela permet une double vérification des permissions lors de l’accès :

  • Vérification des permissions de l’utilisateur ayant signé la SAS
  • Vérification des permissions accordées par la SAS (voir Spécifier des autorisations)

La manière la plus simple de générer une SAS est d’installer Azure CLI :

  1. Installer Azure CLI
  2. Se connecter à la CLI en utilisant le service principal créé dans la première partie de l’article (password = secret)

    az login --service-principal -u SP_ID --tenant mycompany.onmicrosoft.com
    Password:
  3. Utiliser la commande az storage container generate-sas (ajuster les permissions)

    #Fill in those properties
    storage_account=ADLS_STORAGE_ACCOUNT
    container=ADLS_CONTAINER
    
    az storage container generate-sas -n "$container" \
     --account-name "$storage_account" \
     --subscription "MySubscription" \
     --permission dlrw \
     --expiry 2020-09-25T00:00:00Z \
     --as-user --auth-mode login
  4. Sauvegarder la SAS généré

Note : La durée maximale d’une user delegation SAS est de 7 jours, vous devrez donc automatiser son renouvellement ou utiliser un service SAS qui peut avoir une durée de vie plus longue.

Configurer le dataflow

Nous pouvons maintenant intéragir avec ADLS Gen2 depuis un dataflow NiFi :

  1. Créer un ADLSCredentialsControllerService
  2. Remplissez les propriétés

    1. Storage Account Name
    2. SAS Token : Ajouter un ? avant la SAS généré précédemment. Exemple :

      ?se=2020-11-10T00%3A00%3A00Z&sp=rwdl&sv=2018-11-09&sr=...
  3. Créer le processor dont vous avez besoin pour accéder à ADLS Gen2, en utilisant le ADLSCredentialsControllerService créé précédemment

Solutions alternatives

Azure Data Factory

Une solution alternative pour copier des données depuis un cluster Hadoop on-premise vers Azure est d’utiliser Azure Data Factory, qui offre une panoplie de connecteurs :

Data Factory vous permet en outre de créer un self-hosted integration runtime dans votre réseaux privé on-premise.

Toute la configuration est bien expliquée sur la documentation Azure donc nous n’en parlerons pas plus ici !

Résumé

Dans cet article, nous avons vu que même s’il n’est pas pris en charge nativement, nous pouvons facilement utiliser des versions ultérieures de quelques composants pour interagir avec ADLS Gen2 à partir des plates-formes HDP et HDF.

Canada - Morocco - France

International locations

10 rue de la Kasbah
2393 Rabbat
Canada

Nous sommes une équipe passionnées par l'Open Source, le Big Data et les technologies associées telles que le Cloud, le Data Engineering, la Data Science le DevOps…

Nous fournissons à nos clients un savoir faire reconnu sur la manière d'utiliser les technologies pour convertir leurs cas d'usage en projets exploités en production, sur la façon de réduire les coûts et d'accélérer les livraisons de nouvelles fonctionnalités.

Si vous appréciez la qualité de nos publications, nous vous invitons à nous contacter en vue de coopérer ensemble.