在Kubernetes上运行Spark时遭遇文件访问权限错误求助
先解答你的两个疑问:
为什么Jar已在容器本地还要复制?
Spark的Executor设计上会将所有依赖文件(包括Jar包)复制到自身的工作目录下,这是为了保证每个Executor拥有独立的文件副本,避免共享文件带来的并发冲突、权限不一致等问题,同时也能提升本地文件的访问效率。哪怕Jar已经存在于容器镜像中,Spark的fetchFile机制依然会执行这个复制流程,默认目标目录是Executor的当前工作目录(./)或者配置的spark.local.dir路径。如何让Master创建的目录具备可写权限?
问题的核心是Spark Executor Pod运行的用户没有当前工作目录的写入权限——在OpenShift中,默认会强制容器以非root用户运行,而你的Spark镜像的工作目录(比如/opt/spark)可能没有给这个非root用户分配写权限。下面是几个可行的解决方案:
解决方案1:指定Spark使用可写的临时目录
OpenShift容器默认会给/tmp目录赋予全局可写权限,你只需要在spark-submit命令中添加一个配置,让Spark将文件复制到/tmp即可:
$DIR/$SPARKVERSION/bin/spark-submit \ --master=k8s://https://192.168.99.101:8443 \ --deploy-mode=cluster \ --conf spark.executor.instances=3 \ --name spark-pi \ --class org.apache.spark.examples.SparkPi \ --conf spark.kubernetes.container.image=172.30.1.1:5000/myapp/spark-docker:latest \ --conf spark.kubernetes.namespace=$namespace \ --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \ --conf spark.kubernetes.driver.pod.name=spark-pi-driver \ # 添加下面这行配置指定可写目录 --conf spark.local.dir=/tmp \ local:///opt/spark/examples/jars/spark-examples_2.11-2.3.0.jar
这个方案最简单,不需要修改镜像或者集群配置,适合快速验证。
解决方案2:修改Spark镜像,配置有权限的工作目录
如果不想依赖/tmp,可以修改你的Spark Docker镜像,创建一个专门的工作目录并赋予正确的权限。比如在Dockerfile中添加:
# 创建专属工作目录 RUN mkdir -p /opt/spark/work-dir # 给OpenShift默认的非root用户(UID 185)赋予权限,不同环境UID可能有差异 RUN chown -R 185:185 /opt/spark/work-dir # 切换到该非root用户 USER 185 # 设置为容器默认工作目录 WORKDIR /opt/spark/work-dir
重新构建镜像后,Executor会默认使用这个有权限的目录进行文件复制,就不会出现权限问题了。
解决方案3:调整OpenShift安全上下文约束(SCC)(谨慎使用)
如果你的环境允许放宽安全限制,可以给spark服务账号添加anyuid SCC,让Pod可以以指定用户运行并获得更多目录权限:
oc adm policy add-scc-to-user anyuid -z spark -n myapp
注意:这个方案会降低集群的安全性,只适合测试环境,生产环境不推荐使用。
验证方法
修改spark-submit命令添加spark.local.dir=/tmp配置后,重新运行SparkPi任务,应该就能正常执行,不会再出现AccessDeniedException错误了。
内容的提问来源于stack exchange,提问作者Ben

