Spark 和 Amazon S3 未在执行程序中设置凭证



我正在做一个从 Amazon 读取和写入的 Spark 程序 S3.My 问题是如果我在本地模式下执行(--master local[6]),它可以工作,但如果我在集群中执行(在其他机器上),我的凭据出现错误:

org.apache.spark.SparkException: Job aborted due to stage failure: Task 2 in stage 1.0 failed 4 times, most recent failure: Lost task 2.3 in stage 1.0 (TID 33, mmdev02.stratio.com): com.amazonaws.AmazonClientException: Unable to load AWS credentials from any provider in the chain
at com.amazonaws.auth.AWSCredentialsProviderChain.getCredentials(AWSCredentialsProviderChain.java:117)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:3521)
at com.amazonaws.services.s3.AmazonS3Client.headBucket(AmazonS3Client.java:1031)
at com.amazonaws.services.s3.AmazonS3Client.doesBucketExist(AmazonS3Client.java:994)
at org.apache.hadoop.fs.s3a.S3AFileSystem.initialize(S3AFileSystem.java:297)
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2596)
at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:91)
at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2630)
at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2612)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:370)
at org.apache.hadoop.fs.Path.getFileSystem(Path.java:296)
at org.apache.parquet.hadoop.ParquetFileReader.readFooter(ParquetFileReader.java:384)
at org.apache.parquet.hadoop.ParquetRecordReader.initializeInternalReader(ParquetRecordReader.java:157)
at org.apache.parquet.hadoop.ParquetRecordReader.initialize(ParquetRecordReader.java:140)
at org.apache.spark.rdd.SqlNewHadoopRDD$$anon$1.<init>(SqlNewHadoopRDD.scala:155)
at org.apache.spark.rdd.SqlNewHadoopRDD.compute(SqlNewHadoopRDD.scala:120)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:300)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:264)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:300)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:264)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:300)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:264)
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:73)
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:41)
at org.apache.spark.scheduler.Task.run(Task.scala:88)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:214)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

原因:com.amazonaws.AmazonClient异常:无法从链中的任何提供商加载 AWS 凭证

我的代码如下:

val conf = new SparkConf().setAppName("BackupS3")

val sc = SparkContext.getOrCreate(conf)
sc.hadoopConfiguration.set("fs.s3a.access.key", accessKeyId)
sc.hadoopConfiguration.set("fs.s3a.secret.key", secretKey)
sc.hadoopConfiguration.set("fs.s3a.endpoint", "s3-" + region + ".amazonaws.com")
sc.hadoopConfiguration.set("com.amazonaws.services.s3.enableV4", "true")
sc.hadoopConfiguration.set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
sc.hadoopConfiguration.set("fs.s3a.buffer.dir", "/var/tmp/spark")
System.setProperty(SDKGlobalConfiguration.ENABLE_S3_SIGV4_SYSTEM_PROPERTY, "true");
System.setProperty("com.amazonaws.services.s3.enableV4", "true")

我可以写入 Amazon S3,但无法读取!当我进行 spark-submit 时,我还必须发送一些属性,因为我所在的地区是法兰克福,我必须启用 V4:

--conf spark.executor.extraJavaOptions=-Dcom.amazonaws.services.s3.enableV4=true

我也尝试以这种方式传递凭据。如果我把它们放在hdfs站点中.xml在每台机器上它都可以工作。

我的问题是,我如何从代码中做到这一点?为什么执行程序没有得到我从代码中传递给它们的配置?

我正在使用Spark 1.5.2,hadoop-aws 2.7.1和aws-java-sdk 1.7.4。

谢谢

  • 不要把秘密放在钥匙上,这会导致机密丢失
  • 如果您在 EC2 中运行,您的密钥将自动从 IAM 功能中获取;客户端会向魔术 Web 服务器询问会话密钥。
  • 。这意味着:可能是Spark的自动凭据传播妨碍了。在提交作品之前取消设置您的AWS_环境变量。

如果在代码中显式设置这些属性,则这些值将仅对驱动程序进程可见。 执行者将没有机会获取这些凭据。

如果您在实际的配置文件中设置了它们,例如core-site.xml,它们将传播。

代码将在本地模式下工作,因为所有操作都在单个进程中发生。

为什么它适用于小文件但不适用于大文件的集群 (*):该代码还可以适用于未分区的文件,其中读取操作在驱动程序中执行,然后将分区广播给执行程序。 在执行程序读取单个分区的分区文件上,不会在执行程序上设置凭据,因此会失败。

最好使用标准机制来传递凭证,或者更好的是,按照 EricJ 的答案建议在集群中使用 EC2 角色和 IAM 策略。 默认情况下,如果您不提供凭证,EMRFS 将通过 EC2 实例元数据服务查找临时凭证。

(*) 我自己仍在学习这个,随着我了解更多信息,我可能需要修改这个答案

相关内容

最新更新