AirFlow:在 AirFlow 任务中设置环境变量和环境

时间:2021-02-25 16:20:50

标签: python anaconda environment-variables airflow

我目前正在尝试自动化由不同脚本组成的数据管道。其中许多脚本依赖于名为 DB_URL 的环境变量的设置。 在 python 脚本中,这个变量是通过 os.getenv('DB_URL', None) 读入的。

我可以通过使用 BashOperator 并在脚本执行前直接指定 DB_URL 来执行 DAG:

default_args = {
'owner': 'Hans Bambel',
'depends_on_past': False,
'email': ['hans-bambel@example.com'],
'email_on_failure': False,
'email_on_retry': False,
'retries': 0,
'retry_delay': timedelta(minutes=5),
}

with DAG(
    dag_id='get_data_from_testdb',
    default_args=default_args,
    description='Gets some data from the DB specified in the connection "test_db"',
    schedule_interval=None,
    start_date=datetime(2021, 2, 24)
) as dag:
    connection = BaseHook.get_connection("test_db")
    db_url = 'postgresql://' + str(connection.login) + ':' + str(connection.password) + \
             '@' + str(connection.host) + ':' + str(connection.port) + '/' \
             + str(connection.schema)

    test_db_call = BashOperator(
        task_id='test_db_call',
        bash_command=f'export DB_URL={db_url}; /path/to/my/conda/environment/python /path/to/my/scripts/db_connection_test.py'
    )

但我想为所有使用相同 env 变量的脚本设置一次 DB_URL,如下所示:

with DAG(
        dag_id='get_data_from_testdb',
        default_args=default_args,
        description='Gets some data from the DB specified in the connection "test_db"',
        schedule_interval=None,
        start_date=datetime(2021, 2, 24)
    ) as dag:
        connection = BaseHook.get_connection("test_db")
        db_url = 'postgresql://' + str(connection.login) + ':' + str(connection.password) + '@' + str(connection.host) + ':' + str(connection.port) + '/' + str(connection.schema)

        set_db_env = BashOperator(
            task_id='set-dburl',
            bash_command=f'export DB_URL={db_url}'
        )

        # activate_myenv = BashOperator(
        #     task_id='activate-conda-environment',
        #     bash_command='source activate myenv'
        # )

        test_db_call = BashOperator(
            task_id='test_db_call',
            bash_command=f'/path/to/my/conda/environment/python /path/to/my/scripts/db_connection_test.py'
        )
        set_db-env >> test_db_call

此外,我想事先激活我的 conda 环境(由 activate_myenv 任务准备),但是在将其添加到 DAG 时出现以下错误:

[2021-02-25 17:07:12,923] {bash.py:158} INFO - Running command: source activate carex
[2021-02-25 17:07:12,932] {bash.py:169} INFO - Output:
[2021-02-25 17:07:12,942] {bash.py:173} INFO - bash: activate: No such file or directory
[2021-02-25 17:07:12,943] {bash.py:177} INFO - Command exited with return code 1

我希望每个 DAG 都是独立运行的,但不是每个任务也是如此。因此,我希望我的第二个 DAG 也能正常工作。 有什么我可以做的事情吗?

1 个答案:

答案 0 :(得分:1)

当您对 unix shell 的环境进行任何更改时,例如创建一个新的 变量,这种变化会向下传播到子进程,但永远不会传播到 外壳的父级。这就是 Unix shell 的工作原理。

因此,当您的 BashOperator 执行“export DB_URL=...”时,会更改外壳 正在运行 set_db_env 任务,但是一旦该任务完成,它的 修改后的环境消失了,随之而来的是您创建的 DB_URL 变量。下一个任务 test_db_call 继承了 set_db_env 开始时的相同环境 与,而不是它改变的那个。

要使 DB_URL 可用于所有脚本,您可以在之前定义它 气流进程运行,通常在用户运行的 .bashrc 文件中 气流过程。这样你的shell脚本就可以直接访问 变量的值以通常的方式。

或者您可以使用 Airflow 的“变量”:在 Airflow UI 中,菜单 Admin / Variables,定义 key=DB_URL,设置值,然后保存。然后你可以使用 Concepts docs 中描述的机制与 jinja 模板:

bash_command='echo {{ var.value.DB_URL }}'

使用双括号语法访问变量的值。