pathlib / configparser 的气流问题 - 'PosixPath' 对象不可迭代

Airflow issue with pathlib / configparser - 'PosixPath' object is not iterable

我正在尝试将我的气流设置容器化。我的任务是保持环境不变,只需将其移动到 docker 容器中即可。我们目前在 anaconda 环境中安装了 Airflow 和所有依赖项。所以我所做的是创建一个自定义 docker 图像来安装 anaconda 并创建我的环境。问题是,我们当前的环境利用 systemd 服务启动气流,其中 Docker 需要通过气流命令“airflow webserver/scheduler/worker”将气流 运行 启动,当我 运行 那样时,我得到一个错误。启动调度程序后出现错误。

我们的 DAG 需要自定义存储库来帮助与我们的数据库服务器进行通信。在该 repo 中,我们使用 pathlib 获取配置文件的路径并将其传递给 configparser。

基本上是这样的:

import configparser
from pathlib import Path

config = configparser.ConfigParser()
p = Path(__file__)
p = p.parent
config_file_name = 'comms.conf'
config.read(p.joinpath('config', config_file_name))

这为我在 Airflow 中的所有 DAG 抛出了以下错误:

Broken DAG: [/opt/airflow/dags/example_folder/example_dag.py] 'PosixPath' object is not iterable

命令行错误为:

[2021-01-11 19:53:13,868] {dagbag.py:259} ERROR - Failed to import: /opt/airflow/dags/example_folder/example_dag.py
Traceback (most recent call last):
  File "/opt/anaconda3/envs/airflow/lib/python3.7/site-packages/airflow/models/dagbag.py", line 256, in process_file
    m = imp.load_source(mod_name, filepath)
  File "/opt/anaconda3/envs/airflow/lib/python3.7/imp.py", line 172, in load_source
    module = _load(spec)
  File "<frozen importlib._bootstrap>", line 696, in _load
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/opt/airflow/example_folder/example_dag.py", line 8, in <module>
    dag = Dag()
  File "/opt/airflow/dags/util/dag_base.py", line 27, in __init__
    self.comms = get_comms(Variable.get('environment'))
  File "/opt/airflow/repository/repo_folder/custom_script.py", line 56, in get_comms
    config = get_config('comms.conf')
  File "/opt/airflow/repository/repo_folder/custom_script.py", line 39, in get_config
    config.read(p.joinpath('config', config_file_name))
  File "/opt/anaconda3/envs/airflow/lib/python3.7/site-packages/backports/configparser/__init__.py", line 702, in read
    for filename in filenames:
TypeError: 'PosixPath' object is not iterable

我能够在 docker 容器之外复制此行为,所以我认为这与它没有任何关系。 airflow 运行s 作为 systemd 服务和它如何通过 cli 运行s 之间一定是有区别的?

这是我的 airflow 服务文件:

[Unit]
Description=Airflow webserver daemon
After=network.target postgresql.service mysql.service redis.service rabbitmq-server.service
Wants=postgresql.service mysql.service redis.service rabbitmq-server.service

[Service]
EnvironmentFile=/etc/sysconfig/airflow
User=airflow
Group=airflow
Type=simple
ExecStart=/opt/anaconda3/envs/airflow/bin/airflow webserver
Restart=on-failure
RestartSec=5s
PrivateTmp=true

[Install]
WantedBy=multi-user.target

这是我在服务文件中使用的气流环境文件。请注意,我需要在本地导出这些 env 变量,以使气流达到 运行,直至 cli 中的这一点。另请注意,自定义存储库位于 /opt/airflow 目录中。

AIRFLOW_CONFIG=/opt/airflow/airflow.cfg
AIRFLOW_HOME=/opt/airflow
PATH=/bin:/opt/anaconda3/envs/airflow/bin:/opt/airflow/etl:/opt/airflow:$PATH
PYTHONPATH=/opt/airflow/etl:/opt/airflow:$PYTHONPATH

我的气流配置是默认的,除了以下变化:

executor = CeleryExecutor
sql_alchemy_conn = postgresql+psycopg2://airflow:airflow@192.168.x.x:5432/airflow
load_examples = False
logging_level = WARN
broker_url = amqp://guest:guest@127.0.0.1:5672/
result_backend = db+postgresql://airflow:airflow@192.168.x.x:5432/airflow
catchup_by_default =  False

configparser==3.5.3

我的conda环境使用的是python3.7,airflow版本是1.10.14。它在 Centos7 服务器上 运行ning。如果有人有任何可以帮助的想法,我会采纳!

编辑:如果我将行 config.read(p.joinpath('config', config_file_name)) 更改为直接指向这样的配置 config.read('/opt/airflow/repository/repo_folder/config/comms.conf') 它工作正常。所以它与 configparser 如何处理 pathlib 输出有关?但是如果气流是通过 systemd 服务 运行?

就没有问题了

Edit2:我还可以将 pathlib 对象包装在 str() 中并且它可以工作。 config.read(str(p.joinpath('config', config_file_name))) 我只是想知道为什么这在 systemd 服务上运行良好。我担心其他东西会被破坏?

配置文件的路径计算错误。

这是因为下面一行

# filename: custom_script.py
p = p.parent
confpath = p.joinpath('config', config_file_name))

confpath 的计算结果为 /opt/airflow/repository/repo_folder/config/comms.conf

您共享的配置文件所在的路径是/opt/airflow/repository/repo_folder/conn.conf

您需要通过使用 custom_script.py 所在的文件夹构建其路径来解析相对于 repo_folder 的配置文件。

# filename: custom_script.py

from pathlib import Path

p = Path(dirname(__file__))
p = p.parent
confpath = p.joinpath(config_file_name)

我可以通过卸载并安装较新版本的 configparser 来解决这个问题。

configparser==5.0.1