環境変数の利用

DBへの接続情報など環境変数から設定するようにしたいケースが発生しそうなので調査しました。
いずれもドライバプログラム内でしか利用できません。つまりworkerノード(リモート)で利用するためには一旦変数に格納してアプリケーションコード内で参照するような工夫が必要ですのでご注意ください。

方法1:initialization-actionsで自前スクリプトを実行する

initialization-actionsで自前のスクリプトを実行して、その中で環境変数を設定するというとても原始的な方法です。この方法だと変数の内容をファイルに記載して、GCSにアップロードしなくてはならないので正直使えないと思っています。

  1. まず、クラスター作成時にinitialization-actionsオプションで指定するスクリプト(initialize.sh)を実装する

    echo "export HOGE=xxx" | tee -a initialize.sh
  2. ドライバプログラム(main.py)を実装する

    import os
    import pyspark
    hoge = os.getenv('HOGE')
  3. 実装したファイルをGCSにアップロードする

    gsutil cp initialize.sh gs://hoge/
    gsutil cp main.py gs://hoge/
  4. クラスタを作成する

    • --initialization-actionsで作成したinitialize.shを指定している
      gcloud dataproc clusters create hoge-gluster --initialization-actions='gs://hoge/initialize.sh'
  5. ジョブを実行する

    gcloud dataproc jobs submit pyspark --cluster=hoge-gluster  gs://hoge/main.py

方法2:spark-env.shで環境変数を設定する(推奨)

--propertiesspark-env:HOGE=XXXのように指定しておくと、spark-env.shはその内容を読み込んで環境変数HOGE=XXXを設定してくれます。これが一番スタンダードな方法だと思います。

  1. ドライバプログラム(main.py)を実装する
    import pyspark
    import os
    sc = pyspark.SparkContext()
    hoge =  os.getenv('HOGE')
    :
  2. 実装したファイルをGCSにアップロードする
    gsutil cp main.py gs://hoge/
  3. クラスターを作成する
    • --propertiesオプションで、spark-envプレフィックスをつけて、環境変数を設定する
      gcloud dataproc clusters create hoge-gluster --properties="spark-env:HOGE=xxx,spark-env:FUGA=yyy"
  4. ジョブを実行する
    gcloud dataproc jobs submit pyspark --cluster=hoge-gluster  gs://hoge/main.py

方法3:spark-defaults.confに設定を追加する

こちらは環境変数ではないのですが、--propertiesspark:HOGE=XXXのように指定しておくと、spark-defaults.confにその内容が記載され、設定情報としてプログラム内から参照できます。

  1. ドライバプログラム(main.py)を実装する
    import pyspark
    sc = pyspark.SparkContext()
    hoge = sc.getConf().get('HOGE')
  2. 実装したファイルをGCSにアップロードする
    gsutil cp main.py gs://hoge/
  3. クラスターを作成する
    • --propertiesオプションで、sparkのexecutorEnvを指定している
      gcloud dataproc clusters create hoge-gluster --properties="spark:HOGE=xxx,spark:FUGA=yyy"
  4. ジョブを実行します
    gcloud dataproc jobs submit pyspark --cluster=hoge-gluster  gs://hoge/main.py

別フォルダのpythonファイルをimport

残念ながら別フォルダのpythonファイルをimportする方法はなさそうです。

hoge.py
models
┗fuga.py

のようなフォルダ構成で、hoge.pyでは、以下のようにでfuga.pyをimportするケースを試しました。

from models import fuga

これをDataProcで実行すると、以下のように ImportError: No module named modelsというエラーが発生します。

gcloud dataproc jobs submit pyspark \
  --cluster=hoge-cluster \
  --files='gs://hoge-bucket/models/fuga.py' \
  gs://hoge-bucket/hoge.py

> Traceback (most recent call last):
>   File "/tmp/987eqbkewqvf0uh9qet43/hoge.py", line 9, in <module>
>     from models import grants
> ImportError: No module named models

これは、結局--filesで指定したファイルは、元のフォルダ構成に関係なく実行ファイル(hoge.py)と同じテンポラリフォルダに展開されて実行されるためです。

なので

try:
    from models import fuga
except ModuleNotFoundError:
    import fuga

とすると、ローカルPC上でも、クラスタ上でもエラーは発生しなくなります。