在现代云原生环境中,构建轻量级、高性能的对象存储服务是许多应用场景的核心需求。RustFS 作为一个基于 Rust 编写的高性能 S3 兼容对象存储解决方案,因其资源占用低、性能优异而受到关注。本文记录在单节点 Kubernetes 环境中,使用 HostPath 持久化部署 RustFS,并通过 Gateway API + Envoy Gateway + MetalLB 将 S3 API 与 Web Console 暴露到集群外。整体方案适合实验、测试与个人环境,生产环境建议替换为更高可用的存储与部署架构。
1. 环境信息
| 组件 | 版本 / 说明 |
|---|---|
| Kubernetes | v1.34.6+rke2r3 |
| MetalLB | 已部署,用于为 LoadBalancer Service 分配外部 IP |
| Gateway API | v1.4.1 |
| Envoy Gateway | v1.9.1 |
| 部署方式 | 非 Helm,单主机单节点 |
| 持久化 | HostPath + 静态 PV/PVC |
| S3 Endpoint | rustfs.me.com |
| Web Console Endpoint | s3.me.com |
最终访问方式:
- S3 API:
https://rustfs.me.com - Web Console:
https://s3.me.com
MetalLB 会自动为 Envoy Gateway 创建的 LoadBalancer Service 分配外部地址,例如本文中的 10.0.10.100。在本地配置 hosts 后,即可通过域名访问。
2. 前置条件
开始前请确认以下组件已经可用:
- Kubernetes 集群正常运行;
- Gateway API CRD 已安装;
- Envoy Gateway 已安装,并存在
GatewayClass/eg; - MetalLB 已配置地址池,可以为 LoadBalancer Service 分配 EXTERNAL-IP;
- 已在
rustfs命名空间中创建 TLS Secret,例如rustfs-tls。
检查 GatewayClass:
kubectl get gatewayclass eg
创建 TLS Secret 示例:
kubectl create secret tls rustfs-tls -n rustfs \
--cert=/path/to/fullchain.pem \
--key=/path/to/privkey.pem
注意:证书需要覆盖
rustfs.me.com和s3.me.com。如果是自签证书,浏览器或客户端访问时可能需要额外信任。
3. 部署 RustFS
创建 rustfs.yaml,内容如下。该文件包含 Namespace、PV、PVC、Deployment 与 Service。
apiVersion: v1
kind: Namespace
metadata:
name: rustfs
---
# ========== PV: 数据目录 ==========
apiVersion: v1
kind: PersistentVolume
metadata:
name: rustfs-data-pv
spec:
capacity:
storage: 500Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /r5/rustfs/data
type: DirectoryOrCreate
---
# ========== PV: 日志目录 ==========
apiVersion: v1
kind: PersistentVolume
metadata:
name: rustfs-logs-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /r5/rustfs/logs
type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rustfs-data
namespace: rustfs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Gi
volumeName: rustfs-data-pv
storageClassName: ""
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rustfs-logs
namespace: rustfs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
volumeName: rustfs-logs-pv
storageClassName: ""
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: rustfs
namespace: rustfs
labels:
app: rustfs
spec:
replicas: 1
strategy:
type: Recreate # hostPath + RWO,使用 Recreate 避免多 Pod 同时挂载
selector:
matchLabels:
app: rustfs
template:
metadata:
labels:
app: rustfs
spec:
initContainers:
- name: rustfs-perms
image: alpine:3.20
command: ["sh", "-c", "chown -R 10001:10001 /data /logs"]
securityContext:
runAsUser: 0
volumeMounts:
- name: data
mountPath: /data
- name: logs
mountPath: /logs
containers:
- name: rustfs
image: rustfs/rustfs:latest
imagePullPolicy: IfNotPresent
ports:
- name: api
containerPort: 9000
- name: console
containerPort: 9001
env:
- name: RUSTFS_ADDRESS
value: ":9000"
- name: RUSTFS_CONSOLE_ADDRESS
value: ":9001"
- name: RUSTFS_CONSOLE_ENABLE
value: "true"
- name: RUSTFS_OBS_LOGGER_LEVEL
value: "error"
- name: RUSTFS_OBS_LOG_DIRECTORY
value: "/var/log/rustfs/"
- name: RUSTFS_SERVER_URL
# 如果客户端通过 HTTPS 访问,建议改为 https://rustfs.me.com
value: "http://rustfs.me.com"
volumeMounts:
- name: data
mountPath: /data
- name: logs
mountPath: /var/log/rustfs/
securityContext:
runAsUser: 10001
runAsGroup: 10001
readinessProbe:
tcpSocket:
port: 9000
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 9000
initialDelaySeconds: 30
periodSeconds: 20
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "2"
memory: "2Gi"
volumes:
- name: data
persistentVolumeClaim:
claimName: rustfs-data
- name: logs
persistentVolumeClaim:
claimName: rustfs-logs
---
apiVersion: v1
kind: Service
metadata:
name: rustfs
namespace: rustfs
spec:
type: ClusterIP
selector:
app: rustfs
ports:
- name: api
port: 9000
targetPort: 9000
- name: console
port: 9001
targetPort: 9001
应用部署:
kubectl apply -f rustfs.yaml
检查 Pod 状态:
kubectl get pods -n rustfs
预期输出类似:
NAME READY STATUS RESTARTS AGE
rustfs-666cf84994-9z69k 1/1 Running 0 22h
4. 配置 Gateway API
创建 rustfs-gateway.yaml,通过 Gateway API 将 RustFS 的 S3 API 与 Web Console 暴露出去。
注意:原示例中有一个空的
gpulistener,缺少protocol、port等必填字段,会导致 Gateway 不合法。本文已移除该 listener,只保留实际使用的s3与console。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: rustfs-gateway
namespace: rustfs
spec:
gatewayClassName: eg
listeners:
- name: s3
protocol: HTTPS
port: 443
hostname: "rustfs.me.com"
tls:
mode: Terminate
certificateRefs:
- name: rustfs-tls
- name: console
protocol: HTTPS
port: 443
hostname: "s3.me.com"
tls:
mode: Terminate
certificateRefs:
- name: rustfs-tls
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rustfs-route
namespace: rustfs
spec:
parentRefs:
- name: rustfs-gateway
sectionName: s3
hostnames:
- "rustfs.me.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: rustfs
port: 9000
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rustfs-console
namespace: rustfs
spec:
parentRefs:
- name: rustfs-gateway
sectionName: console
hostnames:
- "s3.me.com"
rules:
- backendRefs:
- name: rustfs
port: 9001
应用 Gateway 配置:
kubectl apply -f rustfs-gateway.yaml
5. 验证部署
查看 Gateway:
kubectl get gateway -n rustfs
预期输出:
NAME CLASS ADDRESS PROGRAMMED AGE
rustfs-gateway eg 10.0.10.100 True 157m
查看 HTTPRoute:
kubectl get httproute -n rustfs
预期输出:
NAME HOSTNAMES AGE
rustfs-console ["s3.me.com"] 28m
rustfs-route ["rustfs.me.com"] 156m
此时 MetalLB 已为 Envoy Gateway 分配外部地址,例如 10.0.10.100。
在本地配置 hosts:
10.0.10.100 rustfs.me.com s3.me.com
Linux / macOS:
sudo tee -a /etc/hosts <<'EOF'
10.0.10.100 rustfs.me.com s3.me.com
EOF
Windows 编辑:
C:\Windows\System32\drivers\etc\hosts
然后访问:
- Web Console:
https://s3.me.com - S3 API:
https://rustfs.me.com
也可以用 curl 检查:
curl -k -I https://s3.me.com
curl -k -I https://rustfs.me.com
如果使用 AWS CLI,可以测试 S3 Endpoint:
aws --endpoint-url https://rustfs.me.com s3 ls
6. 注意事项与踩坑记录
6.1 Gateway listener 必须完整
Gateway API 中每个 listener 都必须包含 name、protocol、port。如果存在空的 listener,例如只有 name: gpu,会导致 Gateway 创建失败或状态异常。
6.2 TLS Secret 必须存在且域名匹配
certificateRefs 引用的 rustfs-tls 必须位于同一个 Namespace,并且证书 SAN 需要覆盖:
rustfs.me.coms3.me.com
否则 Gateway listener 可能无法正常提供服务。
6.3 MetalLB 地址分配
如果 kubectl get gateway -n rustfs 的 ADDRESS 为空,可以检查 Envoy Gateway 创建的 LoadBalancer Service:
kubectl get svc -n envoy-gateway-system | grep rustfs
确认 MetalLB 已正确配置地址池和 L2Advertisement。
6.4 HostPath 仅适合单节点实验
本文使用 HostPath + RWO PV,并设置 Deployment 策略为 Recreate。该方式只适合单节点、测试或个人环境。生产环境建议:
- 使用分布式存储或云盘;
- 部署多副本 RustFS;
- 使用固定镜像版本,而不是
latest; - 配置备份、监控、告警;
- 使用 cert-manager 等工具管理证书。
7. 总结
本文完整记录了在单节点 Kubernetes 上部署 RustFS,并通过 Gateway API、Envoy Gateway 与 MetalLB 暴露 S3 API 和 Web Console 的过程。
核心链路如下:
外部客户端
-> https://rustfs.me.com / https://s3.me.com
-> MetalLB 分配的 Gateway 地址
-> Envoy Gateway HTTPS listener
-> HTTPRoute
-> rustfs Service
-> rustfs Pod: 9000 / 9001
该方案配置简单、结构清晰,适合快速验证 RustFS 与 Gateway API 的集成。如果需要用于生产,建议进一步优化存储、副本、证书管理与高可用架构。