news 2026/11/4 3:05:43

在 Kubernetes 上部署 MinIO 对象存储:基于 examples 仓库的 Standalone 与 Distributed 完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 Kubernetes 上部署 MinIO 对象存储:基于 examples 仓库的 Standalone 与 Distributed 完整实战指南
  • 示例工程

【免费下载链接】examples

Kubernetes application example tutorials

项目地址:https://gitcode.com/gh_mirrors/examp/examples
点击查看免费下载

本指南以 examples 仓库中归档的 MinIO 示例文档(_archived/storage/minio/README.md)为骨架,完整讲解如何在 Kubernetes 上以云原生方式部署 MinIO(AWS S3 兼容的对象存储服务):一套是使用 Deployment + PVC + LoadBalancer 的单机(Standalone)方案,另一套是使用 Headless Service + StatefulSet 的四节点分布式(Distributed)方案。读完本文,你将掌握两类部署的完整 YAML 清单、kubectl 操作命令、DNS 命名原理与资源清理方法,并能直接在本仓库的清单文件基础上落地运行。

MinIO 是什么:S3 兼容的云原生对象存储

MinIO 是一个面向云应用与 DevOps 场景的、与 AWS S3 兼容的对象存储服务器。它的关键特性是“云原生(cloud native)”:MinIO 能够感知自身运行在集群管理器之中,并直接利用集群管理基础设施来分配计算与存储资源,而不是把自己当成一个需要手工绑定主机节点的传统存储进程。

正是这种设计让它与 Kubernetes 天然契合:

  • 存储资源的分配交给 Kubernetes 的 PersistentVolumeClaim / PersistentVolume 体系完成,数据不随 Pod 生命周期丢失;
  • 计算资源的编排交给 Deployment、StatefulSet 等控制器完成,Pod 故障后会自动重建;
  • 网络访问的暴露交给 Service(ClusterIP / NodePort / LoadBalancer)体系完成,集群内外均可按需访问。

前置条件

本示例假定你满足以下环境要求:

  • 已安装并运行Kubernetes 版本 >= 1.4的集群(示例清单使用apps/v1API 版本,适用于 1.9 及以后的版本;更早版本需按清单内注释回退到apps/v1beta2或extensions/v1beta1,详见下文);
  • 已安装kubectl命令行工具并加入系统 PATH;
  • 集群具备可动态供给的存储类(示例中storageClassName: standard,在 GKE 等云平台通常开箱即用)。

仓库中六个清单文件与本文各步骤一一对应,位于_archived/storage/minio/目录下,可直接以本地相对路径配合kubectl使用。

一、单机(Standalone)部署

单机方案把 MinIO 以单副本 Deployment 的方式运行,数据挂载到持久卷上,适用于开发测试或数据量有限的场景。该小节使用以下 Kubernetes 核心组件:

组件用途本示例对应资源
Pod承载 MinIO 容器的运行单元Deployment 模板中生成
Service提供稳定的网络访问入口minio-service(LoadBalancer)
Deployment管理副本集与 Pod 生命周期,故障自动恢复minio-deployment
PersistentVolumeClaim向集群申请持久化存储minio-pv-claim(10Gi)

1.1 快速开始(Quickstart)

如果只想快速跑起来,按顺序执行下面三条命令即可(本仓库中请将 URL 替换为本地清单路径,如kubectl apply -f _archived/storage/minio/minio-standalone-pvc.yaml):

kubectl create -f minio-standalone-pvc.yaml kubectl create -f minio-standalone-deployment.yaml kubectl create -f minio-standalone-service.yaml

1.2 Step 1:创建持久化卷声明(PVC)

MinIO 必须拥有持久化存储来保存对象数据。如果缺少持久化存储,数据会被写入容器文件系统,一旦容器重启,数据即被清空——这显然是对象存储不可接受的。

创建 PersistentVolumeClaim 即向集群“申请”存储:Kubernetes 会自动在集群中寻找与 PVC 请求匹配的 PV 并完成绑定。本示例的 PVC 清单如下(完整文件见 minio-standalone-pvc.yaml):

apiVersion: v1 kind: PersistentVolumeClaim metadata: # This name uniquely identifies the PVC. Will be used in deployment below. name: minio-pv-claim labels: app: minio-storage-claim spec: accessModes: - ReadWriteOnce storageClassName: standard resources: # This is the request for storage. Should be available in the cluster. requests: storage: 10Gi

