S3 Proxy
The S3 Proxy is a lightweight proxy service deployed on S3 client nodes. It uses the Alluxio mount table and consistent hash ring to identify the Alluxio worker that stores the requested object or file segment, then forwards the request directly to that worker.
The S3 Proxy is primarily intended for AWS CLI, boto3, PyTorch S3 Connector, and other AWS SDK-based clients that cannot correctly handle HTTP 307 redirects from Alluxio workers. Applications do not need to change how they call the S3 API; they only need to point their S3 endpoint to the S3 Proxy.
This page covers deploying and operating the proxy. For the S3 API itself — endpoints, authentication, deployment modes, and supported actions — see S3 API.
How It Works
S3 client (AWS CLI, boto3, PyTorch S3 Connector, and others)
│ Path-style S3 request
▼
Node-local S3 Proxy (default port 8080)
│ Selects a worker based on the mount table,
│ consistent hash ring, and Range offset
▼
Alluxio Worker S3 API that owns the data (default port 29998)
│ Cache hit: return data directly
│ Cache miss: load data from UFS
▼
Underlying storage (S3, GCS, HDFS, and others)After it starts, the S3 Proxy connects to the etcd instance used by the Alluxio cluster and retrieves the worker list, mount table, and routing information. The proxy refreshes this information periodically as workers join or leave the cluster.
For each request, the proxy:
Looks up the Alluxio mount table using the S3 bucket and object key.
Converts the S3 request path to the corresponding UFS path.
Calculates the worker that owns the data from the UFS path and consistent hash ring.
If file segmentation is enabled, calculates the worker that owns the segment using the starting offset of the
Rangerequest.Forwards the request headers and body to the target worker's S3 API.
The proxy preserves request headers such as Authorization and Range. For several seconds immediately after startup, the proxy may briefly return 502 responses until it finishes synchronizing its initial worker and mount-table information.
Prerequisites
Before deploying the S3 Proxy, verify that:
The current Kubernetes Operator and CRD support
spec.s3Proxy. Support starts with Operatorv3.7.2.The buckets that clients need to access through S3 are mounted in the Alluxio namespace.
Kubernetes nodes can pull the S3 Proxy image.
The S3 Proxy can be scheduled on every node that may run an S3 client.
If you use
hostNetwork: true, no other process on the node is using the default port8080.
Check whether the Operator supports spec.s3Proxy:
Check the Alluxio cluster status. In this example, the namespace is alx-ns and the cluster name is alluxio-cluster:
Check the mount points:
The namespace,
AlluxioClustername, and Pod name above are examples. Replace them with the values from your environment.
Deploy with the Kubernetes Operator
In an environment managed by the Kubernetes Operator, you only need to update the existing AlluxioCluster resource. The Operator automatically creates and manages:
A
ConfigMapcontaining the S3 Proxy configurationA
DaemonSetthat runs one S3 Proxy Pod on each target nodeA
ClusterIPService for in-cluster accessContainer ports, health checks, and DNS policies
Do not create or edit the S3 Proxy ConfigMap, DaemonSet, or Service manually. The Operator may overwrite changes made directly to generated resources.
Configuration Example
The following example uses:
alluxio-clusteras theAlluxioClustername.alx-nsas the namespace.The default S3 Proxy port,
8080.hostNetwork: true, allowing clients to connect through the node loopback address127.0.0.1.Alluxio-client: "true"to select nodes that run S3 clients.1 GiB file segmentation. You can omit the segmentation settings if segmentation is not required.
Example configuration: Change the image location, image version, namespace, node labels, tolerations, and resource allocation for your environment. Port
8080is the default, but you can change it throughspec.s3Proxy.ports.http. If you change the port, clients must use the same port in their endpoint.
Merge the following fields into the existing alluxio-cluster.yaml. Do not overwrite or remove other existing settings under spec or spec.properties.
Apply the configuration:
Key Configuration Settings
alluxio.worker.s3.api.enabled
Yes
"true"
Enables the worker S3 API. By default, the S3 Proxy forwards requests to worker port 29998.
alluxio.worker.s3.redirect.enabled
Yes for this reference configuration
"true"
Allows workers to issue HTTP redirects and supports cross-segment reads. The S3 client connects only to the proxy and does not handle worker routing directly.
alluxio.worker.s3.connection.keep.alive.enabled
Recommended
"true"
Reuses HTTP connections and reduces connection overhead for highly concurrent requests.
alluxio.user.file.segment.enabled
Required with segmentation
"true"
Enables segmented file reads.
alluxio.user.file.segment.size
Required with segmentation
"1GB"
Worker segment size. It must match s3Proxy.config.segmentSize.
s3Proxy.enabled
Yes
true
Instructs the Operator to create the S3 Proxy resources. The default is false.
s3Proxy.image
Yes
Example image location
The S3 Proxy uses a dedicated image and does not inherit the Alluxio cluster image.
s3Proxy.imageTag
Yes
Example version
Use an image version that is compatible with and validated for the target Alluxio version.
s3Proxy.hostNetwork
Yes; set it explicitly
true
Determines whether clients use the node loopback address or Kubernetes Service. The current default is true.
s3Proxy.ports.http
No
8080
Default S3 Proxy port. The Operator applies it to the proxy listen port, container port, and Service port.
s3Proxy.nodeSelector
Environment-dependent
Example node label
Determines which nodes run the proxy. It must cover every node that may run an S3 client.
s3Proxy.tolerations
Environment-dependent
Example toleration
Required when client nodes have taints.
s3Proxy.config.segmentSize
Required with segmentation
1073741824
Proxy segment size in bytes. 1 GiB equals 1073741824 bytes.
s3Proxy.resources
Recommended
Example resources
Adjust for actual concurrency and cluster size; do not treat the example as a fixed recommendation.
The Operator derives the following proxy settings from the AlluxioCluster; you do not need to configure them manually:
etcd endpoint
Alluxio cluster name
Worker S3 API port
S3 Proxy listen port
The
ClusterFirstWithHostNetDNS policy whenhostNetwork: trueThe
ClusterFirstDNS policy whenhostNetwork: false
Keys in nodeSelector and tolerations are case-sensitive. Alluxio-client and Alluxio-Client in this example are different keys, and each must match the actual node label or taint.
If the nodes do not yet have the example label, run:
This command changes the node's labels. Before running it, verify that <client-node-name> is a node intended to run S3 clients.
Verify the Operator-Generated Resources
Use the component label to list all S3 Proxy resources created by the Operator:
With the AlluxioCluster name in this example, the Operator typically creates:
Actual resource names may vary based on the cluster name and Operator naming rules. Use the label query to discover the names instead of assuming fixed names in automation.
Wait for the DaemonSet to become ready:
Check the nodes that run the proxy Pods:
Check the DaemonSet status:
The DaemonSet DESIRED, CURRENT, and READY counts should match, and every node that may run an S3 client should have a Ready S3 Proxy Pod.
Access the S3 Proxy from Kubernetes Pods
Kubernetes clients can access the S3 Proxy in two ways:
Kubernetes Service
hostNetwork: false recommended
A regular Pod
http://<service-name>:8080
Yes; the Operator sets internalTrafficPolicy: Local
Node loopback
hostNetwork: true
The client must also use hostNetwork: true
http://127.0.0.1:8080
Yes
Current Operator behavior: When
hostNetwork: true, the Operator still creates a ClusterIP Service, but does not setinternalTrafficPolicy: Localon that Service. Requests through the Service work, but may be forwarded to an S3 Proxy on another node and are not guaranteed to remain node-local. To guarantee node-local access, use one of the two recommended configurations below.
Method 1: Access Through a Kubernetes Service
This method is intended for Kubernetes applications that use the regular Pod network and is recommended for most Kubernetes workloads.
Configure the S3 Proxy as follows:
This fragment shows only the settings related to the access method. Keep the image, node selector, tolerations, segmentation, and resource settings from the complete example.
When s3Proxy.hostNetwork is false, the current Operator:
Runs the S3 Proxy in the regular Pod network.
Creates a
ClusterIPService.Automatically sets
internalTrafficPolicy: Localon the Service.Does not configure a
hostPortfor the proxy.Automatically uses the
ClusterFirstDNS policy.
internalTrafficPolicy: Local instructs kube-proxy to forward Service traffic only to a Ready endpoint on the same node as the client. This prevents the request from first crossing the network to an S3 Proxy on another node.
If the client node does not have a Ready S3 Proxy endpoint, the request fails instead of being forwarded to another node. Therefore, s3Proxy.nodeSelector must cover every S3 client node.
Verify the Service Configuration
Find the actual Service name:
For the example cluster, the Service name is:
Verify the Service's local traffic policy:
Expected output:
Check the Service endpoints and their nodes:
If the client Pod's node has no corresponding endpoint, check the S3 Proxy nodeSelector, tolerations, and Pod readiness.
Service Endpoint
A client in the same namespace as the S3 Proxy can use the short Service name:
A client in another namespace should use the fully qualified Service DNS name:
Check the health endpoint from an actual client Pod:
Expected output:
Do not use 127.0.0.1:8080 from a regular Kubernetes Pod. The loopback address of a regular Pod refers to the client Pod itself, not the node or the S3 Proxy Pod.
Access Through the Service with hostNetwork: true
The current Operator also creates a ClusterIP Service when s3Proxy.hostNetwork: true, but it does not set internalTrafficPolicy: Local. When the field is omitted, Kubernetes uses the Cluster policy and may select a Ready S3 Proxy endpoint on any node.
Therefore, this combination:
is functional, but does not guarantee that requests use the local-node S3 Proxy and may add a cross-node network transfer. It is not recommended for workloads that depend on node-local performance.
Method 2: Access Through 127.0.0.1
Use this method when clients already use the host network or the application explicitly requires a node loopback endpoint.
Configure the S3 Proxy as follows:
When s3Proxy.hostNetwork is true, the current Operator:
Runs the S3 Proxy in the node network namespace.
Configures
ports.httpas both the container port andhostPort.Automatically uses
ClusterFirstWithHostNet, allowing the proxy to resolve in-cluster etcd and other Services.Creates a ClusterIP Service without setting
internalTrafficPolicy: Local.
The client Pod must also use the host network. For example:
This client Pod and a Ready S3 Proxy Pod must run on the same node. The S3 Proxy DaemonSet must cover every node where the client may be scheduled.
Check the health endpoint from the client Pod:
Expected output:
Before using this method, verify that:
No other process on the node uses port
8080.The client Pod sets
hostNetwork: true.The client Pod and S3 Proxy Pod run on the same node.
Network policies and node security policies permit the connection.
If the client uses the regular Pod network, 127.0.0.1 refers only to the client Pod, even when the client and S3 Proxy run on the same node.
Verify S3 API Access
The Alluxio S3 API supports only path-style requests. Virtual-hosted-style bucket addresses are not supported.
Set the endpoint for the selected access method:
Verify with AWS CLI
Configure path-style addressing:
With SIMPLE authentication, the Access Key is the Alluxio username and the Secret Key can be any non-empty value:
List the buckets:
Upload and download a test object:
If cmp produces no output and exits with status 0, the downloaded content matches the uploaded content.
Verify a Range Read with boto3
Install boto3 in the client environment and provide the endpoint and credentials through environment variables. Do not store production credentials directly in source code.
A successful Range request should return HTTP 206 and show the returned byte range in ContentRange.
Consistent Hashing and File Segmentation
The S3 Proxy must use the UFS path as the consistent-hash key instead of using the S3 request path directly. For example:
The proxy uses the Alluxio mount table to convert the bucket and object key in a request to a UFS path. To ensure that the proxy and Alluxio workers calculate the same data ownership, correctly mount each bucket exposed through S3 in Alluxio:
If there is no matching mount, the proxy falls back to using s3://bucket/key for hashing. This result may differ from the worker's result for a mounted path, causing requests to be routed to the wrong worker.
When file segmentation is enabled, large files are divided into fixed-size segments that can be cached by different workers. The proxy uses the starting offset of a Range request to select the worker for the corresponding segment.
The following two values must match exactly:
s3Proxy.config.segmentSize is expressed in bytes. A mismatch can route Range requests to the wrong worker.
Update the S3 Proxy Configuration
Update spec.s3Proxy in the AlluxioCluster and apply the resource again:
The Operator continues to manage the generated ConfigMap, DaemonSet, and Service. Do not edit generated resources directly.
The S3 Proxy mounts the generated config.yaml using subPath. If you change only fields under s3Proxy.config, existing proxy Pods do not reload the updated ConfigMap automatically. Restart the DaemonSet after the ConfigMap is updated:
Wait for the rollout to complete:
Docker or Bare-Metal Deployment
In non-Kubernetes environments, the S3 Proxy uses a standalone structured config.yaml. Configure the etcd endpoint, Alluxio cluster name, worker S3 port, proxy listen port, and segment size manually.
Minimal configuration example:
Set ALLUXIO_PROXY_CONFIG to the configuration file and start the proxy:
If etcd authentication is enabled, provide the credentials through environment variables:
To run the container in the foreground, set:
Restart the S3 Proxy after changing config.yaml.
Troubleshooting
The DaemonSet Does Not Create Pods
Check the DaemonSet DESIRED count:
If DESIRED is 0, no nodes usually match s3Proxy.nodeSelector. Check the node labels:
The S3 Proxy Pod Remains Pending
Check the Pod events:
In particular, check whether:
Node taints have matching tolerations.
Sufficient CPU and memory resources are available.
nodeSelectormatches the intended nodes.
Service DNS Resolves but the Connection Times Out
When internalTrafficPolicy: Local is active, kube-proxy does not forward traffic to another node if the client node has no Ready S3 Proxy endpoint.
Check the nodes that run the client and proxy Pods:
Then check the EndpointSlice:
The Connection to 127.0.0.1:8080 Is Refused
Verify that:
The S3 Proxy sets
hostNetwork: true.The client Pod also sets
hostNetwork: true.The client and S3 Proxy run on the same node.
The client port matches
s3Proxy.ports.http.No other process on the node uses the port.
The Health Check Succeeds but S3 Requests Fail
Verify that:
The client uses path-style addressing.
The target bucket is mounted in Alluxio.
Both the Access Key and Secret Key are non-empty.
The application's endpoint matches the selected access method.
The proxy has retrieved the worker and mount-table information from etcd.
Requests Return 502
The proxy may briefly return 502 before loading its initial worker view. If 502 responses continue, check connectivity from the proxy to etcd, the cluster name, and worker status.
View the proxy logs:
Range Requests Are Routed to the Wrong Worker
Verify that:
alluxio.user.file.segment.enabledistrue.alluxio.user.file.segment.sizeexactly matchess3Proxy.config.segmentSize.The bucket is mounted correctly, allowing the proxy to convert the S3 path to the correct UFS path.
alluxio.worker.s3.redirect.enabledistrue.
Compare the file locations with the target= field in the proxy log:
Requests for the same segment should be forwarded to the worker that stores that segment.
Last updated