- 示例工程
【免费下载链接】examples
Kubernetes application example tutorials
本指南以 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.yaml1.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_KEY | minio | 访问密钥(Access Key),客户端登录/认证使用 |
MINIO_SECRET_KEY | minio123 | 秘密密钥(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 1mEXTERNAL-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-service1.6 单机模式要点小结
- 数据持久化依赖 PVC,缺了它容器重启即丢数据;
- Deployment 提供自动恢复能力,但
hostPort: 9000与Recreate策略意味着同一节点只能运行一个实例,横向扩容受限,因此单机方案适合开发测试与轻量场景; - 三种 Service 类型中,ClusterIP 仅集群内可访问,NodePort / LoadBalancer 面向外部流量,按需选用。
二、分布式(Distributed)部署
分布式方案把 MinIO 以 4 副本 StatefulSet 的方式部署,每个 Pod 挂载独立持久卷、通过内网 DNS 相互发现并组成一个分布式存储集群。该小节使用以下核心组件:
| 组件 | 用途 | 本示例对应资源 |
|---|---|---|
| Pod | 承载 MinIO 容器的运行单元 | StatefulSet 模板中生成 |
| Service | Headless 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.yaml2.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 1m2.5 Step 4:资源清理
分布式方案需要清理的对象比单机多一个 Headless Service:
kubectl delete statefulset minio \ && kubectl delete svc minio \ && kubectl delete svc minio-service2.6 分布式模式原理:DNS 命名与自动供给卷
从源码与清单结构可以归纳出分布式部署的两个关键机制:
- 确定性 DNS 身份:
$(pod-name-{i}).$(service name).$(namespace).svc.cluster.local这一命名规则,让 MinIO 各节点在启动时即可通过固定域名互连。即使某节点 Pod 被删除重建,其名称与域名保持不变,分布式集群的成员关系得以稳定维系; - 按副本自动供给存储:
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 3 | LoadBalancer 对外暴露 |
| minio-distributed-headless-service.yaml | 分布式 Step 1 | Headless Service 提供 DNS 域 |
| minio-distributed-statefulset.yaml | 分布式 Step 2 | 4 副本分布式 StatefulSet |
| minio-distributed-service.yaml | 分布式 Step 3 | LoadBalancer 对外暴露 |
本地实操时,可将文中示例的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访问。
四、版本兼容与生产化建议
- API 版本适配:两套清单头部注释均提示——Kubernetes 1.9.0 及以上使用
apps/v1;1.8.0~1.9.0 之前使用apps/v1beta2;1.8.0 之前使用extensions/v1beta1。请依据集群实际版本选择,这也是为什么本示例要求集群版本不低于 1.4; - 凭据安全:示例把
MINIO_ACCESS_KEY/MINIO_SECRET_KEY明文写入 YAML,仅适合演示。生产环境建议将密钥放入 Kubernetes Secret,再以env.valueFrom.secretKeyRef方式注入容器,避免凭据随清单泄露; - 镜像版本:示例使用
minio/minio:latest,便于复现。生产环境建议固定到明确的稳定版本标签(tag),保证集群内各节点镜像一致、可追溯; - 资源与可用性:生产环境建议为容器补充
resources.requests/limits(CPU/内存)声明,并为minio容器配置就绪/存活探针(readinessProbe / livenessProbe),让负载均衡与故障恢复更精准; - 副本数与纠删码:分布式示例固定为 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
相关推荐
在 Kubernetes 上部署 Spark Standalone 集群:基于 kubernetes-handbook 的 Master、Worker 与 Zeppelin 完整实战指南
在 Kubernetes 上部署 Spark Standalone 集群:基于 kubernetes handbook 的 Master、Worker 与 Ze
教程云原生容器编排6 步解除 Wand 2 小时限制:Wand-Enhancer 自建补丁完整指南
6 步解除 Wand 2 小时限制:Wand Enhancer 自建补丁完整指南 Wand 免费版每次只给 2 小时游戏时间,AI 攻略还藏在付费墙后面。Wan
桌面应用前端Kubernetes Handbook:基于 Rook 在 Kubernetes 上编排部署 Ceph 分布式存储的完整实战指南
Kubernetes Handbook:基于 Rook 在 Kubernetes 上编排部署 Ceph 分布式存储的完整实战指南 本指南以 practice/r
教程云原生容器编排
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考