适用于Dataproc的Spark的BigQuery连接器-无法使用服务帐户密钥文件进行身份验证

时间:2018-11-07 13:59:59

标签: google-bigquery google-cloud-dataproc

我遵循Use the BigQuery connector with Spark来从公开可用的数据集中成功获取数据。现在,我需要访问一个由我们的客户之一拥有的bigquery数据集,并为其提供了服务帐户密钥文件(我知道该服务帐户密钥文件是有效的,因为我可以使用{{{ 3}})。

我遵循了Igor Dvorzhak推荐的Google BigQuery library for Python

  

要使用服务帐户密钥文件授权,您需要将mapred.bq.auth.service.account.enable属性设置为true,并使用mapred.bq.auth.service.account.json.keyfile属性将BigQuery连接器指向服务帐户json密钥文件

像这样:

from pyspark.sql import SparkSession
from datetime import datetime

spark = SparkSession.builder.appName("SparkSessionBQExample").enableHiveSupport().getOrCreate()

bucket = spark._jsc.hadoopConfiguration().get('fs.gs.system.bucket')
project = spark._jsc.hadoopConfiguration().get('fs.gs.project.id')
input_directory =     'gs://{}/hadoop/tmp/bigquery/pyspark_input{}'.format(bucket, datetime.now().strftime("%Y%m%d%H%M%S"))

project_id = 'clientproject'#'publicdata'
dataset_id = 'clientdataset'#samples'
table_id = 'clienttable'#'shakespeare'
conf = {
    # Input Parameters.
    'mapred.bq.project.id': project,
    'mapred.bq.gcs.bucket': bucket,
    'mapred.bq.temp.gcs.path': input_directory,
    'mapred.bq.input.project.id': project_id,
    'mapred.bq.input.dataset.id': dataset_id,
    'mapred.bq.input.table.id': table_id,
    'mapred.bq.auth.service.account.enable': 'true'
}

# Load data in from BigQuery.
table_data = spark.sparkContext.newAPIHadoopRDD(
    'com.google.cloud.hadoop.io.bigquery.JsonTextBigQueryInputFormat',
    'org.apache.hadoop.io.LongWritable',
    'com.google.gson.JsonObject',
    conf=conf)

print ('row tally={}'.format(table_data.toDF().count()))

我已将服务帐户密钥文件放置在群集的主节点和所有工作节点上的/tmp/keyfile.json上,然后我像这样提交作业:

gcloud dataproc jobs submit pyspark \
    ./bq_pyspark.py  \
    --cluster $CLUSTER \
    --region $REGION \
    --properties=spark.hadoop.mapred.bq.auth.service.account.json.keyfile=/tmp/keyfile.json

我也尝试过:

gcloud dataproc jobs submit pyspark \
    ./bq_pyspark.py  \
    --cluster $CLUSTER \
    --region $REGION \
    --properties=spark.hadoop.mapred.bq.auth.service.account.json.keyfile=/tmp/keyfile.json,spark.hadoop.mapred.bq.auth.service.account.enable=true

以下是作业输出的相关部分:

  

Bigquery连接器版本0.10.7-hadoop2
  18/11/07 13:36:47 INFO com.google.cloud.hadoop.io.bigquery.BigQueryFactory:使用默认凭据创建BigQuery。
  18/11/07 13:36:47 INFO com.google.cloud.hadoop.io.bigquery.BigQueryFactory:使用给定的凭据创建BigQuery。
  18/11/07 13:36:47 INFO com.google.cloud.hadoop.io.bigquery.BigQueryConfiguration:使用工作路径:'gs:// dataproc-9e5dc592-1a35-42e6-9dd6-5f9dd9c8df87-europe-west1 / hadoop / tmp / bigquery / pyspark_input20181107133646'
  追溯(最近一次通话):
    
中的文件“ /tmp/b6973a26c76d4069a86806dfbd2d7d0f/bq_pyspark.py”,第30行       conf = conf)
    newAPIHadoopRDD中的第702行的文件“ /usr/lib/spark/python/lib/pyspark.zip/pyspark/context.py”
    调用
中的文件“ /usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/java_gateway.py”,行1133     deco文件中的文件“ /usr/lib/spark/python/lib/pyspark.zip/pyspark/sql/utils.py”,第63行,
    在get_return_value
中的第319行中的文件“ /usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/protocol.py”   py4j.protocol.Py4JJavaError:调用z:org.apache.spark.api.python.PythonRDD.newAPIHadoopRDD时发生错误。
  :com.google.api.client.googleapis.json.GoogleJsonResponseException:禁止403
  {
    “代码”:403,
    “错误”:[{
      “ domain”:“ global”,
      “ message”:“访问被拒绝:表clientproject:clientdatatset.clienttable:用户mydataprocserviceaccount@myproject.iam.gserviceaccount.com没有bigquery.tables.get表clientproject:clientdatatset.clienttable的权限。”,
      “ reason”:“ accessDenied”
    }],
    “ message”:“访问被拒绝:表clientproject:clientdatatset.clienttable:用户mydataprocserviceaccount@myproject.iam.gserviceaccount.com没有对表clientproject:clientdatatset.clienttable的bigquery.tables.get权限。”
  }

  

18/11/07 13:36:47信息com.google.cloud.hadoop.io.bigquery.BigQueryFactory:使用默认凭据创建BigQuery。

