K8s中部署Minio集群 如何部署minio集群

接上文:https://blog.csdn.net/soso678/article/details/153775348?spm=1001.2014.3001.5501

上文介绍了minio的原理,下面我将详细介绍在 Kubernetes 中手动部署 MinIO 集群的完整步骤.

MinIO 有两个最主要的默认端口:

端口号 协议 用途 说明
9000 HTTP API 端口 这是最核心的端口。 应用程序通过这个端口与 MinIO 服务进行通信,执行上传、下载、删除等所有 S3 操作。
9001 HTTP 控制台端口(Web UI) 通过这个端口可以访问 MinIO 的 Web 管理界面,用于管理用户、策略、存储桶和监控等。

由于我们正常部署minlo集群最少需要四个节点,每个节点均有独立的磁盘。本次部署在k8s集群中分别给四个节点添加了磁盘,用于制作pv作为minlo的存储。

首先先对四个节点的磁盘进行格式化并挂载使用

ini 复制代码
[root@master ~]# mkfs.ext4 /dev/nvme0n2
[root@node01 ~]# mkfs.ext4 /dev/nvme0n2
[root@node02 ~]# mkfs.ext4 /dev/nvme0n2
[root@node03 ~]# mkfs.ext4 /dev/nvme0n2
[root@master ~]# mkdir /mnt/data
[root@node01 ~]# mkdir /mnt/data
[root@node02 ~]# mkdir /mnt/data
[root@node03 ~]# mkdir /mnt/data

[root@master ~]# cat /etc/fstab
UUID=8bed5399-5358-44d3-a120-41c1265858e7 /mnt/data     ext4 defaults 0 0
[root@node01 ~]# cat /etc/fstab
UUID=42f78c55-0a16-4562-a78b-92c073c38054 /mnt/data     ext4 defaults 0 0
[root@node02 ~]# cat /etc/fstab
UUID=319ea715-c68f-4aef-8d54-546e0f30a54a /mnt/data     ext4 defaults 0 0
[root@node03 ~]# cat /etc/fstab
UUID=f889447e-9c9a-4863-8b92-2611d99abd43 /mnt/data     ext4     defaults        0 0

制作本地持久卷(Local PV)

为每个节点创建 PV

ini 复制代码
[root@master ~]# mkdir minio
[root@master ~]# cd minio/
[root@master minio]# cat minio-pv.yml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: minio-pv-0
  labels:
    type: local
    app: minio
spec:
  capacity:
    storage: 18Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  local:
    path: /mnt/data  #节点上的实际路径
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - master   #替换为实际节点名
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: minio-pv-1
  labels:
    type: local
    app: minio
spec:
  capacity:
    storage: 18Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  local:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node01
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: minio-pv-2
  labels:
    type: local
    app: minio
spec:
  capacity:
    storage: 18Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  local:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node02
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: minio-pv-3
  labels:
    type: local
    app: minio
spec:
  capacity:
    storage: 18Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  local:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node03
          
[root@master minio]# kubectl apply -f minio-pv 
persistentvolume/minio-pv-0 created
persistentvolume/minio-pv-1 created
persistentvolume/minio-pv-2 created
persistentvolume/minio-pv-3 created

[root@master minio]# kubectl get pv 
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
minio-pv-0   18Gi       RWO            Retain           Available                          <unset>                          5m7s
minio-pv-1   18Gi       RWO            Retain           Available                          <unset>                          5m7s
minio-pv-2   18Gi       RWO            Retain           Available                          <unset>                          5m7s
minio-pv-3   18Gi       RWO            Retain           Available                          <unset>                          5m7s

创建命名空间

ini 复制代码
[root@master minlo]# vim minio-namespace.yml
apiVersion: v1
kind: Namespace
metadata:
  name: minio
  labels:
    name: minio
    
[root@master minio]# kubectl apply -f minio-namespace.yml 
namespace/minio created
[root@master minio]# kubectl get ns | grep minio
minio              Active   7s

创建secret

设置管理员用户与密码

ini 复制代码
[root@master ~]# echo -n "minioadmin" | base64
bWluaW9hZG1pbg==
[root@master ~]# echo -n "minioadmin123" | base64
bWluaW9hZG1pbjEyMw==

[root@master minio]# cat minio-secret.yml 
apiVersion: v1
kind: Secret
metadata:
  name: minio-secret
  namespace: minio
type: Opaque
data:
  rootuser: bWluaW9hZG1pbg==
  rootpassword: bWluaW9hZG1pbjEyMw==
  
[root@master minio]# kubectl apply -f minio-secret 
secret/minio-secret created
[root@master minio]# kubectl get secret -n minio
NAME           TYPE     DATA   AGE
minio-secret   Opaque   2      7s

创建 Headless Service

用于集群内部访问,现在用了DNS的方式,minio-{0...3}.minio-service.minio.svc.cluster.local,因为StatefulSet的DNS别名是...svc.cluster.local

