MWAA での環境変数設定パターン


# 設定パターン

網羅的ではないですが、複数あります。以下の5つを試したり紹介だけだったりしていきたいと思います。

* ①Airflow UIで設定(GUI)
* ②DAG内で設定
* ③airflow.cfgで設定(マネコン & CLI)
* ④airflow cliで設定
* ⑤Secrets Managerに全振り

## ①Airflow UIで設定

Airflow UIでの環境変数設定を見ていきます。Airflow UIでのGUI操作になります。

#### 手順

Airflow UIを開き、上部の[Admin]にカーソルを当て、[Variables]をクリック
左下の[+]ボタンをクリックします

![スクリーンショット 0003-11-26 7.34.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/cac44046-3178-9eab-06fe-11c376c54c00.png)

Key/Valueの形式で入力します。ここではfoo/barを入れました。左下の[Save]をクリックします。

![スクリーンショット 0003-11-26 7.34.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/c1c5b11a-9ac2-9729-2502-7d5fc6a94a22.png)

foo/barの環境変数が出来ました。

![スクリーンショット 0003-11-26 7.35.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/a5b29b8d-0804-58c9-273e-b3df6e7ec514.png)

エクスポート/インポートも出来ます。作成した環境変数にチェックを入れエクスポートします

![スクリーンショット 0003-11-26 7.35.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/4b7ed52e-547f-9449-133c-a0756e0aeca2.png)

エクスポートしたファイルの中身はこんな感じ

```json:variables.json
{
    "foo": "bar"
}
```

環境変数を画面で削除し、エクスポートしたファイルをインポートします。

![スクリーンショット 0003-11-26 7.36.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/9492d924-e167-77b2-8934-a80fe75edb95.png)

元のfoo/barが戻ります

![スクリーンショット 0003-11-26 7.43.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/5ba55caf-2ca7-43a1-aebb-2427702f378f.png)

#### まとめ

GUIでよければ一番手軽です。エクスポート・インポートも出来るし。GUI操作なので自動化は出来ない

## ②DAG内で設定

環境変数設定のDAGを作っちゃうパターン。

#### 手順

環境変数を書いたJSONファイルを用意します。

```json:variables.json
{
    "red": "liver",
    "white": "real"
}
```

DAGファイルを作成します。

```python:setvar.py
import airflow
from airflow.models import DAG
from airflow.operators.python import PythonOperator
import os
from airflow.models import Variable
import json

args = {
    "owner": "airflow",
    "start_date": airflow.utils.dates.days_ago(1),
    "provide_context": False,
    "email_on_failure": True,
    "email_on_retry": True,
    "retries":1,
    "retry_delay":120
    }

def setvar_modules():
    print("Starting here")
    with open('/usr/local/airflow/dags/variables.json') as f:
        data = json.load(f)
    for key in data:
        print(key, '->', data[key])
        variable = Variable.set(key, data[key])
    print("Debugging here")
    for key in data:
        print(key, '->', data[key])
        variable = Variable.get(key)
with DAG(
    dag_id="set_variables_job",
    description="set variables DAG",
    default_args=args,
    schedule_interval="*/60 * * * *",
    catchup=False,
    tags=['setenv']
) as dag:
    t1 = PythonOperator(
        task_id='setvar_task',
        python_callable=setvar_modules,
        dag=dag
        )

    t1
```

JSONファイルとDAGファイルの2つをS3のDAGフォルダにアップします。

数分するとAirflow UIにset_variables_jobのDAGが表示されます。

![スクリーンショット 0003-11-26 8.34.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/2a550415-a46b-741b-c02d-ef6a384bde44.png)

DAGは最初Pause状態なので、DAG名の左のつまみをクリックしUnpauseします。そうすると自動で実行されます。
次にDAG名をクリックして詳細を確認します。

![スクリーンショット 0003-11-26 8.36.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/0d5ccee3-379d-4ef9-0c0c-b838a0d48b55.png)

[Graph View]をクリックし、真ん中の[setvar_task]をクリック

![スクリーンショット 0003-11-26 8.38.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/faf2d5b4-4bca-51c4-0c83-95e0d07ef5c4.png)

