【问题标题】:Cross account GCS access using Spark on Dataproc在 Dataproc 上使用 Spark 进行跨账户 GCS 访问
【发布时间】:2019-12-18 04:51:34
【问题描述】:

我正在尝试使用在账户 B 的 Dataproc 上运行的 Spark,将账户 A 的 GCS 中的数据提取到账户 B 的 BigQuery。

我尝试将GOOGLE_APPLICATION_CREDENTIALS 设置为服务帐户密钥文件,该文件允许访问帐户A 中的必要存储桶。但如果我启动spark-shell,我会收到以下错误。

Exception in thread "main" java.io.IOException: Error accessing Bucket dataproc-40222d04-2c40-42f9-a5de-413a123f949d-asia-south1

根据我的理解,设置环境变量就是将B账号的访问权限切换到A账号。

有没有办法同时拥有 Spark 中的访问权限,即对帐户 B 的默认访问权限和对帐户 A 的额外访问权限?

更新:我尝试使用Igor's Answer 的配置运行spark-shell,但错误仍然存​​在。这是我尝试过的命令和堆栈跟踪。

$ spark-shell --conf spark.hadoop.fs.gs.auth.service.account.json.keyfile=/home/shasank/watchful-origin-299914-fa29998bad08.json --jars gs://hadoop-lib/bigquery/bigquery-connector-hadoop2-latest.jar
Exception in thread "main" java.io.IOException: Error accessing Bucket dataproc-40999d04-2b99-99f9-a5de-999ad23f949d-asia-south1
  at com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageImpl.getBucket(GoogleCloudStorageImpl.java:1895)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageImpl.getItemInfo(GoogleCloudStorageImpl.java:1846)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageFileSystem.getFileInfoInternal(GoogleCloudStorageFileSystem.java:1125)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageFileSystem.getFileInfo(GoogleCloudStorageFileSystem.java:1116)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageFileSystem.exists(GoogleCloudStorageFileSystem.java:440)
  at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase.configureBuckets(GoogleHadoopFileSystemBase.java:1738)
  at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem.configureBuckets(GoogleHadoopFileSystem.java:76)
  at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase.configure(GoogleHadoopFileSystemBase.java:1659)
  at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase.initialize(GoogleHadoopFileSystemBase.java:683)
  at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase.initialize(GoogleHadoopFileSystemBase.java:646)
  at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:3242)
  at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:121)
  at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:3291)
  at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:3259)
  at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:470)
  at org.apache.spark.deploy.DependencyUtils$.org$apache$spark$deploy$DependencyUtils$$resolveGlobPath(DependencyUtils.scala:165)
  at org.apache.spark.deploy.DependencyUtils$$anonfun$resolveGlobPaths$2.apply(DependencyUtils.scala:146)
  at org.apache.spark.deploy.DependencyUtils$$anonfun$resolveGlobPaths$2.apply(DependencyUtils.scala:144)
  at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:241)
  at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:241)
  at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
  at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
  at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:241)
  at scala.collection.AbstractTraversable.flatMap(Traversable.scala:104)
  at org.apache.spark.deploy.DependencyUtils$.resolveGlobPaths(DependencyUtils.scala:144)
  at org.apache.spark.deploy.SparkSubmit$$anonfun$doPrepareSubmitEnvironment$3.apply(SparkSubmit.scala:403)
  at org.apache.spark.deploy.SparkSubmit$$anonfun$doPrepareSubmitEnvironment$3.apply(SparkSubmit.scala:403)
  at scala.Option.map(Option.scala:146)
  at org.apache.spark.deploy.SparkSubmit$.doPrepareSubmitEnvironment(SparkSubmit.scala:403)
  at org.apache.spark.deploy.SparkSubmit$.prepareSubmitEnvironment(SparkSubmit.scala:250)
  at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:171)
  at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:137)
  at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by:
com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.json.GoogleJsonResponseException:
  403 Forbidden {
    "code" : 403,
    "errors" : [ {
      "domain" : "global",
      "message" : "ingestor@watchful-origin-299914.iam.gserviceaccount.com does not have storage.buckets.get access to dataproc-40999d04-2b99-99f9-a5de-999ad23f949d-asia-south1.",
      "reason" : "forbidden" } ],
    "message" : "ingestor@watchful-origin-299914.iam.gserviceaccount.com does not have storage.buckets.get access to  dataproc-40999d04-2b99-99f9-a5de-999ad23f949d-asia-south1." }
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:150)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:401)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1097)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:499)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:432)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:549)
  at com.google.cloud.hadoop.repackaged.gcs.com.google.cloud.hadoop.gcsio.GoogleCloudStorageImpl.getBucket(GoogleCloudStorageImpl.java:1889)
  ... 32 more

【问题讨论】:

  • 您是否授权您的服务帐号访问您的存储桶?当您谈论“帐户”时,您能准确吗?您喜欢项目或服务帐户吗?
  • 是的,服务帐户被授权访问存储桶。 “帐户”是指“GCP 帐户”。更具体地说,账户 A 是我客户的 GCP 账户,账户 B 是我正在构建数据湖的 GCP 账户。
  • 哪个角色?对象阅读器或存储桶管理员?
  • 存储对象查看者角色。
  • 嗯,试试存储管理员。我的猜测如下:有时,库在获取对象之前会执行 bucket.list API 调用,不知道为什么,并且根据语言不同。如果你愿意,你可以创建一个只有bucket.list和bucket.get权限的自定义角色来降低权限

标签: apache-spark google-cloud-platform google-bigquery google-cloud-storage google-cloud-dataproc


【解决方案1】:

要实现这一点,您需要重新配置 GCS 和 BQ 连接器以使用不同的服务帐户进行身份验证,默认情况下它们都使用 GCE VM 服务帐户。

为此,请参阅 GCS 连接器配置手册中的Method 2

同样的配置适用于 Hadoop BQ 连接器,但您需要将属性名称中的 fs.gs. 前缀替换为 bq.mapred. 前缀:

spark.hadoop.fs.gs.auth.service.account.json.keyfile=/path/to/local/gcs/key/file.json
spark.hadoop.bq.mapred.auth.service.account.json.keyfile=/path/to/local/bq/key/file.json

更新:

要在 GCS 连接器初始化期间禁用 Dataproc 暂存存储桶检查,您需要使用最新的 GCS 连接器版本(目前为 1.9.17)并将 GCS 连接器系统存储桶属性设置为空字符串:

spark.hadoop.fs.gs.system.bucket=

请注意,此系统存储桶功能已在即将推出的 GCS 连接器 2.0 中删除,因此这不会成为问题。

【讨论】:

  • 我试过这个,但是当我为账户 A 使用 GCS 密钥文件时,DataProc 无法访问它自己的 GCS(我相信它用来存储临时文件)。所以它会导致我最初发布的相同错误。我认为它不允许我在 spark.hadoop.fs.gs.auth.service.account.json.keyfile 中指定 2 个密钥文件,不过我会尝试。
  • 您需要一个在 2 个项目中具有权限的服务帐户。
  • 此外,设置 GOOGLE_APPLICATION_CREDENTIALS 可能会产生意想不到的后果,因为它不仅适用于 GCS 和 BQ 连接器,还适用于所有 Google API 客户端库。
  • 当它抱怨访问暂存桶时,您可以发布完整的堆栈跟踪吗?
  • 在这种情况下,您需要创建一个可以同时访问您想要的 GCS 和 BQ 的服务帐户,因为目前不支持您尝试执行的操作
猜你喜欢
  • 2020-05-17
  • 1970-01-01
  • 2021-06-21
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
相关资源
最近更新 更多