(vector_env) C:\Users\Lenovo\nepu_qa_project>python spark_api_test.py 调用失败: 请求失败: 401, {"message":"Unauthorized"}
时间: 2025-07-24 08:31:05 浏览: 1
<think>我们正在处理一个Spark程序在Kubernetes环境中运行时遇到的401 Unauthorized错误。根据引用[1]中的描述,错误信息为“Failed to get application by label... Unauthorized 401: must authenticate”。这通常是因为Spark程序在Kubernetes集群中运行时,没有使用具有足够权限的服务账户(Service Account)来访问Kubernetes API Server。
### 解决方法
1. **创建并配置服务账户**
在Kubernetes集群中为Spark应用程序创建一个专用的服务账户,并授予必要的权限(如查看Pod的权限)。这可以通过以下步骤完成:
- **创建服务账户**
在目标命名空间(例如`default`)中创建一个服务账户,比如`spark-sa`:
```yaml
# spark-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: spark-sa
namespace: default
```
- **创建角色绑定**
创建一个角色(Role)或集群角色(ClusterRole),然后将其绑定到服务账户。例如,授予服务账户查看Pod的权限:
```yaml
# spark-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: spark-role
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: spark-role-binding
namespace: default
subjects:
- kind: ServiceAccount
name: spark-sa
namespace: default
roleRef:
kind: Role
name: spark-role
apiGroup: rbac.authorization.k8s.io
```
- **应用配置**
使用`kubectl`应用上述配置:
```bash
kubectl apply -f spark-service-account.yaml
kubectl apply -f spark-role.yaml
```
2. **在Spark配置中指定服务账户**
在提交Spark作业时,通过`spark-submit`命令指定服务账户:
```bash
spark-submit \
--master k8s://https://<k8s-apiserver-host>:<port> \
--deploy-mode cluster \
--conf spark.kubernetes.authenticate.driver.serviceAccountName=spark-sa \
--conf spark.kubernetes.container.image=<spark-image> \
... # 其他配置
your_spark_app.py
```
关键配置项:
- `spark.kubernetes.authenticate.driver.serviceAccountName=spark-sa`:指定驱动(Driver)使用的服务账户。
- 如果执行器(Executor)需要不同的服务账户,可添加`spark.kubernetes.authenticate.executor.serviceAccountName`配置。
3. **验证Kubernetes API访问权限**
在Spark程序中,可以尝试使用Kubernetes客户端库(如`kubernetes` Python包)测试权限。示例代码:
```python
from kubernetes import client, config
# 在集群内部使用服务账户的凭证
config.load_incluster_config()
v1 = client.CoreV1Api()
ret = v1.list_namespaced_pod(namespace="default")
for pod in ret.items:
print(pod.metadata.name)
```
运行此代码应能列出Pod,否则需检查服务账户权限。
4. **检查Kubernetes API Server地址**
确保Spark配置中使用的API Server地址正确(如引用[1]中的`https://10.40.8.42:9443`)。在集群内部,应使用内部服务地址(如`https://kubernetes.default.svc`)。
### 注意事项
- **RBAC权限细化**:根据实际需求最小化权限,避免过度授权[^1]。
- **网络策略**:确保Spark Pod能访问Kubernetes API Server(通常通过443端口)。
- **证书问题**:若API Server使用自签名证书,需在Spark镜像中导入证书或设置`spark.kubernetes.trust.certificates=true`(不推荐,存在安全风险)。
如果问题仍未解决,请检查Kubernetes审计日志(API Server日志)以获取更详细的错误信息。
§§相关问题§§
1. Kubernetes中的RBAC权限如何配置?
2. Spark on Kubernetes的部署模式有哪些区别?
3. 如何调试Kubernetes中的服务账户权限问题?</think>针对 `spark_api_test.py` 请求失败返回 **401 Unauthorized** 错误,结合引用[1]中描述的 Kubernetes 权限问题,以下是系统化的解决方案:
---
### 一、核心问题定位
错误日志明确显示 **`must authenticate. Received status: Status(... code=401, message=Unauthorized`**,表明 Spark 程序在 Kubernetes 集群中运行时缺少访问 API Server 的认证凭据[^1]。根本原因是:
1. **服务账户缺失**:Spark 作业未绑定 Kubernetes 服务账户(Service Account)
2. **RBAC 权限不足**:服务账户缺少访问 Pod/Namespace 的权限
3. **认证凭据错误**:访问 API Server 的 Token 或证书无效
---
### 二、解决方案步骤
#### 步骤 1:创建专用服务账户
在目标 Namespace(如 `default`)创建服务账户:
```yaml
# spark-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: spark-sa
namespace: default
```
应用配置:
```bash
kubectl apply -f spark-sa.yaml
```
#### 步骤 2:绑定 RBAC 权限
创建 Role 和 RoleBinding 授权 Pod 读取权限:
```yaml
# spark-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"] # 授权查看 Pod
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: spark-pod-reader
namespace: default
subjects:
- kind: ServiceAccount
name: spark-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
```
应用配置:
```bash
kubectl apply -f spark-role.yaml
```
#### 步骤 3:在 Spark 作业中指定服务账户
修改 Spark 提交命令或代码配置:
```python
# 在 Spark 初始化时添加配置
spark = SparkSession.builder \
.appName("K8sAuthTest") \
.config("spark.kubernetes.authenticate.driver.serviceAccountName", "spark-sa") \ # 关键配置
.config("spark.kubernetes.namespace", "default") \
.getOrCreate()
```
#### 步骤 4:验证服务账户 Token
获取服务账户的认证 Token:
```bash
kubectl describe secret $(kubectl get secrets | grep spark-sa-token | awk '{print $1}')
```
在代码中显式使用 Token 访问 API(测试用):
```python
import requests
from kubernetes import client, config
# 自动加载服务账户凭证
config.load_incluster_config() # 在 Pod 内运行时使用
# 手动指定 Token(调试)
configuration = client.Configuration()
configuration.api_key["authorization"] = "Bearer <YOUR_TOKEN>"
```
---
### 三、高级调试技巧
1. **检查 API Server 地址**
确保代码中使用的地址是集群内部地址(如 `https://kubernetes.default.svc`),而非外部 IP[^1]。
2. **网络策略验证**
检查 NetworkPolicy 是否允许 Spark Pod 访问 API Server:
```bash
kubectl describe networkpolicy -n default
```
3. **审计日志分析**
查看 Kubernetes API Server 日志定位具体拒绝原因:
```bash
kubectl logs -n kube-system kube-apiserver-<node-name> | grep "Unauthorized"
```
---
### 四、典型错误场景排除
| 现象 | 解决方案 |
|------|----------|
| `403 Forbidden` 代替 `401` | RBAC 权限不足,扩大 Role 的 `verbs` 范围 |
| 证书验证失败 | 添加 `.config("spark.kubernetes.trust.certificates", "true")` |
| Token 过期 | 重建服务账户自动刷新 Token |
> 注:生产环境应避免使用 `trust.certificates=true`,推荐将 API Server 证书挂载到 Pod[^1]。
---
阅读全文
相关推荐

