この画面が出るので[Log]をクリック

![スクリーンショット 0003-11-26 8.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/e2002725-cc77-a39a-4039-6bf88a73488b.png)

ログの表示から環境変数が設定されてることが分かります。variable.getで確認もしてるのでsetした変数がgetできてます

![スクリーンショット 0003-11-26 8.48.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/14af884c-64f4-1a47-7d8a-d1952c1f5828.png)

Admin->Variablesで確認
設定した環境変数が表示されています

![スクリーンショット 0003-11-26 8.40.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/19d0c543-4087-fb02-f8b8-f43171b01b5d.png)

#### まとめ

環境変数セットアップ用のDAGを作るパターンは良いんじゃないかと思います。
環境変数セットのロジックを切り出せてるので、環境変数の設定や修正時は環境変数のJSONとDAGだけ修正すれば良くて、ビジネスロジック側に手を入れなくて済みます。
本来のDAGではないDAGが作られるのがどうかな？とは思いますが、DAGであるので逆に管理運用はしやすいと思う。

## ③airflow.cfgで設定(マネコン & CLI)

airflow.cfgにカスタムな環境変数を書けます。MWAAでそれを行うやり方。

#### GUI手順

MWAAの環境の編集で、Airflow設定オプションを追加しましす。ここで入れた値はairflow.cfgに反映されます。
入力した値は、custom.envval/helloworld です

![スクリーンショット 0003-11-26 9.08.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/20e471b5-f058-12af-6413-9afc769eaefd.png)

確認のためカスタム環境変数を表示するDAGを作ってS3にアップします。
確認用のDAGなので本来は不要なDAGです。

```python:getvar.py
import boto3
import airflow
from airflow.models import DAG
from airflow.operators.python import PythonOperator
from airflow.providers.amazon.aws.operators.athena import AWSAthenaOperator
from airflow.utils.task_group import TaskGroup
import os

args = {
    "owner": "airflow",
    "start_date": airflow.utils.dates.days_ago(1),
    "provide_context": False,
    "email_on_failure": True,
    "email_on_retry": True,
    "retries":1,
    "retry_delay":120
    }

def getvar_module():
    words = os.getenv("AIRFLOW__CUSTOM__ENVVAL")
    print("Debugging here")
    print (words)

with DAG(
    dag_id="get_variables_job2",
    description="get variables from airflow.cfg DAG",
    default_args=args,
    schedule_interval="*/60 * * * *",
    catchup=False,
    tags=['getenv']
) as dag:
    t1 = PythonOperator(task_id="get_variables_task", python_callable=getvar_module)

    t1
```

Airflow UIでDAGをunpauseして実行します。
DAG名をクリックします

![スクリーンショット 0003-11-26 9.16.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/2631f3f1-c4f4-11ba-7e49-499f3444fee9.png)

[Graph View]で表示します

![スクリーンショット 0003-11-26 9.16.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/d16e18c7-fcd3-0c3d-7107-672f35c5cf1b.png)

ログを確認します。airflow.cfgで設定したカスタム環境変数のhelloworldが表示されてます

![スクリーンショット 0003-11-26 9.17.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/25bc32f6-a963-5009-1ca7-53d4e8032182.png)


#### CLI手順

今回は試しませんが、MWAAの環境作成時に"airflow-configuration-options"で環境変数を設定できそうです。

```bash:
aws mwaa create-environment --airflow-configuration-options {"custom.envval":"helloworld"}
```

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/mwaa/create-environment.html

#### まとめ

DAGに環境変数の記述をしないという意味では一番キレイでシンプルだと思います。
ただ、Airflow UIのVariablesに表示されないため可視性は低めかもしれません。見通しがいいという意味だとVariablesに表示されるといいなと思います。でも、どのみちVariablesを直接操作しないならそこまでデメリットではないかもです
あと、airflow.cfgに書く場合は「AIRFLOW__CUSTOM__ENVVAL」みたいな書式に従う必要があります。
それと、最大のデメリットがairflow.cfgの修正にはMWAA側の反映にかなり時間が掛ります。手元では10分くらい掛りますた、公式Docには「数分かかる」とあります。よって、時々レベルの頻度で更新が入ったり、更新してすぐに試したい環境変数はなるべくairflow.cfgと切り離した方がいいと思います。

