---
# System prepended metadata

title: MinIO & s3fs & Directpv
tags: [K8S]

---

# MinIO & s3fs & Directpv
* 透過 s3fs 搭配 DaemonSet 會將 minio 的 Buckets 掛載到每一台 node 上的目錄區，因此後續 pod 就可以透過 hostpath 使用 volume，並且允許漂移到不同節點上。
* minio 實際會透過 Directpv 存储，直接將資料寫到硬碟。 


## 事前準備
* 需準備 1m2w k8s cluster，本次範例 k8s 架構 1m3w
* 每台 worker node 需要額外再加兩顆 Disk
## 部屬 Directpv
* Directpv 目的就是要來取代 hostpath，讓資料可以直接儲存到 Disk(SSD、Nvme)，可以提高 IO 效能。
* 主要提供給物件儲存、資料庫和需要高效能環境而設計的。
![image](https://hackmd.io/_uploads/HkAlpZxJC.png)
* 安裝 krew
```
$ curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/download/v0.4.4/krew-linux_amd64.tar.gz"
      
$ tar zxvf krew-linux_amd64.tar.gz 

$ ./krew-linux_amd64 install krew 

$ echo 'export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"' | sudo tee -a /etc/profile

$ rm krew-linux_amd64.tar.gz krew-linux_amd64 LICENSE
```
* 重新 login 後測試
```
$ kubectl krew
krew is the kubectl plugin manager.
You can invoke krew through kubectl: "kubectl krew [command]..."

Usage:
  kubectl krew [command]

Available Commands:
  help        Help about any command
  index       Manage custom plugin indexes
  info        Show information about an available plugin
  install     Install kubectl plugins
  list        List installed kubectl plugins
  search      Discover kubectl plugins
  uninstall   Uninstall plugins
  update      Update the local copy of the plugin index
  upgrade     Upgrade installed plugins to newer versions
  version     Show krew version and diagnostics

Flags:
  -h, --help      help for krew
  -v, --v Level   number for the log level verbosity

Use "kubectl krew [command] --help" for more information about a command.
```
* 透過 krew 安裝 directpv plugin
```
$ kubectl krew install directpv
```
* 安裝 directpv 到 k8s
```
$ kubectl directpv install
```
* 顯示安裝完成畫面
```
$ kubectl directpv info
```
* directpv 運作流程
![image](https://hackmd.io/_uploads/SJ9_QNZyC.png)
```
# 可自行調整 controller 數量
$ kubectl -n directpv get all
NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-58df549f48-d288q   3/3     Running   0          178m
pod/controller-58df549f48-mqr9g   3/3     Running   0          178m
pod/controller-58df549f48-s8xnd   3/3     Running   0          178m
pod/node-server-7zhz9             4/4     Running   0          178m
pod/node-server-f9l2k             4/4     Running   0          178m
pod/node-server-ljpgh             4/4     Running   0          178m
pod/node-server-zpww7             4/4     Running   0          178m

NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/node-server   4         4         4       4            4           <none>          178m

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   3/3     3            3           178m

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-58df549f48   3         3         3       178m


$ kubectl get sc
NAME                 PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
directpv-min-io      directpv-min-io         Delete          WaitForFirstConsumer   true                   3h
```
* 檢查 DirectPV discover driver
```
$ kubectl directpv discover --nodes=cilium-w{1...3} --drives=sd{b...f}

 Discovered node 'cilium-w3' ✔
 Discovered node 'cilium-w1' ✔
 Discovered node 'cilium-w2' ✔

┌─────────────────────┬───────────┬───────┬────────┬────────────┬────────────────────┬───────────┬─────────────┐
│ ID                  │ NODE      │ DRIVE │ SIZE   │ FILESYSTEM │ MAKE               │ AVAILABLE │ DESCRIPTION │
├─────────────────────┼───────────┼───────┼────────┼────────────┼────────────────────┼───────────┼─────────────┤
│ 8:48$jHViBmYbA0Q... │ cilium-w1 │ sdd   │ 30 GiB │ -          │ QEMU QEMU_HARDDISK │ YES       │ -           │
│ 8:64$fW3WQftFoXo... │ cilium-w1 │ sde   │ 30 GiB │ -          │ QEMU QEMU_HARDDISK │ YES       │ -           │
│ 8:32$QQwAiXmZknC... │ cilium-w2 │ sdc   │ 30 GiB │ -          │ QEMU QEMU_HARDDISK │ YES       │ -           │
│ 8:48$NKcJ3N3TaE8... │ cilium-w2 │ sdd   │ 30 GiB │ -          │ QEMU QEMU_HARDDISK │ YES       │ -           │
│ 8:16$EHcAYec/Wa7... │ cilium-w3 │ sdb   │ 30 GiB │ -          │ QEMU QEMU_HARDDISK │ YES       │ -           │
│ 8:32$xrd5+hDeqje... │ cilium-w3 │ sdc   │ 30 GiB │ -          │ QEMU QEMU_HARDDISK │ YES       │ -           │
└─────────────────────┴───────────┴───────┴────────┴────────────┴────────────────────┴───────────┴─────────────┘

Generated 'drives.yaml' successfully.
```
* DirectPV add driver
```
$ cat drives.yaml
version: v1
nodes:
    - name: cilium-w1
      drives:
        - id: 8:64$fW3WQftFoXorsSbSQFO4UvvRi6OqxYkAe+Bxa/F41PY=
          name: sde
          size: 32212254720
          make: QEMU QEMU_HARDDISK
          select: "yes"
        - id: 8:48$jHViBmYbA0Q3zrvycywUHNO6SuGJCHclmeBVwHeHVXk=
          name: sdd
          size: 32212254720
          make: QEMU QEMU_HARDDISK
          select: "yes"
    - name: cilium-w2
      drives:
        - id: 8:48$NKcJ3N3TaE8/14aOuJeeqrjLmf3y4sgWFO3L0dm7EbQ=
          name: sdd
          size: 32212254720
          make: QEMU QEMU_HARDDISK
          select: "yes"
        - id: 8:32$QQwAiXmZknCllNQJfYoTt4AxcUIR4EsNl6MCJ5nJIQk=
          name: sdc
          size: 32212254720
          make: QEMU QEMU_HARDDISK
          select: "yes"
    - name: cilium-w3
      drives:
        - id: 8:32$xrd5+hDeqje4AlsYeMKeAu840b3FOoPnfZQ7ZsVrRYQ=
          name: sdc
          size: 32212254720
          make: QEMU QEMU_HARDDISK
          select: "yes"
        - id: 8:16$EHcAYec/Wa76OFbhSSWRMDf0jFdw+t+uKiWGv86tD5Q=
          name: sdb
          size: 32212254720
          make: QEMU QEMU_HARDDISK
          select: "yes"
```
* 加入 driver
```
$ kubectl directpv init --dangerous drives.yaml

 ███████████████████████████████████████████████████████████████████████████ 100%

 Processed initialization request '72cc955c-2b29-4618-9974-d70385305aa9' for node 'cilium-w1' ✔
 Processed initialization request 'fdc82163-3109-4e1e-8bdf-5a753f4db4b7' for node 'cilium-w2' ✔
 Processed initialization request '72e8fd44-408b-4cbc-a473-e745d5525828' for node 'cilium-w3' ✔

┌──────────────────────────────────────┬───────────┬───────┬─────────┐
│ REQUEST_ID                           │ NODE      │ DRIVE │ MESSAGE │
├──────────────────────────────────────┼───────────┼───────┼─────────┤
│ 72cc955c-2b29-4618-9974-d70385305aa9 │ cilium-w1 │ sdd   │ Success │
│ 72cc955c-2b29-4618-9974-d70385305aa9 │ cilium-w1 │ sde   │ Success │
│ fdc82163-3109-4e1e-8bdf-5a753f4db4b7 │ cilium-w2 │ sdc   │ Success │
│ fdc82163-3109-4e1e-8bdf-5a753f4db4b7 │ cilium-w2 │ sdd   │ Success │
│ 72e8fd44-408b-4cbc-a473-e745d5525828 │ cilium-w3 │ sdb   │ Success │
│ 72e8fd44-408b-4cbc-a473-e745d5525828 │ cilium-w3 │ sdc   │ Success │
└──────────────────────────────────────┴───────────┴───────┴─────────┘
```
* 列出 directpv 使用的 driver
```
$ kubectl directpv list drives
┌───────────┬──────┬────────────────────┬────────┬────────┬─────────┬────────┐
│ NODE      │ NAME │ MAKE               │ SIZE   │ FREE   │ VOLUMES │ STATUS │
├───────────┼──────┼────────────────────┼────────┼────────┼─────────┼────────┤
│ cilium-w1 │ sdd  │ QEMU QEMU_HARDDISK │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ cilium-w1 │ sde  │ QEMU QEMU_HARDDISK │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ cilium-w2 │ sdc  │ QEMU QEMU_HARDDISK │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ cilium-w2 │ sdd  │ QEMU QEMU_HARDDISK │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ cilium-w3 │ sdb  │ QEMU QEMU_HARDDISK │ 30 GiB │ 30 GiB │ -       │ Ready  │
│ cilium-w3 │ sdc  │ QEMU QEMU_HARDDISK │ 30 GiB │ 30 GiB │ -       │ Ready  │
└───────────┴──────┴────────────────────┴────────┴────────┴─────────┴────────┘
```
* 移除 Driver
```
$ kubectl directpv remove --drives=sdd --nodes=cilium-w1
Removing cilium-w1/sdd

$ kubectl directpv remove --drives=sde --nodes=cilium-w1
Removing cilium-w1/sde

$ kubectl directpv remove --drives=sdc --nodes=cilium-w2
Removing cilium-w2/sdc

$ kubectl directpv remove --drives=sdd --nodes=cilium-w2
Removing cilium-w2/sdd

$ kubectl directpv remove --drives=sdb --nodes=cilium-w3
Removing cilium-w3/sdb

$ kubectl directpv remove --drives=sdc --nodes=cilium-w3
Removing cilium-w3/sdc
```
## 部屬 minio
* 使用 Statefulset 部屬 minio，會部署在 `kube-system` namespace
* 因為有 cpu 版本的問題所以選 cpuv1 這個版本的 image
* 需先安裝好 metallb，`loadBalancerIP` 需換成自己環境的網段
* minio-job 負責在 minio 建立 fbs、mysql 的 Buckets
```
apiVersion: v1
kind: Service
metadata:
  name: svc-stsminio
  namespace: kube-system
spec:
  type: LoadBalancer
  allocateLoadBalancerNodePorts: false
  loadBalancerIP: 192.168.11.145                 # change
  ports:
    - port: 9000
      targetPort: 9000
      protocol: TCP
      name: mc
    - port: 9001
      targetPort: 9001
      protocol: TCP
      name: mcweb
  selector:
    app: stsminio
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: stsminio
  namespace: kube-system
  labels:
    app: stsminio
spec:
  serviceName: "svc-stsminio"
  replicas: 2
  podManagementPolicy: "Parallel"
  selector:
    matchLabels:
      app: stsminio
  template:
    metadata:
      labels:
        app: stsminio
    spec:
      containers:
      - name: stsminio
        image: quay.io/minio/minio:RELEASE.2023-11-01T01-57-10Z-cpuv1
        volumeMounts:
        - name: minio-data0
          mountPath: /data0
        - name: minio-data1
          mountPath: /data1
        args:
        # Change this according to No. of replicas, namespace and volumes
        - server
        - --console-address
        - :9001
        - http://stsminio-{0...1}.svc-stsminio.kube-system.svc.cluster.local/data{0...1}
        env:
        # MinIO access key and secret key
        - name: MINIO_ACCESS_KEY
          value: "minio"
        - name: MINIO_SECRET_KEY
          value: "minio123"
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /minio/health/live
            port: http
            scheme: HTTP
          initialDelaySeconds: 120
          periodSeconds: 15
          successThreshold: 1
          timeoutSeconds: 10
        ports:
        - containerPort: 9000
          name: mc
          protocol: TCP
        - containerPort: 9001
          name: mcweb
          protocol: TCP
  volumeClaimTemplates: # This is the specification in which you reference the StorageClass
  - metadata:
      name: minio-data0
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 20Gi
      storageClassName: directpv-min-io
  - metadata:
      name: minio-data1
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 20Gi
      storageClassName: directpv-min-io
---
apiVersion: batch/v1
kind: Job
metadata:
  name: minio-job
  namespace: kube-system
spec:
  # If the field is set to 0, the Job will be eligible to be automatically deleted immediately
  # after it finishes.
  ttlSecondsAfterFinished: 0
  template:
    metadata:
      name: minio-job
    spec:
      containers:
      - name: minio-job
        image: docker.io/taiwanese/alp.mc.rclone.s3fs
        tty: true
        command: ["sh", "-c"]
        args:
        - |
          sleep 60
          mc config host add tk8s http://svc-stsminio.kube-system:9000 minio minio123
          mc admin config set tk8s storage_class standard=EC:1
          mc mb tk8s/fbs
          sleep 30
      restartPolicy: Never
```
* 登入 minio web
![image](https://hackmd.io/_uploads/HJKD_r-yA.png)
* 已經建立好 fbs、mysql Buckets
![image](https://hackmd.io/_uploads/rkYK_rWJC.png)

* 安裝 mc CLI
```
$ sudo curl https://dl.min.io/client/mc/release/linux-amd64/mc --create-dirs -o /usr/local/bin/mc

$ sudo chmod +x /usr/local/bin/mc
```
* 檢視 minio url
```
$ mc config host ls
gcs
  URL       : https://storage.googleapis.com
  AccessKey : YOUR-ACCESS-KEY-HERE
  SecretKey : YOUR-SECRET-KEY-HERE
  API       : S3v2
  Path      : dns

local
  URL       : http://localhost:9000
  AccessKey :
  SecretKey :
  API       :
  Path      : auto

play
  URL       : https://play.min.io
  AccessKey : Q3AM3UQ867SPQQA43P2F
  SecretKey : zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG
  API       : S3v4
  Path      : auto

s3
  URL       : https://s3.amazonaws.com
  AccessKey : YOUR-ACCESS-KEY-HERE
  SecretKey : YOUR-SECRET-KEY-HERE
  API       : S3v4
  Path      : dns

tk8s
  URL       : http://192.168.11.145:9000
  AccessKey : minio
  SecretKey : minio123
  API       : s3v4
  Path      : auto
```
* 登入 minio 並測試上傳資料到 minio
```
$ mc alias set tk8s http://192.168.11.145:9000 minio minio123
Added `tk8s` successfully.

$ mc ls tk8s
[2024-03-27 15:17:06 CST]     0B fbs/

$ echo 123 > test.txt

$ mc cp test.txt tk8s/fbs/
/home/rancher/test.txt:               4 B / 4 B ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 37 B/s 0s

$ mc ls tk8s/fbs/
[2024-03-25 10:12:43 CST]     4B STANDARD test.txt

# 刪除在 fbs 下的 test.txt 檔案 
$ mc rm tk8s/fbs/test.txt
Removed `tk8s/fbs/test.txt`.
```
## 部屬 s3fs
* `mountPropagation: Bidirectional` 對 container 內的磁碟區所做的變更會反映在主機中。
```
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: minio-s3fs
  name: minio-s3fs
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: minio-s3fs
  template:
    metadata:
      labels:
        app: minio-s3fs
    spec:
      containers:
      - name: s3fs
        image: docker.io/taiwanese/alp.s3fs.mc
        tty: true
        lifecycle:
          postStart:
            exec:
              command:
                - /bin/bash
                - -c
                - |
                  sleep 120
                  echo 'minio:minio123' > /tmp/.passwd-s3fs
                  chmod 600 /tmp/.passwd-s3fs
                  echo 'user_allow_other' >> /etc/fuse.conf
                  s3fs fbs /opt/fbs -o allow_other -o passwd_file=/tmp/.passwd-s3fs -o url=http://svc-stsminio.kube-system:9000 -o use_path_request_style -o dbglevel=info -o curldbg &>/dev/null &
          preStop:
            exec:
              command: 
                - /bin/bash"
                - -c
                - |
                  umount -f /opt/fbs
        securityContext:
          privileged: true
        volumeMounts:
        - name: fbs    
          mountPath: /opt/fbs
          mountPropagation: Bidirectional
      volumes:
      - name: fbs
        hostPath:
          path: /opt/fbs
```


## 測試 File Browser
* 建立 File Browser
* 使用 hostPath volume
```
kind: Deployment
apiVersion: apps/v1
metadata:
  name: fbs
  labels: 
    app: fbs
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fbs
  template:
    metadata:
      labels:
        app: fbs
    spec:
      containers:
      - name: fbs
        image: taiwanese/alp.fbs
        ports:
        - containerPort: 4000
        volumeMounts:
        - mountPath: /srv
          name: fbs-volume
      volumes:
      - name: fbs-volume
        hostPath:
          # directory location on host
          path: /opt/fbs
---
kind: Service
apiVersion: v1
metadata:
  name: svc-fbs
spec:
  type: NodePort
  selector:
    app: fbs
  ports:
  - port: 8080
    targetPort: 4000
```
* 使用 nodeport 放式登入
> 帳號:admin
> 密碼:admin

* 在 File Browser 丟入一個檔案
![image](https://hackmd.io/_uploads/SJ-7BwCC6.png)

* 測試 pod 移轉 node，資料是否永存
```
$ kubectl get po -owide
NAME                               READY   STATUS    RESTARTS      AGE     IP            NODE        NOMINATED NODE   READINESS GATES
fbs-6fb5b97d98-q72rg               1/1     Running   0             11m     10.42.1.15    cilium-w1   <none>           <none>

$ kubectl scale deploy fbs --replicas=0

$ kubectl cordon cilium-w1

$ kubectl scale deploy fbs --replicas=1

$ kubectl uncordon cilium-w1

$ kubectl get po -owide
NAME                               READY   STATUS    RESTARTS      AGE     IP            NODE        NOMINATED NODE   READINESS GATES
fbs-6fb5b97d98-n252x               1/1     Running   0             31s     10.42.2.250   cilium-w2   <none>           <none>
```
* 再次進入 File Browser 檢查，透過 minio 可以讓掛載 hostpath 做到共享不同主機的目錄
![image](https://hackmd.io/_uploads/Byw88DC06.png)

## 參考連結
https://github.com/minio/directpv

