Docker容器部署的Airflow如何连接访问HDFS读取文件?
问题根因
两个报错核心是Docker网络隔离+WebHDFS固有重定向机制导致的,没有其他玄学问题:
- 直接填
localhost/127.0.0.1时,容器内回环地址指向容器自身,根本碰不到宿主机或其他容器上的HDFS服务,直接触发No route to host - 填
host.docker.internal报Cannot assign requested address,一是Linux环境下Docker默认不会自动配置这个域名到宿主机网关的映射,二是WebHDFS本身的逻辑是:你先访问9870端口的namenode请求文件,namenode会返回对应datanode的地址给客户端做二次重定向,如果HDFS配置里绑定的是127.0.0.1或者宿主机本地地址,容器拿到重定向地址后根本没法访问 - 如果HDFS和Airflow分别跑在独立Docker容器里,默认用bridge网络时容器之间不能直接通过宿主机IP通信,也会触发路由错误
分步解决方案
根据HDFS部署位置选对应方案操作即可。
场景1:HDFS部署在宿主机(本地物理机/虚拟机)
- 第一步:修改HDFS配置,避免返回不可路由的本地地址
找到Hadoop配置目录下的hdfs-site.xml,添加/修改如下配置,让HDFS服务监听所有网卡,且给客户端返回可跨网络访问的地址:
同时修改<property> <name>dfs.namenode.rpc-bind-host</name> <value>0.0.0.0</value> </property> <property> <name>dfs.namenode.servicerpc-bind-host</name> <value>0.0.0.0</value> </property> <property> <name>dfs.namenode.http-bind-host</name> <value>0.0.0.0</value> </property> <property> <name>dfs.datanode.bind-host</name> <value>0.0.0.0</value> </property> <property> <name>dfs.client.use.datanode.hostname</name> <value>true</value> </property> <property> <name>dfs.datanode.use.datanode.hostname</name> <value>true</value> </property>core-site.xml里的fs.defaultFS配置,不要写localhost,改成宿主机物理网卡的非回环IP(就是你之前在PyCharm里能正常访问的172.20.80.1这类地址),改完重启HDFS所有服务。 - 第二步:配置Airflow容器的宿主机访问规则
如果是用docker run启动Airflow,启动命令加--add-host=host.docker.internal:host-gateway参数;如果是用docker-compose部署,在Airflow对应服务的配置段下加:
重启Airflow容器后,先进入容器执行extra_hosts: - "host.docker.internal:host-gateway"curl http://host.docker.internal:9870/webhdfs/v1/?op=LISTSTATUS验证能正常返回HDFS目录列表,再把代码里的访问地址改成http://host.docker.internal:9870/webhdfs/v1/hadoop_files/sample_2022_01.parquet?op=OPEN即可。
场景2:HDFS和Airflow都部署在Docker容器中
- 第一步:创建自定义Docker桥接网络
执行命令:docker network create hadoop-net - 第二步:把HDFS相关容器、Airflow所有服务容器都接入这个自定义网络
启动namenode容器时指定--network hadoop-net --name hdfs-namenode(固定容器名方便Docker内部DNS解析),datanode容器也接入同一个网络;如果是compose部署,把所有相关服务都放在同一个自定义网络下,不要用默认bridge网络。 - 第三步:修改HDFS配置
配置项和场景1一致,把core-site.xml里的fs.defaultFS地址改成hdfs://hdfs-namenode:9000,确保datanode的服务端口在自定义网络内可通。 - 第四步:验证连通性
进入Airflow的worker容器执行curl http://hdfs-namenode:9870/webhdfs/v1/?op=LISTSTATUS,返回正常后再修改代码里的访问地址为对应容器名的URL即可。
稳定性优化建议
不推荐直接拼WebHDFS URL用pd.read_parquet读文件,WebHDFS两次重定向的逻辑在容器、跨网络环境下很容易出兼容问题,更稳定的方式是用HDFS原生RPC协议读取,绕开HTTP重定向逻辑:
- 先在Airflow镜像里安装pyarrow的HDFS依赖:
pip install pyarrow hdfs - 读文件代码改成如下形式:
from pyarrow import fs import pandas as pd # 宿主机部署HDFS就填host.docker.internal,容器同网络部署就填namenode容器名 hdfs = fs.HadoopFileSystem('host.docker.internal', port=9000) with hdfs.open_input_file('/hadoop_files/sample_2022_01.parquet') as f: df = pd.read_parquet(f)
另外记得检查宿主机/容器防火墙开放9000(RPC端口)、9870(namenode Web端口)、9864(datanode数据传输端口),避免路由通了但被防火墙拦截。
内容的提问来源于stack exchange,提问作者Val
相关产品推荐
相关产品推荐