ini 复制代码
[root@master minio]# cat minio-headless-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: minio-service
  namespace: minio
  labels:
    app: minio
spec:
  clusterIP: None  # Headless Service
  ports:
  - port: 9000
    name: minio-api
    targetPort: 9000
  - port: 9001
    name: minio-console
    targetPort: 9001
  selector:
    app: minio
  publishNotReadyAddresses: true  # 重要:发布未就绪的地址:当 Pod 启动中/未就绪时,仍将其 IP 加入 Service 的 DNS 记录
  
[root@master minio]# kubectl apply -f minio-headless-service.yaml 
service/minio-service created
[root@master minio]# kubectl get svc -n minio
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)             AGE
minio-service   ClusterIP   None         <none>        9000/TCP,9001/TCP   12s

参数解释:

ini 复制代码
publishNotReadyAddresses: true  #当 Pod 启动中/未就绪时,仍将其 IP 加入 Service 的 DNS 记录

典型场景:StatefulSet 部署的 MinIO 集群需要节点间直接通信(如分布式配置同步)
默认行为 (false) 会等待 Pod 进入 Ready 状态才注册 DNS

创建 StatefulSet用于管理minio集群

ini 复制代码
[root@master minio]# cat minio-statefulset.yml 
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: minio
  namespace: minio
spec:
  serviceName: minio-service
  replicas: 4
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
      - name: minio
        image: minio/minio:RELEASE.2023-10-25T06-33-25Z
        command:
        - /bin/bash
        - -c
        args:
        - minio server --console-address ":9001" http://minio-{0...3}.minio-service.minio.svc.cluster.local/data #指定启动集群命令
        env:
        - name: MINIO_ROOT_USER
          valueFrom:
            secretKeyRef:
              name: minio-secret
              key: rootuser
        - name: MINIO_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: minio-secret
              key: rootpassword
        ports:
        - containerPort: 9000
          name: minio
        - containerPort: 9001
          name: console
        volumeMounts:
        - name: data
          mountPath: /data
        livenessProbe:
          httpGet:
            path: /minio/health/live
            port: 9000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /minio/health/ready
            port: 9000
          initialDelaySeconds: 30
          periodSeconds: 10
      affinity:
       podAntiAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                     - minio
              topologyKey: kubernetes.io/hostname
      tolerations:
        - key: "node-role.kubernetes.io/control-plane"
          operator: "Exists"
          effect: "NoSchedule"
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 18Gi
          
[root@master minio]# kubectl apply -f minio-stateflset.yml
[root@master minio]# kubectl get pod -n minio -o wide 
NAME      READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATESminio-0   1/1     Running   0          4m20s   10.244.219.104   master   <none>           <none>
minio-1   1/1     Running   0          3m43s   10.244.196.132   node01   <none>           <none>
minio-2   1/1     Running   0          3m9s    10.244.140.116   node02   <none>           <none>
minio-3   1/1     Running   0          2m35s   10.244.186.226   node03   <none>           <none>

[root@master minio]# kubectl get pod,pv,pvc -n minio -o wide 
NAME          READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
pod/minio-0   1/1     Running   0          4m53s   10.244.219.104   master   <none>           <none>
pod/minio-1   1/1     Running   0          4m16s   10.244.196.132   node01   <none>           <none>
pod/minio-2   1/1     Running   0          3m42s   10.244.140.116   node02   <none>           <none>
pod/minio-3   1/1     Running   0          3m8s    10.244.186.226   node03   <none>           <none>

NAME                          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE   VOLUMEMODE
persistentvolume/minio-pv-0   18Gi       RWO            Retain           Bound    minio/data-minio-0                  <unset>                          18m   Filesystem
persistentvolume/minio-pv-1   18Gi       RWO            Retain           Bound    minio/data-minio-1                  <unset>                          18m   Filesystem
persistentvolume/minio-pv-2   18Gi       RWO            Retain           Bound    minio/data-minio-2                  <unset>                          18m   Filesystem
persistentvolume/minio-pv-3   18Gi       RWO            Retain           Bound    minio/data-minio-3                  <unset>                          18m   Filesystem

NAME                                 STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE   VOLUMEMODE
persistentvolumeclaim/data-minio-0   Bound    minio-pv-0   18Gi       RWO                           <unset>                 22m   Filesystem
persistentvolumeclaim/data-minio-1   Bound    minio-pv-1   18Gi       RWO                           <unset>                 17m   Filesystem
persistentvolumeclaim/data-minio-2   Bound    minio-pv-2   18Gi       RWO                           <unset>                 14m   Filesystem
persistentvolumeclaim/data-minio-3   Bound    minio-pv-3   18Gi       RWO                           <unset>                 11m   Filesystem

创建service暴露端口

