J'essaie de forcer mon application Spark Streaming à lire ses entrées dans un répertoire S3, mais je continue à avoir cette exception après l'avoir lancée avec le script spark-submit
Exception in thread "main" Java.lang.IllegalArgumentException: AWS Access Key ID and Secret Access Key must be specified as the username or password (respectively) of a s3n URL, or by setting the fs.s3n.awsAccessKeyId or fs.s3n.awsSecretAccessKey properties (respectively).
at org.Apache.hadoop.fs.s3.S3Credentials.initialize(S3Credentials.Java:66)
at org.Apache.hadoop.fs.s3native.Jets3tNativeFileSystemStore.initialize(Jets3tNativeFileSystemStore.Java:49)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:606)
at org.Apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.Java:82)
at org.Apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.Java:59)
at org.Apache.hadoop.fs.s3native.$Proxy6.initialize(Unknown Source)
at org.Apache.hadoop.fs.s3native.NativeS3FileSystem.initialize(NativeS3FileSystem.Java:216)
at org.Apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.Java:1386)
at org.Apache.hadoop.fs.FileSystem.access$200(FileSystem.Java:66)
at org.Apache.hadoop.fs.FileSystem$Cache.get(FileSystem.Java:1404)
at org.Apache.hadoop.fs.FileSystem.get(FileSystem.Java:254)
at org.Apache.hadoop.fs.Path.getFileSystem(Path.Java:187)
at org.Apache.spark.streaming.StreamingContext.checkpoint(StreamingContext.scala:195)
at MainClass$.main(MainClass.scala:1190)
at MainClass.main(MainClass.scala)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:606)
at org.Apache.spark.deploy.SparkSubmit$.launch(SparkSubmit.scala:292)
at org.Apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:55)
at org.Apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Je mets ces variables dans ce bloc de code comme suggéré ici http://spark.Apache.org/docs/latest/ec2-scripts.html (bas de la page):
val ssc = new org.Apache.spark.streaming.StreamingContext(
conf,
Seconds(60))
ssc.sparkContext.hadoopConfiguration.set("fs.s3n.awsAccessKeyId",args(2))
ssc.sparkContext.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey",args(3))
args (2) et args (3) sont bien sûr mes identifiants de clé d'accès AWS et de clé d'accès Secrete.
Pourquoi continue à dire qu'ils ne sont pas réglés?
EDIT: J'ai aussi essayé de cette façon, mais j'ai la même exception:
val lines = ssc.textFileStream("s3n://"+ args(2) +":"+ args(3) + "@<mybucket>/path/")
Impair. Essayez également de faire un .set
sur la sparkContext
. Essayez également d'exporter des variables env avant de démarrer l'application:
export AWS_ACCESS_KEY_ID=<your access>
export AWS_SECRET_ACCESS_KEY=<your secret>
^^ c'est comme ça qu'on le fait.
MISE À JOUR: Selon @tribbloid, ce qui précède s’est rompu dans la version 1.3.0, vous devez maintenant naviguer pendant des siècles avec hdfs-site.xml, ou vous pouvez le faire (et cela fonctionne dans un spark-shell):
val hadoopConf = sc.hadoopConfiguration;
hadoopConf.set("fs.s3.impl", "org.Apache.hadoop.fs.s3native.NativeS3FileSystem")
hadoopConf.set("fs.s3.awsAccessKeyId", myAccessKey)
hadoopConf.set("fs.s3.awsSecretAccessKey", mySecretKey)
La configuration suivante fonctionne pour moi, assurez-vous de définir également "fs.s3.impl":
val conf = new SparkConf().setAppName("Simple Application").setMaster("local")
val sc = new SparkContext(conf)
val hadoopConf=sc.hadoopConfiguration;
hadoopConf.set("fs.s3.impl", "org.Apache.hadoop.fs.s3native.NativeS3FileSystem")
hadoopConf.set("fs.s3.awsAccessKeyId",myAccessKey)
hadoopConf.set("fs.s3.awsSecretAccessKey",mySecretKey)
Pour ceux qui utilisent EMR, utilisez la version Spark comme décrit à https://github.com/awslabs/emr-bootstrap-actions/tree/master/spark et faites simplement référence à S3 avec l'URI s3: //. Il n'est pas nécessaire de définir l'implémentation S3 ou une configuration supplémentaire, car les informations d'identification sont définies par IAM ou par rôle.
Sur AWS EMR, les suggestions ci-dessus ne fonctionnaient pas. Au lieu de cela, j'ai mis à jour les propriétés suivantes dans le fichier conf/core-site.xml:
fs.s3n.awsAccessKeyId et fs.s3n.awsSecretAccessKey avec vos informations d'identification S3.
Je voulais mettre les informations d'identification de manière plus sécurisée dans un fichier de configuration sur l'une de mes partitions chiffrées. J'ai donc utilisé export HADOOP_CONF_DIR=~/Private/.aws/hadoop_conf
avant d'exécuter mon application spark et placé un fichier dans ce répertoire (chiffré via ecryptfs
) appelé core-site.xml
contenant les informations d'identification suivantes:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.s3n.awsAccessKeyId</name>
<value>my_aws_access_key_id_here</value>
</property>
<property>
<name>fs.s3n.awsSecretAccessKey</name>
<value>my_aws_secret_access_key_here</value>
</property>
</configuration>
HADOOP_CONF_DIR
peut également être défini dans conf/spark-env.sh
.
Les dernières versions d'EMR (testées sur 4.6.0) requièrent la configuration suivante:
val sc = new SparkContext(conf)
val hadoopConf = sc.hadoopConfiguration
hadoopConf.set("fs.s3.impl", "com.Amazon.ws.emr.hadoop.fs.EmrFileSystem")
hadoopConf.set("fs.s3.awsAccessKeyId", myAccessKey)
hadoopConf.set("fs.s3.awsSecretAccessKey", mySecretKey)
Bien que dans la plupart des cas, la configuration prête à l'emploi devrait fonctionner - c'est le cas si vous avez des informations d'identification S3 différentes de celles avec lesquelles vous avez lancé le cluster.
En Java, voici les lignes de code. Vous devez ajouter des creds AWS dans SparkContext uniquement et non pas SparkSession.
JavaSparkContext sc = new JavaSparkContext(spark.sparkContext());
sc.hadoopConfiguration().set("fs.s3a.access.key", AWS_KEY);
sc.hadoopConfiguration().set("fs.s3a.secret.key", AWS_SECRET_KEY);
En augmentant la réponse de @ nealmcb, le moyen le plus simple de le faire est de définir
HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
dans conf/spark-env.sh
ou exporter cette variable env dans ~/.bashrc
ou ~/.bash_profile
.
Cela fonctionnera tant que vous pourrez accéder à s3 via hadoop. Par exemple, si vous pouvez exécuter
hadoop fs -ls s3n://path/
hadoop peut alors voir le chemin s3.
Si hadoop ne peut pas voir le chemin, suivez les conseils contenus dans Comment accéder à S3/S3n à partir d’une installation Hadoop 2.6 locale?
cela fonctionne pour moi dans 1.4.1 Shell:
val conf = sc.getConf
conf.set("spark.hadoop.fs.s3.impl", "org.Apache.hadoop.fs.s3native.NativeS3FileSystem")
conf.set("spark.hadoop.fs.s3.awsAccessKeyId", <your access key>)
conf.set("spark.hadoop.fs.s3.awsSecretAccessKey", <your secret key>)
SparkHadoopUtil.get.conf.addResource(SparkHadoopUtil.get.newConfiguration(conf))
...
sqlContext.read.parquet("s3://...")