Connexion à ADLS Gen2 depuis Hadoop (HDP) et NiFi (HDF)
5 nov. 2020
Ne ratez pas nos articles sur l'open source, le big data et les systèmes distribués, fréquence faible d’un email tous les deux mois.
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 plateforme 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é :
- Ouvrir le portail Azure
- Aller dans le tableau de bord Azure Active Directory (vous pouvez le trouver à l’aide de la bare de recherche)
- Aller dans App registrations → New registration
- Renseigner uniquement le champ
Name
(e.g.hdp-hdf-adls-app
) et cliquer surRegister
- Une fois l’applciation créée, elle apparaît dans “Owned applications”
- Afin de pouvoir s’authentifier en tant que service principal, nous aurons besoin d’un secret
- Allez dans your-app → Certificates & secrets
- 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) :
- Aller dans votre compte de stockage -> Access Controle (IAM)
- 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) :
-
Télécharger le binaire Nifi 1.12.0 depuis le site web officiel
-
Extraire l’archive. Les 2 NARs qui nous intéressent sont
nifi-azure-nar-1.12.0.nar
etnifi-azure-services-api-nar-1.12.0.nar
. Vous les trouverez dans le répertoirelib
. -
Sur chacun des noeuds Nifi :
- Localiser la home Nifi (e.g.
/usr/hdf/current/nifi
sur HDF) - 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
- Supprimer les NARs Azure existants (faire un backup)
- Copier les 2 NARs Azure de Nifi 1.12.0 mentionnés dans l’étapes 2. vers le répertoire
lib
- Assurez-vous que le propriétaire des fichiers soit bien l’utilisateur
nifi
:chown nifi:nifi /usr/hdf/current/nifi/lib/nifi-azure-*
- Localiser la home Nifi (e.g.
-
Redémarrer le cluster Nifi (via Ambari sur HDF)
-
Vérifier que les nouveaux composants sont bien disponibles (e.g. PutAzureDataLakeStorage) :
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 :
-
Installer Azure CLI
-
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:
-
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
-
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 :
- Créer un ADLSCredentialsControllerService
- Remplissez les propriétés
- Storage Account Name
- 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=...
- 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.