本案例使用的是LoadBalancer暴露的服务,由于我们使用的是虚拟机搭建的k8s并没有云环境所以在本地先部署了metalLB服务,同时大家也可以考虑使用nodePort来暴露服务。
LoadBalancer外部负载均衡器 + NodePort 的组合,通过外部负载均衡器(如云厂商的 ELB、裸机的 MetalLB)将流量转发到集群节点的 NodePort,最终路由到 Pod.

ini 复制代码
[root@master minio]# cat minio-external-svc.yml 
apiVersion: v1
kind: Service
metadata:
  name: minio-external
  namespace: minio
  annotations:
    # 使用MetalLB
    metallb.universe.tf/address-pool: "first-pool" #指定使用的地址池名称
spec:
  type: LoadBalancer #服务类型:LoadBalancer(触发外部负载均衡器,如 MetalLB 或云厂商 LB)
  loadBalancerIP: 192.168.209.151 # 可选:从池里面指定静态IP,若不指定,MetalLB 会从 address-pool中自动分配一个 IP)。
  ports:
  - port: 9000
    targetPort: 9000
    name: api
    protocol: TCP
  - port: 9001
    targetPort: 9001
    name: console
    protocol: TCP
  selector:
    app: minio
  sessionAffinity: ClientIP # 会话亲和性策略:根据客户端 IP 路由流量(同一客户端始终访问同一 Pod)
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800 # 会话保持时间(单位:秒,此处为 3 小时)
      
[root@master minio]# kubectl apply -f minio-external-svc.yml 
service/minio-external created

[root@master minio]# kubectl get svc -n minio 
NAME             TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)                         AGE
minio-external   LoadBalancer   10.99.181.219   192.168.209.151   9000:31776/TCP,9001:32006/TCP   29m
minio-service    ClusterIP      None           <none>            9000/TCP,9001/TCP               90m
ini 复制代码
10.99.181.219:为clusterIP
192.168.209.151: 为ExteneralIP
9000/9001端口:为Port端口
31776/32006端口: 我们没有指定节点端口,但是创建完之后自动启动了31776/32006节点端口 ,其类型为NodePort端口(因为 LoadBanlance类型其实就是基于NodePort类型的扩展

LoadBalancer基于nodeport,在创建LoadBalancer的时候会自动创建nodeport的端口。访问的时候可以通过以下方式访问:

ini 复制代码
方式一:
通过使用 NodePort 的方式来访问服务(节点 IP+节点端口);
NodeIP:NodePort
方式二:
同时也 可以通过 EXTERNAL-IP 来访问 
External-IP:port
访问方式三:
ClusterIP:port

测试访问

安装客户端命令

ini 复制代码
[root@master ~]# wget https://dl.min.io/client/mc/release/linux-amd64/mc
[root@master ~]# chmod +x mc 
[root@master ~]# mv mc /usr/local/bin/

设置别名后续操作用此名称指代服务
[root@master ~]# mc alias set myminio http://192.168.209.151:9001 你的AK 你的SK 

mc: Configuration written to `/root/.mc/config.json`. Please update your access credentials.
mc: Successfully created `/root/.mc/share`.
mc: Initialized share uploads `/root/.mc/share/uploads.json` file.
mc: Initialized share downloads `/root/.mc/share/downloads.json` file.
Added `myminio` successfully.

上传
[root@master ~]# mc cp pull.sh myminio/test #指定桶名
/root/pull.sh:           593 B / 593 B ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 3.50 KiB/s 0s
相关推荐
布朗克1684 小时前
MySQL 及 SQL 注入详细说明
数据库·sql·mysql·1024程序员节
荣光波比4 小时前
Prometheus(二)—— 在K8s集群中部署Prometheus+Grafana+AlertManager实现全方位监控
kubernetes·grafana·prometheus
wkj0015 小时前
安装了conda和uv如何创建一个项目?
chrome·conda·uv·1024程序员节
菜鸟una5 小时前
【微信小程序 + 消息订阅 + 授权】 微信小程序实现消息订阅流程介绍,代码示例(仅前端)
前端·vue.js·微信小程序·小程序·typescript·taro·1024程序员节
papership6 小时前
【入门级-算法-5、数值处理算法:高精度的减法】
算法·1024程序员节
好好研究7 小时前
JAVAEE知识整理之AJAX、JSON
ajax·java-ee·json·1024程序员节
隔壁程序员老王7 小时前
基于 Python 的坦克大战小程序,使用 Pygame 库开发
python·小程序·pygame·1024程序员节
程序猿阿伟8 小时前
《3D手游云原生开发:关键难题突破日志》
3d·云原生
F_D_Z8 小时前
SkyDiffusion:用 BEV 视角打开街景→航拍图像合成新范式
diffusion·sota·1024程序员节·bev·skydiffusion·视角变换·多图融合