Docker环境下PySpark应用无法连接Spark-Master的问题求助
从你的错误日志里java.net.UnknownHostException: spark-master可以明确看出,核心问题是你的PySpark应用所在的环境无法解析spark-master这个主机名,导致无法连接到Spark Master节点。下面分两种常用场景给出针对性解决方案:
场景1:Python应用用Docker容器运行(推荐)
既然你的Spark集群是用Docker Compose搭建的,最稳妥的方式是把Python应用也加入到同一个Docker网络(也就是你定义的spark网络)里,这样容器之间可以通过服务名互相解析通信。
步骤1:扩展Docker Compose文件,添加Python应用服务
在原有的docker-compose.yml里新增一个服务节点:
version: '3' services: spark-master: # 保留你原有的spark-master配置 image: docker.io/bitnami/spark:2 environment: - SPARK_MODE=master - SPARK_RPC_AUTHENTICATION_ENABLED=no - SPARK_RPC_ENCRYPTION_ENABLED=no - SPARK_LOCAL_STORAGE_ENCRYPTION_ENABLED=no - SPARK_SSL_ENABLED=no volumes: - type: bind source: ./conf/log4j.properties target: /opt/bitnami/spark/conf/log4j.properties ports: - '8080:8080' - '7077:7077' networks: - spark spark-worker-1: # 保留你原有的spark-worker-1配置 image: docker.io/bitnami/spark:2 environment: - SPARK_MODE=worker - SPARK_MASTER_URL=spark://spark-master:7077 - SPARK_WORKER_MEMORY=1G - SPARK_WORKER_CORES=1 - SPARK_RPC_AUTHENTICATION_ENABLED=no - SPARK_RPC_ENCRYPTION_ENABLED=no - SPARK_LOCAL_STORAGE_ENCRYPTION_ENABLED=no - SPARK_SSL_ENABLED=no volumes: - type: bind source: ./conf/log4j.properties target: /opt/bitnami/spark/conf/log4j.properties ports: - '8081:8081' networks: - spark depends_on: - spark-master # 新增Python应用服务 pyspark-app: build: . # 假设你的Python项目根目录有Dockerfile,构建包含PySpark的运行环境 volumes: - ./your-app-code:/app # 挂载本地代码目录到容器内 working_dir: /app environment: - SPARK_MASTER_URL=spark://spark-master:7077 - SPARK_DRIVER_HOST=pyspark-app # 用服务名作为driver主机名,让worker能回调连接 networks: - spark depends_on: - spark-master networks: spark: driver: bridge
步骤2:调整Spark Session配置
把代码里的spark.driver.host配置改成容器服务名(也就是上面的pyspark-app),或者通过环境变量动态获取:
def get_spark_context(app_name: str) -> SparkSession: conf = SparkConf() conf.setAll( [ ( "spark.master", os.environ.get("SPARK_MASTER_URL", "spark://spark-master:7077"), ), ("spark.driver.host", os.environ.get("SPARK_DRIVER_HOST", "pyspark-app")), # 修改此处 ("spark.submit.deployMode", "client"), ('spark.ui.showConsoleProgress', 'true'), ("spark.driver.bindAddress", "0.0.0.0"), ("spark.app.name", app_name) ] ) return SparkSession.builder.config(conf=conf).getOrCreate()
步骤3:启动所有服务
运行docker-compose up -d,这样Python应用容器和Spark集群容器处于同一个网络,就能正常解析spark-master主机名了。
场景2:Python应用在宿主机本地运行
如果不想把Python应用放进Docker,需要调整配置让宿主机能访问Spark集群,同时Spark Worker能连接回宿主机的Driver:
步骤1:修改Spark Master地址
把spark.master改成宿主机的localhost(因为你已经把7077端口映射到宿主机了):
conf.set("spark.master", "spark://localhost:7077")
步骤2:配置Driver主机名
必须把spark.driver.host设置为宿主机的真实IP地址(不能是localhost或local[*]),因为Spark Worker容器需要通过这个IP访问到你的宿主机Driver:
# 替换成你的宿主机IP,比如192.168.1.100 conf.set("spark.driver.host", "192.168.1.100")
步骤3:开放防火墙端口
Spark Driver默认会使用随机端口,你可以固定端口避免防火墙拦截:
conf.set("spark.driver.port", "4040") # 固定Driver端口
然后在宿主机防火墙开放这个端口,让Spark Worker容器能正常访问。
错误原因说明
你用Docker Compose创建的spark网络是自定义桥接网络,只有加入这个网络的容器才能互相通过服务名(比如spark-master)解析IP。如果你的Python应用不在这个网络里(不管是宿主机还是其他外部容器),就无法解析spark-master的主机名,从而抛出UnknownHostException。
内容的提问来源于stack exchange,提问作者Tavis




