> For the complete documentation index, see [llms.txt](https://documentation.alluxio.io/ee-ai-cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.alluxio.io/ee-ai-cn/data-access/s3-proxy.md).

# S3 代理

S3 代理（S3 Proxy）是部署在 S3 客户端节点上的轻量级代理服务。它通过 Alluxio 的挂载表和一致性哈希环，识别保存目标对象或文件分段的 Alluxio worker，并把请求直接转发到对应 worker。

S3 代理主要用于 AWS CLI、boto3、PyTorch S3 Connector 等基于 AWS SDK、无法正确处理 Alluxio worker HTTP 307 重定向的客户端。应用不需要修改 S3 API 调用方式，只需将 S3 endpoint 指向 S3 代理。

本页讲的是代理的部署与运维。S3 API 本身——端点、身份验证、部署模式、支持的操作——见 [S3 API](/ee-ai-cn/data-access/s3-api.md)。

## 工作原理

```
S3 客户端（AWS CLI、boto3、PyTorch S3 Connector 等）
    │  Path-style S3 请求
    ▼
节点本地 S3 代理（默认端口 8080）
    │  根据挂载表、一致性哈希环和 Range 偏移选择 worker
    ▼
数据所属的 Alluxio Worker S3 API（默认端口 29998）
    │  缓存命中：直接返回
    │  缓存未命中：从 UFS 加载
    ▼
底层存储（S3、GCS、HDFS 等）
```

S3 代理启动后会连接 Alluxio 集群使用的 etcd，获取 worker 列表、挂载表和路由信息。当 worker 加入或退出集群时，代理会定期刷新这些信息。

每个请求到达代理后，代理会：

1. 根据 S3 bucket 和 object key 查询 Alluxio 挂载表。
2. 将 S3 请求路径转换为对应的 UFS 路径。
3. 根据 UFS 路径和一致性哈希环计算数据所属 worker。
4. 如果启用了文件分段，则结合 `Range` 请求的起始偏移计算分段所属 worker。
5. 将请求头和请求体转发到目标 worker 的 S3 API。

代理会保留 `Authorization`、`Range` 等请求头。代理刚启动时，可能在数秒内短暂返回 `502`，直到首次完成 worker 和挂载表信息同步。

## 前提条件

部署 S3 代理前，请确认：

* 当前 Kubernetes Operator 和 CRD 支持 `spec.s3Proxy`。Operator 从 `v3.7.2` 开始支持该字段。
* 需要通过 S3 访问的 bucket 已挂载到 Alluxio 命名空间。
* S3 代理镜像可以被 Kubernetes 节点拉取。
* S3 代理能够调度到所有可能运行 S3 客户端的节点。
* 如果使用 `hostNetwork: true`，默认端口 `8080` 未被节点上的其他进程占用。

检查 Operator 是否支持 `spec.s3Proxy`：

```shell
kubectl explain alluxiocluster.spec.s3Proxy
```

检查 Alluxio 集群状态（示例中，namespace 为 `alx-ns`，集群名称为 `alluxio-cluster`）：

```shell
kubectl -n alx-ns get alluxiocluster alluxio-cluster
```

检查挂载点：

```shell
kubectl -n alx-ns exec -it alluxio-cluster-coordinator-0 -- \
  alluxio mount list
```

> 上述 namespace、`AlluxioCluster` 名称和 Pod 名称均为示例，请替换为实际环境中的值。

## 使用 Kubernetes Operator 部署

在 Kubernetes Operator 管理的环境中，只需修改现有 `AlluxioCluster` 资源。Operator 会自动创建和维护以下资源：

* S3 代理配置 `ConfigMap`
* 每个目标节点一个 S3 代理 Pod 的 `DaemonSet`
* 集群内访问使用的 `ClusterIP` Service
* 容器端口、健康检查和 DNS 策略

不要手动创建或修改 S3 代理的 ConfigMap、DaemonSet 和 Service。直接修改 Operator 生成的资源，后续可能会被 Operator 覆盖。

### 配置示例

以下示例使用：

* `alluxio-cluster` 作为 `AlluxioCluster` 名称。
* `alx-ns` 作为 namespace。
* S3 代理默认端口 `8080`。
* `hostNetwork: true`，客户端通过节点回环地址 `127.0.0.1` 访问。
* `Alluxio-client: "true"` 选择运行 S3 客户端的节点。
* 1 GiB 文件分片。不需要分片可以忽略。

> **示例配置：** 镜像地址、镜像版本、namespace、节点标签、污点容忍和资源规格需要根据实际环境修改。端口 `8080` 是默认值，也可以通过 `spec.s3Proxy.ports.http` 修改。修改端口后，客户端 endpoint 必须使用相同端口。

将以下内容合并到现有 `alluxio-cluster.yaml`。不要覆盖或删除 `spec` 和 `spec.properties` 中已有的其他配置。

```yaml
apiVersion: k8s-operator.alluxio.com/v1
kind: AlluxioCluster
metadata:
  name: alluxio-cluster
  namespace: alx-ns
spec:
  properties:
    # 必需：启用每个 Alluxio worker 的 S3 API。
    alluxio.worker.s3.api.enabled: "true"

    # 客户端代理模式的参考配置。
    # S3 代理会把请求路由到数据所属 worker；跨分段读取也需要 worker
    # 能够执行重定向。
    alluxio.worker.s3.redirect.enabled: "true"

    # 建议启用：复用 worker S3 API 的 HTTP 连接。
    alluxio.worker.s3.connection.keep.alive.enabled: "true"
    alluxio.worker.s3.redirect.health.check.enabled: "false"

    # 本示例启用 1 GiB 文件分段。
    alluxio.user.file.segment.enabled: "true"
    alluxio.user.file.segment.size: "1GB"

  s3Proxy:
    # S3 代理默认关闭，必须显式启用。
    enabled: true

    # 示例镜像地址和版本，请替换为实际可用值。
    image: image-registry/alluxio-s3-proxy
    imageTag: AI-3.9-16.0.0
    imagePullPolicy: IfNotPresent

    # true：代理使用节点网络，支持通过 127.0.0.1:8080 访问。
    # 当前 Operator 中该字段的默认值为 true。
    hostNetwork: true

    # S3 代理默认监听端口。可以修改，但需同步修改客户端 endpoint。
    ports:
      http: 8080

    # 在每个可能运行 S3 客户端的节点上部署一个代理 Pod。
    # 请替换为实际环境中的客户端节点标签。
    nodeSelector:
      Alluxio-client: "true"

    # 仅当客户端节点存在对应 NoSchedule 污点时才需要此项。
    # toleration 只允许 Pod 调度到污点节点，不会为节点添加污点。
    tolerations:
      - key: "Alluxio-Client"
        operator: "Exists"
        effect: "NoSchedule"

    config:
      # 单位为字节，必须与 alluxio.user.file.segment.size 完全一致。
      segmentSize: 1073741824

    # 以下是资源配置示例，不是适用于所有环境的推荐值。
    # 请根据 worker 数量、并发数和对象大小进行调整。
    resources:
      limits:
        cpu: "16"
        memory: "4Gi"
      requests:
        cpu: "2"
        memory: "1Gi"
```

应用配置：

```shell
kubectl apply -f alluxio-cluster.yaml
```

### 关键配置说明

| 配置项                                               | 是否必需     | 示例值          | 说明                                                            |
| ------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------- |
| `alluxio.worker.s3.api.enabled`                   | 是        | `"true"`     | 启用 worker S3 API。S3 代理默认转发到 worker 的`29998` 端口。               |
| `alluxio.worker.s3.redirect.enabled`              | 是，参考配置   | `"true"`     | 允许 worker 执行 HTTP 重定向，并支持跨分段读取场景。S3 客户端只连接代理，不直接处理 worker 路由。 |
| `alluxio.worker.s3.connection.keep.alive.enabled` | 建议       | `"true"`     | 复用 HTTP 连接，降低高并发请求的连接开销。                                      |
| `alluxio.user.file.segment.enabled`               | 使用分段时必需  | `"true"`     | 启用文件分段读取。                                                     |
| `alluxio.user.file.segment.size`                  | 使用分段时必需  | `"1GB"`      | worker 使用的分段大小。必须与`s3Proxy.config.segmentSize` 一致。            |
| `s3Proxy.enabled`                                 | 是        | `true`       | 让 Operator 创建 S3 代理相关资源。默认值为`false`。                          |
| `s3Proxy.image`                                   | 是        | 示例镜像地址       | S3 代理使用独立镜像，不继承 Alluxio 集群镜像。                                 |
| `s3Proxy.imageTag`                                | 是        | 示例版本         | 应使用与目标 Alluxio 版本兼容并经过验证的镜像版本。                                |
| `s3Proxy.hostNetwork`                             | 是，建议显式设置 | `true`       | 决定使用节点回环地址还是 Kubernetes Service 访问。当前默认值为`true`。              |
| `s3Proxy.ports.http`                              | 否        | `8080`       | S3 代理默认端口。Operator 会同步配置代理监听端口、容器端口和 Service 端口。              |
| `s3Proxy.nodeSelector`                            | 取决于集群    | 示例节点标签       | 决定在哪些节点运行代理。必须覆盖所有可能运行 S3 客户端的节点。                             |
| `s3Proxy.tolerations`                             | 取决于集群    | 示例污点容忍       | 客户端节点存在污点时需要配置。                                               |
| `s3Proxy.config.segmentSize`                      | 使用分段时必需  | `1073741824` | 代理使用的分段大小，单位为字节。1 GiB 等于`1073741824` 字节。                      |
| `s3Proxy.resources`                               | 建议       | 示例资源规格       | 根据实际并发和集群规模调整，不应把示例值视为固定推荐值。                                  |

Operator 会根据 `AlluxioCluster` 自动生成以下代理配置，不需要客户手动填写：

* etcd 访问地址
* Alluxio 集群名称
* worker S3 API 端口
* S3 代理监听端口
* `hostNetwork: true` 时使用的 `ClusterFirstWithHostNet` DNS 策略
* `hostNetwork: false` 时使用的 `ClusterFirst` DNS 策略

`nodeSelector` 和 `tolerations` 中的 key 区分大小写。示例中的 `Alluxio-client` 和 `Alluxio-Client` 是两个不同的 key，必须分别与实际节点 label 和 taint 一致。

如果节点还没有示例 label，可以执行：

```shell
kubectl label node <client-node-name> Alluxio-client=true
```

该命令会修改节点标签。执行前请确认 `<client-node-name>` 是计划运行 S3 客户端的节点。

### 验证 Operator 生成的资源

使用 component label 查询 Operator 创建的全部 S3 代理资源：

```shell
kubectl -n alx-ns get daemonset,configmap,service \
  -l app.kubernetes.io/component=s3-proxy
```

使用示例中的 `AlluxioCluster` 名称时，通常会生成：

```
alluxio-cluster-s3-proxy
alluxio-cluster-s3-proxy-config
alluxio-cluster-s3-proxy-local
```

实际资源名称可能受到集群名称和 Operator 命名规则影响。建议先通过 label 查询实际名称，不要在自动化脚本中直接假设资源名称。

等待 DaemonSet 就绪：

```shell
kubectl -n alx-ns rollout status \
  daemonset/alluxio-cluster-s3-proxy
```

检查代理 Pod 所在节点：

```shell
kubectl -n alx-ns get pods \
  -l app.kubernetes.io/component=s3-proxy \
  -o wide
```

检查 DaemonSet 状态：

```shell
kubectl -n alx-ns get daemonset \
  -l app.kubernetes.io/component=s3-proxy
```

`DESIRED`、`CURRENT` 和 `READY` 应一致，并且每个可能运行 S3 客户端的节点上都应有一个 Ready 状态的 S3 代理 Pod。

## 从 Kubernetes Pod 访问 S3 代理

Kubernetes 中有两种访问 S3 代理的方式：

| 访问方式               | S3 代理配置                | 客户端 Pod 配置                  | Endpoint                     | 是否保证访问本节点代理                                  |
| ------------------ | ---------------------- | --------------------------- | ---------------------------- | -------------------------------------------- |
| Kubernetes Service | 建议`hostNetwork: false` | 普通 Pod 即可                   | `http://<service-name>:8080` | 是，Operator 会设置`internalTrafficPolicy: Local` |
| 节点回环地址             | `hostNetwork: true`    | 客户端也必须使用`hostNetwork: true` | `http://127.0.0.1:8080`      | 是                                            |

> **当前 Operator 行为：** `hostNetwork: true` 时仍会创建 ClusterIP Service，但不会为该 Service 设置 `internalTrafficPolicy: Local`。此时通过 Service 访问可以正常工作，但请求可能被转发到其他节点的 S3 代理，不能保证 node-local。需要严格保证本地访问时，请按照下面两种推荐方式之一配置。

### 方式一：通过 Kubernetes Service 访问

该方式适用于使用普通 Pod 网络的 Kubernetes 应用，是大多数 Kubernetes 工作负载的推荐方式。

将 S3 代理配置为：

```yaml
spec:
  s3Proxy:
    hostNetwork: false
    ports:
      http: 8080
```

该片段只展示访问方式相关字段。镜像、节点选择、污点容忍、分段配置和资源配置仍需保留。

当 `s3Proxy.hostNetwork` 为 `false` 时，当前 Operator 会：

* 让 S3 代理使用普通 Pod 网络。
* 创建一个 `ClusterIP` Service。
* 自动为 Service 设置 `internalTrafficPolicy: Local`。
* 不为代理配置 `hostPort`。
* 自动使用 `ClusterFirst` DNS 策略。

`internalTrafficPolicy: Local` 表示 kube-proxy 只会把 Service 流量转发到客户端所在节点上的 Ready endpoint。这样可以避免请求先跨节点访问另一个 S3 代理。

如果客户端所在节点没有 Ready 状态的 S3 代理 endpoint，请求会失败，不会自动转发到其他节点。因此，`s3Proxy.nodeSelector` 必须覆盖所有 S3 客户端节点。

#### 确认 Service 配置

查询实际 Service 名称：

```shell
kubectl -n alx-ns get service \
  -l app.kubernetes.io/component=s3-proxy
```

对于示例集群，Service 名称为：

```
alluxio-cluster-s3-proxy-local
```

确认 Service 的本地流量策略：

```shell
kubectl -n alx-ns get service \
  alluxio-cluster-s3-proxy-local \
  -o jsonpath='{.spec.internalTrafficPolicy}{"\n"}'
```

预期输出：

```
Local
```

检查 Service endpoint 及其所在节点：

```shell
kubectl -n alx-ns get endpointslice \
  -l kubernetes.io/service-name=alluxio-cluster-s3-proxy-local \
  -o wide
```

如果客户端 Pod 所在节点没有对应 endpoint，应检查 S3 代理的 `nodeSelector`、`tolerations` 和 Pod Ready 状态。

#### Service Endpoint

与 S3 代理位于同一 namespace 的客户端可以使用短 Service 名称：

```
http://alluxio-cluster-s3-proxy-local:8080
```

其他 namespace 中的客户端应使用完整 Service DNS 名称：

```
http://alluxio-cluster-s3-proxy-local.alx-ns.svc.cluster.local:8080
```

从实际客户端 Pod 检查健康状态：

```shell
kubectl -n <client-namespace> exec <client-pod> -- \
  curl -fsS \
  http://alluxio-cluster-s3-proxy-local.alx-ns.svc.cluster.local:8080/health
```

预期输出：

```
OK
```

不要在普通 Kubernetes Pod 中使用 `127.0.0.1:8080`。普通 Pod 的 `127.0.0.1` 指向客户端 Pod 自己，不是节点或 S3 代理 Pod。

#### `hostNetwork: true` 时通过 Service 访问

当前 Operator 在 `s3Proxy.hostNetwork: true` 时也会创建 ClusterIP Service，但不会设置 `internalTrafficPolicy: Local`。未显式设置时，Kubernetes 使用 `Cluster` 策略，可以选择任意节点上的 Ready S3 代理 endpoint。

因此，这种组合：

```
s3Proxy.hostNetwork: true + 客户端使用 Service DNS
```

功能上可用，但不保证请求访问本节点 S3 代理，可能增加一次跨节点网络传输。对于依赖 node-local 性能的场景，不建议使用该组合。

### 方式二：通过 `127.0.0.1` 访问

该方式适用于客户端已经使用 host network，或者应用明确要求使用节点回环地址的场景。

S3 代理需要配置：

```yaml
spec:
  s3Proxy:
    hostNetwork: true
    ports:
      http: 8080
```

当 `s3Proxy.hostNetwork` 为 `true` 时，当前 Operator 会：

* 让 S3 代理使用节点网络。
* 将 `ports.http` 同时配置为容器端口和 `hostPort`。
* 自动使用 `ClusterFirstWithHostNet` DNS 策略，使代理仍能解析集群内的 etcd 和其他 Service。
* 创建 ClusterIP Service，但不设置 `internalTrafficPolicy: Local`。

客户端 Pod 也必须使用 host network。例如：

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: s3-client
  namespace: client-ns
spec:
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet
  nodeSelector:
    Alluxio-client: "true"
  tolerations:
    - key: "Alluxio-Client"
      operator: "Exists"
      effect: "NoSchedule"
  containers:
    - name: client
      image: <client-image>
      env:
        - name: S3_ENDPOINT
          value: http://127.0.0.1:8080
```

该客户端 Pod 和 Ready 状态的 S3 代理 Pod 必须运行在同一个节点。S3 代理 DaemonSet 应覆盖客户端可能被调度到的所有节点。

从客户端 Pod 检查健康状态：

```shell
kubectl -n client-ns exec s3-client -- \
  curl -fsS http://127.0.0.1:8080/health
```

预期输出：

```
OK
```

使用该方式前，还需要确认：

* 节点上的 `8080` 端口没有被其他进程占用。
* 客户端 Pod 确实设置了 `hostNetwork: true`。
* 客户端 Pod 与 S3 代理 Pod 位于同一节点。
* 网络策略和节点安全策略允许相应访问。

如果客户端使用普通 Pod 网络，即使它与 S3 代理位于同一节点，`127.0.0.1` 仍然只指向客户端 Pod 自身。

## 验证 S3 API 访问

Alluxio S3 API 只支持 path-style 请求，不支持 virtual-hosted-style bucket 地址。

根据访问方式设置 endpoint：

```shell
# 方式一：通过 Kubernetes Service 访问
export S3_PROXY_ENDPOINT=http://alluxio-cluster-s3-proxy-local.alx-ns.svc.cluster.local:8080

# 方式二：通过节点回环地址访问
# export S3_PROXY_ENDPOINT=http://127.0.0.1:8080
```

### 使用 AWS CLI 验证

配置 path-style addressing：

```shell
aws configure set default.s3.addressing_style path
```

在 SIMPLE 认证模式下，Access Key 用作 Alluxio 用户名，Secret Key 可以使用任意非空值：

```shell
export AWS_ACCESS_KEY_ID=testuser
export AWS_SECRET_ACCESS_KEY=testpassword
```

列出 bucket：

```shell
aws s3 ls --endpoint-url "${S3_PROXY_ENDPOINT}"
```

上传并下载测试对象：

```shell
printf 's3-proxy-test\n' > /tmp/s3-proxy-test.txt

aws s3 cp /tmp/s3-proxy-test.txt \
  s3://<bucket>/s3-proxy-test.txt \
  --endpoint-url "${S3_PROXY_ENDPOINT}"

aws s3 cp \
  s3://<bucket>/s3-proxy-test.txt \
  /tmp/s3-proxy-download.txt \
  --endpoint-url "${S3_PROXY_ENDPOINT}"

cmp /tmp/s3-proxy-test.txt /tmp/s3-proxy-download.txt
```

`cmp` 没有输出且退出码为 `0` 表示下载内容与上传内容一致。

### 使用 boto3 验证 Range 读取

在客户端环境中安装 boto3，并通过环境变量提供 endpoint 和凭据。不要把生产凭据直接写入源代码。

```python
import os

import boto3
from botocore.config import Config


s3 = boto3.client(
    "s3",
    endpoint_url=os.environ["S3_PROXY_ENDPOINT"],
    aws_access_key_id=os.environ["AWS_ACCESS_KEY_ID"],
    aws_secret_access_key=os.environ["AWS_SECRET_ACCESS_KEY"],
    region_name=os.environ.get("AWS_REGION", "us-east-1"),
    config=Config(s3={"addressing_style": "path"}),
)

response = s3.get_object(
    Bucket="<bucket>",
    Key="<object-key>",
    Range="bytes=0-1023",
)

try:
    data = response["Body"].read()
finally:
    response["Body"].close()

print(
    "status=",
    response["ResponseMetadata"]["HTTPStatusCode"],
    "content_range=",
    response.get("ContentRange"),
    "bytes=",
    len(data),
)
```

成功的 Range 请求应返回 HTTP `206`，并在 `ContentRange` 中显示实际返回的字节范围。

## 一致性哈希与文件分段

S3 代理必须使用 UFS 路径作为一致性哈希键，而不是直接使用 S3 请求路径。例如：

```
s3://real-bucket/data/file
```

代理会根据 Alluxio 挂载表，把请求中的 bucket 和 object key 转换为 UFS 路径。为了确保代理和 Alluxio worker 对数据归属的计算结果一致，需要将对外提供 S3 访问的 bucket 正确挂载到 Alluxio：

```shell
alluxio mount add \
  --path /<bucket> \
  --ufs-uri s3://<real-bucket>/
```

如果没有匹配的挂载，代理会退回使用 `s3://bucket/key` 计算哈希。该结果可能与 worker 针对已挂载路径计算的结果不同，导致请求被路由到错误 worker。

启用文件分段后，大文件会按固定大小拆分，不同分段可以由不同 worker 缓存。代理会根据 Range 起始偏移选择对应分段的 worker。

以下两个值必须完全一致：

```yaml
spec:
  properties:
    alluxio.user.file.segment.size: "1GB"
  s3Proxy:
    config:
      segmentSize: 1073741824
```

其中 `s3Proxy.config.segmentSize` 的单位是字节。不一致会造成 Range 请求被路由到错误 worker。

## 更新 S3 代理配置

更新 `AlluxioCluster` 中的 `spec.s3Proxy`，然后重新应用：

```shell
kubectl apply -f alluxio-cluster.yaml
```

Operator 会继续管理生成的 ConfigMap、DaemonSet 和 Service。不要直接编辑生成的资源。

S3 代理通过 `subPath` 挂载生成的 `config.yaml`。如果只修改了 `s3Proxy.config` 中的字段，ConfigMap 更新后，现有代理 Pod 不会自动重新加载配置，需要滚动重启 DaemonSet：

```shell
kubectl -n alx-ns rollout restart \
  daemonset/alluxio-cluster-s3-proxy
```

等待滚动更新完成：

```shell
kubectl -n alx-ns rollout status \
  daemonset/alluxio-cluster-s3-proxy
```

## Docker 或裸机部署

在非 Kubernetes 环境中，S3 代理使用独立的结构化 `config.yaml`。需要手动配置 etcd 地址、Alluxio 集群名称、worker S3 端口、代理监听端口和分段大小。

最小配置示例：

```yaml
etcd:
  urls: "http://alluxio-etcd:2379"
cluster:
  name: "DefaultAlluxioCluster"
worker:
  s3Port: 29998
proxy:
  listenPort: 8080
  segmentSize: 1073741824
```

通过 `ALLUXIO_PROXY_CONFIG` 指定配置文件并启动代理：

```shell
export ALLUXIO_PROXY_CONFIG=./config.yaml
integration/proxy/start.sh
```

如果 etcd 启用了认证，通过环境变量提供凭据：

```shell
export ALLUXIO_ETCD_USERNAME='<username>'
export ALLUXIO_ETCD_PASSWORD='<password>'
```

容器前台运行时可以设置：

```shell
export ALLUXIO_PROXY_FOREGROUND=1
```

修改 `config.yaml` 后需要重启 S3 代理。

## 故障排查

### DaemonSet 没有创建 Pod

检查 DaemonSet 的 `DESIRED` 数量：

```shell
kubectl -n alx-ns get daemonset \
  -l app.kubernetes.io/component=s3-proxy
```

如果 `DESIRED` 为 `0`，通常表示没有节点匹配 `s3Proxy.nodeSelector`。检查节点标签：

```shell
kubectl get nodes --show-labels
```

### S3 代理 Pod 一直处于 Pending

检查 Pod 事件：

```shell
kubectl -n alx-ns describe pod <s3-proxy-pod>
```

重点检查：

* 节点污点是否存在对应 toleration。
* CPU 或内存资源是否充足。
* `nodeSelector` 是否匹配预期节点。

### Service DNS 可以解析，但连接超时

当 `internalTrafficPolicy: Local` 生效时，如果客户端节点没有 Ready 状态的 S3 代理 endpoint，kube-proxy 不会转发到其他节点。

检查客户端和代理所在节点：

```shell
kubectl -n <client-namespace> get pod <client-pod> -o wide

kubectl -n alx-ns get pods \
  -l app.kubernetes.io/component=s3-proxy \
  -o wide
```

然后检查 EndpointSlice：

```shell
kubectl -n alx-ns get endpointslice \
  -l kubernetes.io/service-name=alluxio-cluster-s3-proxy-local \
  -o wide
```

### `127.0.0.1:8080` 连接被拒绝

确认：

* S3 代理设置了 `hostNetwork: true`。
* 客户端 Pod 也设置了 `hostNetwork: true`。
* 客户端和 S3 代理位于同一节点。
* 客户端使用的端口与 `s3Proxy.ports.http` 一致。
* 节点端口没有被其他进程占用。

### 健康检查成功，但 S3 请求失败

检查：

* 客户端是否使用 path-style addressing。
* 目标 bucket 是否已经挂载到 Alluxio。
* Access Key 和 Secret Key 是否均为非空值。
* 应用配置的 endpoint 是否与实际访问方式一致。
* 代理是否已从 etcd 获取到 worker 和挂载表信息。

### 请求返回 502

代理刚启动时，可能在首次加载 worker 视图前短暂返回 `502`。如果持续返回 `502`，检查代理到 etcd 的连接、集群名称和 worker 状态。

查看代理日志：

```shell
kubectl -n alx-ns logs \
  -l app.kubernetes.io/component=s3-proxy \
  --all-containers=true \
  --tail=200
```

### Range 请求路由到错误 worker

确认：

* `alluxio.user.file.segment.enabled` 为 `true`。
* `alluxio.user.file.segment.size` 与 `s3Proxy.config.segmentSize` 完全一致。
* bucket 已正确挂载，代理可以把 S3 路径转换为正确的 UFS 路径。
* `alluxio.worker.s3.redirect.enabled` 为 `true`。

可以比较文件位置和代理日志中的 `target=` 字段：

```shell
alluxio fs location <path> --segments 0-2
```

同一分段的请求应被转发到保存该分段的 worker。
