Ошибка подключения к BigQuery из Dataproc с помощью Datalab с использованием коннектора BigQuery Spark (Ошибка при получении токена доступа с сервера метаданных в)

У меня есть таблица BigQuery, кластер Dataproc (с Datalab), и я следую этому руководству: https://cloud.google.com/dataproc/docs/tutorials/bigquery-connector-spark-example

bucket = spark._jsc.hadoopConfiguration().get("fs.gs.system.bucket")
project = spark._jsc.hadoopConfiguration().get("fs.gs.project.id")

# Set an input directory for reading data from Bigquery.
todays_date = datetime.strftime(datetime.today(), "%Y-%m-%d-%H-%M-%S")
input_directory = "gs://{}/tmp/bigquery-{}".format(bucket, todays_date)

# Set the configuration for importing data from BigQuery.
# Specifically, make sure to set the project ID and bucket for Cloud Dataproc,
# and the project ID, dataset, and table names for BigQuery.

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,
    'mapred.bq.input.dataset.id': 'my-test-dataset',
    'mapred.bq.input.table.id': 'test-table'
}

# Read the data from BigQuery into Spark as an RDD.
table_data = spark.sparkContext.newAPIHadoopRDD(
    "com.google.cloud.hadoop.io.bigquery.JsonTextBigQueryInputFormat",
    "org.apache.hadoop.io.LongWritable",
    "com.google.gson.JsonObject",
    conf=conf)

Скрипт работает нормально, когда я пытаюсь подключиться к общедоступным наборам данных. Однако, когда я пытаюсь подключиться к моему личному набору данных, я получаю следующую ошибку:

Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.newAPIHadoopRDD.
: java.io.IOException: Error getting access token from metadata server at: http://metadata/computeMetadata/v1/instance/service-accounts/default/token
    at com.google.cloud.hadoop.util.CredentialFactory.getCredentialFromMetadataServiceAccount(CredentialFactory.java:210)
    at com.google.cloud.hadoop.util.CredentialConfiguration.getCredential(CredentialConfiguration.java:75)
    at com.google.cloud.hadoop.io.bigquery.BigQueryFactory.createBigQueryCredential(BigQueryFactory.java:82)
    at com.google.cloud.hadoop.io.bigquery.BigQueryFactory.getBigQuery(BigQueryFactory.java:102)
    at com.google.cloud.hadoop.io.bigquery.BigQueryFactory.getBigQueryHelper(BigQueryFactory.java:90)
    at com.google.cloud.hadoop.io.bigquery.AbstractBigQueryInputFormat.getBigQueryHelper(AbstractBigQueryInputFormat.java:357)
    at com.google.cloud.hadoop.io.bigquery.AbstractBigQueryInputFormat.getSplits(AbstractBigQueryInputFormat.java:108)
    at org.apache.spark.rdd.NewHadoopRDD.getPartitions(NewHadoopRDD.scala:125)
    at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:252)
    at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:250)
    at scala.Option.getOrElse(Option.scala:121)
    at org.apache.spark.rdd.RDD.partitions(RDD.scala:250)
    at org.apache.spark.rdd.MapPartitionsRDD.getPartitions(MapPartitionsRDD.scala:35)
    at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:252)
    at org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:250)
    at scala.Option.getOrElse(Option.scala:121)
    at org.apache.spark.rdd.RDD.partitions(RDD.scala:250)
    at org.apache.spark.rdd.RDD$$anonfun$take$1.apply(RDD.scala:1333)
    at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:151)
    at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:112)
    at org.apache.spark.rdd.RDD.withScope(RDD.scala:362)
    at org.apache.spark.rdd.RDD.take(RDD.scala:1327)
    at org.apache.spark.api.python.SerDeUtil$.pairRDDToPython(SerDeUtil.scala:203)
    at org.apache.spark.api.python.PythonRDD$.newAPIHadoopRDD(PythonRDD.scala:587)
    at org.apache.spark.api.python.PythonRDD.newAPIHadoopRDD(PythonRDD.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
    at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
    at py4j.Gateway.invoke(Gateway.java:280)
    at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
    at py4j.commands.CallCommand.execute(CallCommand.java:79)
    at py4j.GatewayConnection.run(GatewayConnection.java:214)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.UnknownHostException: metadata
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
    at sun.net.www.http.HttpClient.<init>(HttpClient.java:242)
    at sun.net.www.http.HttpClient.New(HttpClient.java:339)
    at sun.net.www.http.HttpClient.New(HttpClient.java:357)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1220)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1156)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1050)
    at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:984)
    at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:93)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:972)
    at com.google.cloud.hadoop.util.CredentialFactory$ComputeCredentialWithRetry.executeRefreshToken(CredentialFactory.java:159)
    at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
    at com.google.cloud.hadoop.util.CredentialFactory.getCredentialFromMetadataServiceAccount(CredentialFactory.java:208)
    ... 35 more