可能表明我没有正确传递服务帐户密钥文件中的凭据,所以我想我误解了Igor所说的话(或缺少某些信息)。

如果有人能让我知道我要去哪里错了,我将非常感激。

更新... 我试图通过代码而不是通过命令行提供所需的auth配置:

conf = {
    # Input Parameters.
    'mapred.bq.project.id': project,
    'mapred.bq.gcs.bucket': bucket,
    'mapred.bq.temp.gcs.path': input_directory,
    'mapred.bq.input.project.id': project_id,
    'mapred.bq.input.dataset.id': dataset_id,
    'mapred.bq.input.table.id': table_id,
    'mapred.bq.auth.service.account.enable': 'true',
    'mapred.bq.auth.service.account.keyfile': '/tmp/keyfile.json',
    'mapred.bq.auth.service.account.email': 'username@clientproject.iam.gserviceaccount.com'
}

这次我遇到了另一个错误:

  

18/11/07 16:44:21 INFO com.google.cloud.hadoop.io.bigquery.BigQueryFactory:使用默认凭据创建BigQuery。
  追溯(最近一次通话):
    在
中的文件“ /tmp/cb5cbb16d59945dd926cab2c1f2f5524/bq_pyspark.py”中,第39行       conf = conf)
    newAPIHadoopRDD中的第702行的文件“ /usr/lib/spark/python/lib/pyspark.zip/pyspark/context.py”
    调用
中的文件“ /usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/java_gateway.py”,行1133     deco文件中的文件“ /usr/lib/spark/python/lib/pyspark.zip/pyspark/sql/utils.py”,第63行,
    文件“ /usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/protocol.py”,行319,位于get_return_value中   py4j.protocol.Py4JJavaError:调用z:org.apache.spark.api.python.PythonRDD.newAPIHadoopRDD时发生错误。
  :java.io.IOException:toDerInputStream拒绝标记类型123
          在sun.security.util.DerValue.toDerInputStream(DerValue.java:881)
          在sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1939)
          在java.security.KeyStore.load(KeyStore.java:1445)
          在com.google.api.client.util.SecurityUtils.loadKeyStore(SecurityUtils.java:82)
          在com.google.api.client.util.SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.java:115)
          com.google.api.client.googleapis.auth.oauth2.GoogleCredential $ Builder.setServiceAccountPrivateKeyFromP12File(GoogleCredential.java:670)
          在com.google.cloud.hadoop.util.CredentialFactory.getCredentialFromPrivateKeyServiceAccount(CredentialFactory.java:251)
          在com.google.cloud.hadoop.util.CredentialConfiguration.getCredential(CredentialConfiguration.java:100)
          在com.google.cloud.hadoop.io.bigquery.BigQueryFactory.createBigQueryCredential(BigQueryFactory.java:95)
          在com.google.cloud.hadoop.io.bigquery.BigQueryFactory.getBigQuery(BigQueryFactory.java:115)
          com.google.cloud.hadoop.io.bigquery.BigQueryFactory.getBigQueryHelper(BigQueryFactory.java:103)

我搜索了“ toDerInputStream拒绝标记类型123”,这导致我进入here,这表明我需要使用P12文件进行身份验证。这与在调用堆栈中提到sun.security.pkcs12.PKCS12KeyStore是一致的。因此,我认为我需要一个P12文件(也称为PKCS#12格式文件)而不是.json文件,这意味着我需要回到客户端进行询问-从经验来看,我认为可能需要一些时间获取P12文件。如果有的话,我会报告。

更新2 ...在Igor的帮助下解决了。我错误地指定了mapred.bq.auth.service.account.keyfile,它必须为mapred.bq.auth.service.account.json.keyfile。因此,相关的代码部分变为:

conf = {
    # Input Parameters.
    'mapred.bq.project.id': project,
    'mapred.bq.gcs.bucket': bucket,
    'mapred.bq.temp.gcs.path': input_directory,
    'mapred.bq.input.project.id': project_id,
    'mapred.bq.input.dataset.id': dataset_id,
    'mapred.bq.input.table.id': table_id,
    'mapred.bq.auth.service.account.enable': 'true',
    'mapred.bq.auth.service.account.json.keyfile': '/tmp/keyfile.json'
}
table_data = spark.sparkContext.newAPIHadoopRDD(
    'com.google.cloud.hadoop.io.bigquery.JsonTextBigQueryInputFormat',
    'org.apache.hadoop.io.LongWritable',
    'com.google.gson.JsonObject',
    conf=conf)

和submit命令很简单

gcloud dataproc jobs submit pyspark \
    ./bq_pyspark.py  \
    --cluster $CLUSTER \
    --region $REGION

现在可以正常工作了,我可以从spark-on-dataproc访问biquery中的数据,并使用服务帐户json密钥文件进行身份验证。谢谢伊戈尔。

1 个答案:

答案 0 :(得分:2)

问题似乎在这里:

  

警告:忽略非火花配置属性:mapred.bq.auth.service.account.json.keyfile = / tmp / keyfile.json

要解决此问题,您should在Spark中使用spark.hadoop前缀设置Hadoop属性:

gcloud dataproc jobs submit pyspark ./bq_pyspark.py \
  --cluster $CLUSTER --region $REGION \
  --properties=spark.hadoop.mapred.bq.auth.service.account.json.keyfile=/tmp/keyfile.json