执行创建:

kubectl create -f minio-standalone-pvc.yaml persistentvolumeclaim "minio-pv-claim" created

对关键字段的说明:

  • accessModes: ReadWriteOnce:表示该卷同一时刻只能被一个节点以读写方式挂载。对单机 MinIO 而言完全够用(多副本共享读写需要 ReadWriteMany,分布式方案正是通过“每个副本一块独立卷”绕开了这一限制);
  • storageClassName: standard:指定存储类。在支持动态供给的云环境(如 GKE 的 standard 存储类)下,PVC 创建后会由控制器自动创建底层 PV,无需手工预置;
  • requests.storage: 10Gi:申请 10GiB 容量,需确保集群中有足够的可供给配额。

1.3 Step 2:创建 MinIO Deployment

Deployment 封装了副本集(ReplicaSet)与 Pod:一旦某个 Pod 异常退出,控制器会立刻拉起一个新 Pod 顶上,因此你无需操心单点故障,就能获得一个稳定可用的 MinIO 服务。本示例的 Deployment 清单如下(完整文件见 minio-standalone-deployment.yaml):

apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1 kind: Deployment metadata: # This name uniquely identifies the Deployment name: minio-deployment spec: selector: matchLabels: app: minio strategy: type: Recreate template: metadata: labels: # Label is used as selector in the service. app: minio spec: # Refer to the PVC created earlier volumes: - name: storage persistentVolumeClaim: # Name of the PVC created earlier claimName: minio-pv-claim containers: - name: minio # Pulls the default Minio image from Docker Hub image: minio/minio:latest args: - server - /storage env: # Minio access key and secret key - name: MINIO_ACCESS_KEY value: "minio" - name: MINIO_SECRET_KEY value: "minio123" ports: - containerPort: 9000 hostPort: 9000 # Mount the volume into the pod volumeMounts: - name: storage # must match the volume name, above mountPath: "/storage"

执行创建:

kubectl create -f minio-standalone-deployment.yaml deployment "minio-deployment" created

逐段解读这个清单:

  • strategy.type: Recreate:更新策略为“先删旧、再建新”。因为示例在 Pod 上声明了hostPort: 9000,同一节点上同一端口只能被一个 Pod 占用,Recreate 策略可以避免新旧 Pod 同时竞争端口;
  • volumes+persistentVolumeClaim.claimName:把第 1 步创建的minio-pv-claim挂进 Pod,volumeMounts.mountPath: "/storage"将其挂载到容器内/storage目录,同时args里的server /storage告诉 MinIO 把该目录作为数据盘;
  • 环境变量:通过MINIO_ACCESS_KEY/MINIO_SECRET_KEY设置访问密钥,是客户端(如 S3 SDK、mc 客户端)访问该实例的凭证:
环境变量值说明
MINIO_ACCESS_KEYminio访问密钥(Access Key),客户端登录/认证使用
MINIO_SECRET_KEYminio123秘密密钥(Secret Key),需妥善保管
  • ports:containerPort: 9000声明容器监听端口,hostPort: 9000额外把端口绑定到宿主机。注意:示例清单将密钥明文写入 YAML,仅适合演示;生产环境应改为从 Kubernetes Secret 注入(见文末“生产化建议”)。

1.4 Step 3:创建 MinIO Service

Deployment 就绪后,访问方式取决于你的使用场景:是集群内部访问,还是暴露到集群外部(公网)。这由 Service 类型决定——默认类型ClusterIP只对集群内部连接可见,NodePort与LoadBalancer则会把服务暴露给外部流量。

本示例通过创建LoadBalancer类型的 Service 把 MinIO 暴露到外部(完整文件见 minio-standalone-service.yaml):

apiVersion: v1 kind: Service metadata: name: minio-service spec: type: LoadBalancer ports: - port: 9000 targetPort: 9000 protocol: TCP selector: app: minio

执行创建:

kubectl create -f minio-standalone-service.yaml service "minio-service" created