Некоторая дополнительная информация:

  1. Я использую python (pySpark) через Datalab (который был инициирован через https://github.com/GoogleCloudPlatform/dataproc-initialization-actions/tree/master/datalab)
  2. Данные BigQuery по США, кластер Dataproc по ЕС
  3. Изображение Dataproc является самым последним (1.2)
  4. Кластер Dataproc был настроен для доступа к API в масштабах Google.

1 ответ

Согласно сообщению об ошибке, которое вы получаете (Error getting access token from metadata server at: http://metadata/computeMetadata/v1/instance/service-accounts/default/token [...] Caused by: java.net.UnknownHostException: metadata), похоже, ошибка в учетной записи службы, которая не может правильно получить токен доступа.

Чтобы упростить сценарий использования, я бы предложил начать с сужения продуктов, которые вы используете (поскольку сбой может происходить на разных этапах). Для этого я предлагаю вам запустить код PySpark непосредственно из кластера Dataproc, который у вас уже запущен, как объяснено в документации:

  1. Перейдите в меню Dataproc > Clusters в консоли GCP.
  2. Зайдите в используемый вами кластер и перейдите на вкладку "Экземпляры виртуальной машины".
  3. SSH в главный узел, нажав на кнопку "SSH" рядом с его именем.
  4. Создать скрипт words.py содержащий код PySpark, который вы хотите запустить.
  5. Запустите скрипт с помощью команды spark-submit words.py,

Как только вы это сделаете, проверьте, если вы получаете то же сообщение об ошибке. Если вы это сделаете, проблема должна быть на стороне Dataproc / BigQuery. Если вы этого не сделаете, скорее всего, он находится в Даталабе. Я предполагаю, что вы получите то же сообщение об ошибке, которое выглядит как проблема с учетными данными.

Как только вы (возможно) определили, в чем заключается проблема, посмотрите, какую учетную запись службы вы используете, выполнив следующую команду в терминале, когда у вас есть SSHed в главный узел в вашем кластере:

gcloud auth list

Также убедитесь, что переменная окружения GOOGLE_APPLICATION_CREDENTIALS пусто, выполнив команду ниже. Если он пуст, экземпляр виртуальной машины, на котором работает узел, будет использовать учетную запись службы по умолчанию для GCE (которая должна быть той, которую вы получили при запуске). gcloud auth list, поскольку Dataproc работает над экземплярами GCE). Если он не пустой, он будет использовать файл учетных данных, на который указывает эта переменная среды. Это вариант реализации, использовать ли учетные данные по умолчанию или пользовательские.

echo $GOOGLE_APPLICATION_CREDENTIALS

Как только вы узнаете, какая учетная запись службы используется, перейдите на вкладку IAM в консоли и проверьте, имеет ли эта учетная запись службы нужные роли и разрешения для доступа к BigQuery.

Я предполагаю, что проблема может быть связана с используемой учетной записью службы, и, вероятно, GOOGLE_APPLICATION_CREDENTIALS указывает на неправильное местоположение, поэтому вам следует начать с проверки правильности конфигурации аутентификации; и чтобы сделать это, я бы запустил код прямо из главного узла, чтобы упростить сценарий использования и уменьшить количество задействованных компонентов.

Другие вопросы по тегам