## ④Airflow CLI

2.0.2からできるっぽいですね。サンプルコードもありました

https://docs.aws.amazon.com/ja_jp/mwaa/latest/userguide/airflow-cli-command-reference.html#airflow-unsupported-cli-commands

Airflowの公式Doc的にはこちらのコマンドです

```bash:
airflow variables get [-h] [-d VAL] [-j] [-v] key
```

https://airflow.apache.org/docs/apache-airflow/stable/cli-and-env-variables-ref.html

#### まとめ

試してないですmm
試してないのに感想ですが、CLIなのでCLI実行環境が必要なので、手頃なコンピューティングがあれば良いいかなと。
Airflowとは別な環境で管理する形になるので、実行環境といい感じに疎結合になったバッチサーバーみたいな基盤があれば良さそう
AirflowはAirflowでまとめたいなら前述の手段がいいかも。Airflowでまとめなくてもいいのだけど。

## ⑤Secrets Manager全振り

環境変数の保存先にSecrets Managerも使えます。本来は秘匿性が高いDB接続情報(ID/Passwordなど)を保存することに使うAWSのナイスIntegrationですが、環境変数の保存先にも使えます

※注意点は、前述のvariables.getではMWAA(Airflow)のメタストア(MWAA内部のRDS)に保存された値を取得しますが、SecretsManagerを保存先にした場合は、variables.getでSecretsManagerに保存された値を取得します。キーが被っている場合はSecretsManagerが優先されそうです。
英語ですがこちらの[ブログ](https://dev-clone.nuxtjs.app/094459/773118)にこの辺含めて、MWAA+SecretsManagerをすごく丁寧に検証してるので是非ご確認ください。

https://docs.aws.amazon.com/ja_jp/mwaa/latest/userguide/connections-secrets-manager.html#connections-sm-createsecret-variables

MWAAでSecrets Managerを使う設定は[こちら](https://docs.aws.amazon.com/ja_jp/mwaa/latest/userguide/connections-secrets-manager.html)

サンプルコードは[こちら](https://docs.aws.amazon.com/ja_jp/mwaa/latest/userguide/samples-secrets-manager-var.html)ですが、variable.getを使う点では②とほとんど同じ感じです。
variable.setはSecrets Managerへの設定操作ということになりますね。

#### まとめ

試してないですmm
環境変数を入れ先としてはAWSらしい疎結合で、可視性と操作性もいいと思います。Secretでない値を入れるのに若干違和感ありますが、公式ドキュメントにも環境変数の設定手順とあるので利用用途してはアリだと思います。
デメリットとしては、Secrets Manager側にも若干ですがコストがかかる点があるかもしれません。
あと、Airflowで完結したい場合は、別サービスであるSecrets Managerが登場してきてしまいます。ただ、いい感じの結合度なのでmake senseだと思います。

## 全体まとめ

個人的には「⑤Secrets Manager全振り」でいいと思います(試してないのに一番お勧めmm)。「①環境変数設定DAGにするパターン」もユースケースによってはマッチしそうです。DAGに慣れてれば扱いやすいしMWAAで完結できますね。ほとんど変更がない環境変数であれば「②airflow.cfgで設定」も良いと思います。

# 参考リンク

* [Airflow 公式Doc: Managing Variables](https://airflow.apache.org/docs/apache-airflow/2.0.2/howto/variable.html)
* [AWS CLI: MWAA CLI](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/mwaa/create-environment.html)
* [MWAA Secrets Manager Integration](https://docs.aws.amazon.com/ja_jp/mwaa/latest/userguide/connections-secrets-manager.html)
* [Airflow CLI: Variables set](https://airflow.apache.org/docs/apache-airflow/stable/cli-and-env-variables-ref.html)
* [MWAAでのAirflow CLI](https://docs.aws.amazon.com/ja_jp/mwaa/latest/userguide/airflow-cli-command-reference.html#airflow-unsupported-cli-commands)