关键点说明:

  • selector.app: minio:Service 通过标签选择器路由到带有app: minio标签的 Pod,这与 Deployment 模板中的labels: app: minio一一对应,是流量正确转发的核心纽带;
  • port: 9000 / targetPort: 9000:Service 对外端口与容器实际监听端口均为 9000,protocol: TCP指定传输协议;
  • LoadBalancer 类型的 Service 通常需要云厂商(GCP、AWS、Azure 等)的负载均衡器支持,分配外部 IP 一般需要几分钟。创建后可用以下命令确认是否成功:
kubectl get svc minio-service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE minio-service 10.55.248.23 104.199.249.165 9000:31852/TCP 1m

EXTERNAL-IP出现后,即可通过http://104.199.249.165:9000访问 MinIO 的 S3 API 与 Web 控制台(登录凭据即上一步设置的环境变量)。PORT(S)中的9000:31852/TCP表示集群内 Service 端口 9000 同时映射到了各节点的 31852 端口(NodePort),本地开发时也可通过kubectl port-forward svc/minio-service 9000:9000转发访问。

1.5 Step 4:资源清理

使用完毕后,按依赖顺序清理 Deployment、PVC 与 Service:

kubectl delete deployment minio-deployment \ && kubectl delete pvc minio-pv-claim \ && kubectl delete svc minio-service

1.6 单机模式要点小结

  • 数据持久化依赖 PVC,缺了它容器重启即丢数据;
  • Deployment 提供自动恢复能力,但hostPort: 9000与Recreate策略意味着同一节点只能运行一个实例,横向扩容受限,因此单机方案适合开发测试与轻量场景;
  • 三种 Service 类型中,ClusterIP 仅集群内可访问,NodePort / LoadBalancer 面向外部流量,按需选用。

二、分布式(Distributed)部署

分布式方案把 MinIO 以 4 副本 StatefulSet 的方式部署,每个 Pod 挂载独立持久卷、通过内网 DNS 相互发现并组成一个分布式存储集群。该小节使用以下核心组件:

组件用途本示例对应资源
Pod承载 MinIO 容器的运行单元StatefulSet 模板中生成
ServiceHeadless Service 提供稳定 DNS 域minio(clusterIP: None)
StatefulSet提供确定性命名与唯一身份,管理有状态副本minio(replicas: 4)

2.1 快速开始(Quickstart)

按顺序执行三条命令(本仓库中请使用本地路径,如kubectl apply -f _archived/storage/minio/minio-distributed-headless-service.yaml):

kubectl create -f minio-distributed-headless-service.yaml kubectl create -f minio-distributed-statefulset.yaml kubectl create -f minio-distributed-service.yaml

2.2 Step 1:创建 MinIO Headless Service

Headless Service(clusterIP: None)控制了 StatefulSet 内部 Pod 所处的 DNS 域。该 Service 管理的域形如$(service name).$(namespace).svc.cluster.local(其中cluster.local是集群域名),域内 Pod 的完整域名形如$(pod-name-{i}).$(service name).$(namespace).svc.cluster.local。这是让 StatefulSet 中每个 Pod 都能获得可解析 DNS 地址的前提——分布式 MinIO 正是依靠这些域名互相通信。

本示例的 Headless Service 清单如下(完整文件见 minio-distributed-headless-service.yaml):

apiVersion: v1 kind: Service metadata: name: minio labels: app: minio spec: clusterIP: None ports: - port: 9000 name: minio selector: app: minio

执行创建:

kubectl create -f minio-distributed-headless-service.yaml service "minio" created

注意它与普通 Service 的两个区别:一是clusterIP: None(不分配集群 IP,改为直接暴露每个 Pod 的 DNS 记录);二是命名必须与 StatefulSet 的serviceName字段一致(本例均为minio),否则 Pod 无法进入该 DNS 域。

2.3 Step 2:创建 MinIO StatefulSet

StatefulSet 为每个 Pod 提供确定性的名称与唯一身份,非常适合部署有状态的分布式应用。要启动分布式 MinIO,需要把各参与节点的数据盘地址作为参数传给minio server命令,并且所有参与的 Pod 必须执行相同的命令——StatefulSet 恰好能完美满足这一要求。

本示例的 StatefulSet 清单如下(完整文件见 minio-distributed-statefulset.yaml):

# for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1 apiVersion: apps/v1 kind: StatefulSet metadata: name: minio labels: app: minio spec: serviceName: minio replicas: 4 selector: matchLabels: app: minio template: metadata: labels: app: minio spec: containers: - name: minio env: - name: MINIO_ACCESS_KEY value: "minio" - name: MINIO_SECRET_KEY value: "minio123" image: minio/minio:latest args: - server - http://minio-0.minio.default.svc.cluster.local/data - http://minio-1.minio.default.svc.cluster.local/data - http://minio-2.minio.default.svc.cluster.local/data - http://minio-3.minio.default.svc.cluster.local/data ports: - containerPort: 9000 hostPort: 9000 # These volume mounts are persistent. Each pod in the Statefulset # gets a volume mounted based on this field. volumeMounts: - name: data mountPath: /data # These are converted to volume claims by the controller # and mounted at the paths mentioned above. volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: standard resources: requests: storage: 10Gi

执行创建:

kubectl create -f minio-distributed-statefulset.yaml statefulset "minio" created

关键字段解读:

  • serviceName: minio:绑定第 1 步创建的 Headless Service,使 Pod 获得可解析的稳定 DNS 域名;
  • replicas: 4:创建 4 个副本。StatefulSet 按序创建并保证命名确定性,Pod 名称依次为minio-0、minio-1、minio-2、minio-3;
  • args中的 4 个 URL:把 4 个 Pod 的固定 DNS 地址(http://minio-{i}.minio.default.svc.cluster.local/data,其中default是命名空间)一次性传给server命令,四节点用完全相同的命令组成一个分布式实例。分布式 MinIO 采用纠删码(Erasure Coding)机制在多个节点间分散冗余数据,这也正是它比单机方案具备更高数据可靠性、可横向扩展的根本原因(该行为由 MinIO 服务端实现,本仓库仅负责以正确方式把节点地址编排进参数);
  • volumeClaimTemplates:StatefulSet 专属字段。控制器会依据模板为每一个Pod 自动生成并绑定一块独立 PVC(命名形如data-minio-0、data-minio-1……),随后挂载到mountPath: /data。这正是分布式 MinIO 中“每个节点一块独立持久盘”的实现来源,无需像单机方案那样手工预创建 PVC。

2.4 Step 3:创建 MinIO Service

分布式 StatefulSet 就绪后,同样通过 Service 决定访问方式。本示例继续使用 LoadBalancer 类型把整个集群暴露出去(完整文件见 minio-distributed-service.yaml):

apiVersion: v1 kind: Service metadata: name: minio-service spec: type: LoadBalancer ports: - port: 9000 targetPort: 9000 protocol: TCP selector: app: minio

执行创建:

kubectl create -f minio-distributed-service.yaml service "minio-service" created

该 Service 的selector.app: minio会命中 StatefulSet 创建的全部 4 个 Pod,LoadBalancer 会把外部流量负载均衡到整个分布式集群的任意节点。创建后确认外部 IP:

kubectl get svc minio-service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE minio-service 10.55.248.23 104.199.249.165 9000:31852/TCP 1m

2.5 Step 4:资源清理

分布式方案需要清理的对象比单机多一个 Headless Service:

kubectl delete statefulset minio \ && kubectl delete svc minio \ && kubectl delete svc minio-service

2.6 分布式模式原理:DNS 命名与自动供给卷

从源码与清单结构可以归纳出分布式部署的两个关键机制:

  1. 确定性 DNS 身份:$(pod-name-{i}).$(service name).$(namespace).svc.cluster.local这一命名规则,让 MinIO 各节点在启动时即可通过固定域名互连。即使某节点 Pod 被删除重建,其名称与域名保持不变,分布式集群的成员关系得以稳定维系;
  2. 按副本自动供给存储:volumeClaimTemplates是 StatefulSet 与 Deployment 的核心差异之一。控制器为每个有序副本生成独立 PVC 与卷,配合ReadWriteOnce访问模式,天然满足“每节点独享数据盘”的分布式存储需求,避免了单机方案中共享卷与Recreate策略的限制。

三、仓库中的资源清单与本地实操路径

本仓库将上述文档与清单统一归档在 _archived/storage/minio/ 目录下,六个文件与部署步骤的对应关系如下:

文件对应步骤用途
minio-standalone-pvc.yaml单机 Step 1申请 10Gi 持久卷
minio-standalone-deployment.yaml单机 Step 2单副本 MinIO Deployment
minio-standalone-service.yaml单机 Step 3LoadBalancer 对外暴露
minio-distributed-headless-service.yaml分布式 Step 1Headless Service 提供 DNS 域
minio-distributed-statefulset.yaml分布式 Step 24 副本分布式 StatefulSet
minio-distributed-service.yaml分布式 Step 3LoadBalancer 对外暴露

本地实操时,可将文中示例的kubectl create -f命令替换为仓库相对路径(kubectl create与kubectl apply均可,后者更适合反复调整清单的迭代场景),例如:

kubectl apply -f _archived/storage/minio/minio-standalone-pvc.yaml kubectl apply -f _archived/storage/minio/minio-standalone-deployment.yaml kubectl apply -f _archived/storage/minio/minio-standalone-service.yaml

排障时建议配合kubectl get pods、kubectl describe pod <pod-name>、kubectl logs <pod-name>查看运行状态与日志;若集群无云负载均衡器(如 minikube、Kind),可将 Service 的type临时改为NodePort或使用kubectl port-forward访问。

四、版本兼容与生产化建议

  1. API 版本适配:两套清单头部注释均提示——Kubernetes 1.9.0 及以上使用apps/v1;1.8.0~1.9.0 之前使用apps/v1beta2;1.8.0 之前使用extensions/v1beta1。请依据集群实际版本选择,这也是为什么本示例要求集群版本不低于 1.4;
  2. 凭据安全:示例把MINIO_ACCESS_KEY/MINIO_SECRET_KEY明文写入 YAML,仅适合演示。生产环境建议将密钥放入 Kubernetes Secret,再以env.valueFrom.secretKeyRef方式注入容器,避免凭据随清单泄露;
  3. 镜像版本:示例使用minio/minio:latest,便于复现。生产环境建议固定到明确的稳定版本标签(tag),保证集群内各节点镜像一致、可追溯;
  4. 资源与可用性:生产环境建议为容器补充resources.requests/limits(CPU/内存)声明,并为minio容器配置就绪/存活探针(readinessProbe / livenessProbe),让负载均衡与故障恢复更精准;
  5. 副本数与纠删码:分布式示例固定为 4 副本。实际副本数可根据容量与可靠性需求调整,但所有节点的启动参数必须保持一致(每个节点都要传入全部节点的地址),这是分布式 MinIO 组建集群的硬性要求。

结语

本文基于 examples 仓库的归档文档与配套清单,完整复现了 MinIO 在 Kubernetes 上的两套部署路径:单机模式用 Deployment + PVC 快速起一个带持久化的 S3 兼容存储;分布式模式用 StatefulSet + Headless Service 编排 4 节点存储集群。两者覆盖了 Kubernetes 有状态应用部署中最核心的组件组合(PVC、Deployment、Service、Headless Service、StatefulSet、volumeClaimTemplates),直接复用仓库中的清单即可在符合前置条件的集群上运行验证。

  • 示例工程

【免费下载链接】examples

Kubernetes application example tutorials

项目地址:https://gitcode.com/gh_mirrors/examp/examples
点击查看免费下载
上一篇:macOS录屏新选择:QuickRecorder的5大核心优势
下一篇:MELPA生态系统构建:从单一仓库到完整开发平台的转型

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 18:40:20

oneTBB 并行化复杂循环:parallel_for_each 与 parallel_pipeline 实战指南

并发编程高性能计算 【免费下载链接】oneTBB oneAPI Threading Building Blocks (oneTBB) 项目地址&#xff1a; https://gitcode.com/gh_mirrors/on/oneTBB 点击查看 免费下载 复杂循环的并行化并不总是像 parallel_for 那样简单直接。当迭代空间在运行前无法预知、循环体可能…

作者头像 李华
网站建设 2026/10/25 20:16:40

ResNet50毒蘑菇识别系统:光照畸变与遮挡鲁棒性实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/20 20:35:11

Cadence Allegro 16.6焊盘命名规范与表贴/通孔盘制作

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 20:37:35

正弦波信号源设计:文氏桥振荡器原理与调试全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/25 22:22:30

YOLOv5+DeepSort车流量统计:密集场景下的跟踪与计数实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华