MinIO Operatorを使ってMinIOを立てる

MinIO Operatorを使ってMinIOを立てた時のメモ。
Veleroが必要な人なんかはご参考にしていただければ。

## MinIOとは
MinIOはローカル環境などに自前で立てることが出来るオブジェクトストレージストアで、S3互換APIを持っている。
そのため、S3ストレージが用意しにくいオンプレミス環境などで検証する際などには非常にお世話になるOSSである。

昔はyamlを適当にapplyすればインストール出来たのだが、最近はOperatorを挟むようになって高機能になった分少し面倒になった。

大まかな利用手順は以下となる。
1. MinIO Operatorの導入
2. テナントの作成
3. バケットの作成

ここからの手順は複数NodeからなるKubernetesクラスタが既にある状態を前提とする。
また、以下も実施するが、適宜スキップしたり読み替えて欲しい。
- External IPを使ってサービスを外部公開する
- Tanzu Kubernetes Cluster（vSphere with Tanzuのクラスタ）向けにPSPを設定する

なお、「複数Node」と書いているのは複数Nodeが前提となっているためであり、単一Node構成だとMinio OperatorのPodがいつまでもPendingでデプロイされずに先に進めないので注意（[こちらのIssue](https://github.com/minio/operator/issues/1252)も参照）。


## MinIO Operatorの導入
MinIOのインストーラはkubectlのpluginとして提供されているため、pluginをインストールする。
[krew](https://krew.sigs.k8s.io/docs/user-guide/)をインストールしていない人は以下を実行してインストールする。
```sh
(
  set -x; cd "$(mktemp -d)" &&
  OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
  ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
  KREW="krew-${OS}_${ARCH}" &&
  curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
  tar zxvf "${KREW}.tar.gz" &&
  ./"${KREW}" install krew
)
```
krewが使えるようになったら、以下を実行してMinIOのpluginをインストールする。
```
kubectl krew update
kubectl krew install minio
```
インストール後、以下のコマンドを実行してバージョンが表記されればインストールは正常に出来ている。
```
kubectl minio version
```

pluginのインストールが終わったら、Operatorをインストールする。
```
kubectl minio init
```
上記のコマンドを実行すると、`minio-operator`というNamespaceが作成され、以下のようにPodが作成される。(なお、Namespaceの変更などはオプションで可能だが、今回は割愛する)
```
$ kubectl get pod -n minio-operator
NAME                              READY   STATUS    RESTARTS   AGE
console-68fb58cbcb-84gx9          1/1     Running   0          20h
minio-operator-6b8b678c66-jt9ff   1/1     Running   0          20h
minio-operator-6b8b678c66-rf5rj   1/1     Running   0          20h
```
なお、Tanzu Kubernetes Cluster（vSphere with Tanzuのクラスタ）だとデフォルトで権限が不足してPodが起動しない。その場合はminio-operator Namespace内のServiceAccountに権限を付与する。
```yaml
cat << EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-minio-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: minio-operator
  namespace: minio-operator
- kind: ServiceAccount
  name: console-sa
  namespace: minio-operator
EOF
```
権限付与後、ReplicaSetを削除すればPodが正常に作成される。
```
kubectl delete rs -n minio-operator --all
```


## テナントの作成
先にテナント展開用のNamespaceを作成しておく。
```
kubectl create ns velero-tenant
```

次にGUIで操作していく。デフォルトでテナント作成用のコンソール画面のServiceは`Type:LoadBalancer`で公開されている模様。
```
$ kubectl get svc -n minio-operator
NAME       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                         AGE
console    LoadBalancer   10.98.212.154   10.220.14.117   9090:31881/TCP,9443:30258/TCP   21h
operator   ClusterIP      10.100.37.245   <none>          4222/TCP,4221/TCP               21h
```
ExternalIPのPort9090(ここではhttp://10.220.14.117:9090となる)にアクセスする。

![1668565638136.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/1421a596-28bf-e1be-aedf-fbdac9218ff8.png)

"Enter JWT”の箇所には以下のコマンドで取得できるTokenを指定する。
```
kubectl minio proxy
```
なお、コマンド実行後PortForwardを始めるが、無視してコマンドはCtrl+Cなどで強制終了して問題ない。

ログイン後、右上の"Create Tenant"をクリックする。
色々な設定項目があるが、`Name`、`Namespace`、`Number of Servers`、`Total Size`が埋まっていればテナント作成は出来るので、必要項目だけ埋める。
ここでは以下のように設定した。デフォルトのサイズが大きいので、ここだけは見直しておいた方がよさそう。

![1668566368952.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/7f9e9f58-1723-51de-6657-a92a6abbe57e.png)


なお、デフォルトでTLSが有効化され、オレオレ証明書が作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/5721c125-8b61-e280-4769-69275a9a813f.png)

Velero用途でMinIOを使う場合、オレオレでTLSが有効化されているとインストールやバックアップに失敗する可能性がある（`--insecure-sklip-tls-verify`オプションが[ある](https://velero.io/docs/main/self-signed-certificates/#skipping-tls-verification)が、サポートされたのが新しめ）。Veleroの検証用途で利用する場合はTLSをOffにすることも検討した方がよい。

Createをクリックすると、テナントへアクセスするためのAccess KeyとSecret Keyが表示されるので、大事に残しておく。
しばらくすると以下のようなリソースが作成される（全てのリソースの作成が完了するまで数分掛かる）。
```
$ kubectl get all -n velero-tenant
NAME                                                READY   STATUS    RESTARTS   AGE
pod/velero-tenant-log-0                             1/1     Running   0          97s
pod/velero-tenant-log-search-api-677556bdbf-jfcgk   1/1     Running   3          96s
pod/velero-tenant-pool-0-0                          1/1     Running   0          99s
pod/velero-tenant-pool-0-1                          1/1     Running   0          99s
pod/velero-tenant-prometheus-0                      2/2     Running   0          38s

NAME                                      TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)          AGE
service/minio                             LoadBalancer   10.109.40.11     10.220.14.120   443:30090/TCP    2m39s
service/velero-tenant-console             LoadBalancer   10.108.235.108   10.220.14.121   9443:30543/TCP   2m39s
service/velero-tenant-hl                  ClusterIP      None             <none>          9000/TCP         2m39s
service/velero-tenant-log-hl-svc          ClusterIP      None             <none>          5432/TCP         97s
service/velero-tenant-log-search-api      ClusterIP      10.96.85.93      <none>          8080/TCP         96s
service/velero-tenant-prometheus-hl-svc   ClusterIP      None             <none>          9090/TCP         38s

NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/velero-tenant-log-search-api   1/1     1            1           96s

NAME                                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/velero-tenant-log-search-api-677556bdbf   1         1         1       96s

NAME                                        READY   AGE
statefulset.apps/velero-tenant-log          1/1     98s
statefulset.apps/velero-tenant-pool-0       2/2     100s
statefulset.apps/velero-tenant-prometheus   1/1     39s
```


## バケットの作成
先程作成したテナントのリソースのうち、Serviceの`velero-tenant-console `にHTTPSでアクセスする。ExternalIPが10.220.14.121でPort9443で公開しているため、[https://10.220.14.121:9443/](https://10.220.14.121:9443/)にブラウザでアクセスする。
すると以下のようなログイン画面が表示されるので、先程保存したAccess KeyとSecret Keyを利用してログインする。

![1668573671595.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/588c01e9-ce9b-0952-3bf3-f78462828711.png)

ログイン後、右上の"Create Bucket"を選択すると、バケット作成画面が表示されるので好きな名前や設定をして"Create Bucket"を押すとバケットが作成される。

![1668573801783.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/2abc2a97-f231-2f44-f193-479a5d78e5b4.png)

## バケットへのアクセス
作成されたAccess KeyとSecret Keyが使いづらいので、先にこちらを新規に生成する。
左サイドバーから`Administrator`->`Identity`->`Users`を選択し、`Create User`をクリックして任意のものを作成する。以下の画像のようにPolicyに`consoleAdmin`もしくは適切な権限を付与することを忘れないこと。

![1668587252993.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/c670c7f6-c6cf-7018-7265-085586198ba8.png)

Passwordの長さは8文字以上である必要がある。

作成したアカウントでログインしなおすと、同じようにログインできる。

最後に、[mcコマンド](https://github.com/minio/mc)を使ってバケットにアクセスする。
Windows、Mac、Linuxともにバイナリが配布されており、インストールは容易であるためインストール方法の紹介は割愛する。

最初にmcコマンドを初期化する。`--insecure`オプションが必要な点に注意。なお、ここで指定するIPはconsoleの方ではなく、Service`minio`が公開しているIPとなる。
```
$ mc alias set velero-bucket https://10.220.14.120/ demouser demodemo123 --insecure
Added `velero-bucket` successfully.
```
正常に設定ができた場合、以下のコマンドでテナント内の情報が取得できる。
```
$ mc admin info velero-bucket --insecure
●  velero-tenant-pool-0-0.velero-tenant-hl.velero-tenant.svc.cluster.local:9000
   Uptime: 20 hours
   Version: 2022-11-11T03:44:20Z
   Network: 2/2 OK
   Drives: 2/2 OK
   Pool: 1

●  velero-tenant-pool-0-1.velero-tenant-hl.velero-tenant.svc.cluster.local:9000
   Uptime: 20 hours
   Version: 2022-11-11T03:44:20Z
   Network: 2/2 OK
   Drives: 2/2 OK
   Pool: 1

Pools:
   1st, Erasure sets: 1, Drives per erasure set: 4

0 B Used, 1 Bucket, 0 Objects
4 drives online, 0 drives offline
```
バケットにファイルを作成してみる。
```
echo "demo" > ./aaa.txt
mc cp aaa.txt velero-bucket/velero-bucket/aaa.txt --insecure
```
確認する。
```
$ mc ls velero-bucket/ --insecure -r
[2022-11-17 10:43:18 JST]     5B STANDARD velero-bucket/aaa.txt
```

GUI上からも確認できる。
![1668649490986.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0e17d840-a1da-2bae-f6f2-4cfaa75f91c1.png)

お疲れ様でした。


## おまけ：Linux上で普通に立てる

Kubernetesに立てるのが面倒な時は[こちら](https://docs.vmware.com/en/VMware-Telco-Cloud-Automation/2.2/com.vmware.tca.userguide/GUID-1AE9BC94-B8B2-4E10-A3F4-CCC753D9D95D.html)の手順に従うとLinux上に簡単に立てられる。
自動化用にスクリプト化したものを貼っておく。
```sh
#!/bin/bash
set -x
IPADDR=$(hostname -I | awk '{print $1}')
curl -O https://dl.minio.io/server/minio/release/linux-amd64/minio
sudo install minio /usr/local/bin
sudo mkdir -p /usr/local/share/minio
sudo mkdir -p /usr/local/share/minio
sudo useradd minio-user
sudo chown minio-user:minio-user /usr/local/share/minio
sudo mkdir -p /etc/minio
sudo chown minio-user:minio-user /etc/minio
cat << EOF > /tmp/minio-default
MINIO_VOLUMES="/usr/local/share/minio/"
MINIO_OPTS="-C /etc/minio --address $IPADDR:9000"
MINIO_ACCESS_KEY="minio"
MINIO_SECRET_KEY="minio123"
EOF
sudo mv /tmp/minio-default /etc/default/minio

curl -O https://raw.githubusercontent.com/minio/minio-service/master/linux-systemd/minio.service
sudo mv minio.service /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio
```

Consoleの接続先は`sudo systemctl status minio`で確認できる。

バケット作成まではこちら。
```
curl https://dl.min.io/client/mc/release/linux-amd64/mc \
  -o $HOME/mc
sudo install mc /usr/local/bin/

mc alias set minio-server http://localhost:9000 minio minio123
mc mb minio-server/mybucket
```
TLSに対応させたい場合は[公式ドキュメントの手順](https://min.io/docs/minio/linux/operations/network-encryption.html#enabling-tls)に従い以下を実施する。

　1. 自己署名証明書を作成する
　2. ファイル名を公式ドキュメントにあわせてrenameした上で適当なところに置く（ここでは`/home/ubuntu/.minio/certs`とする）
　3. minio-userが参照できるようにownerを変更する。 
```
chown -R minio-user.minio-user /home/ubuntu/.minio/certs
```
　4. `/etc/systemd/system/minio.service`を編集し、`ExecStart`を以下のように`--certs-dir`を追加した形に修正する。
```
ExecStart=/usr/local/bin/minio server --certs-dir /home/ubuntu/.minio/certs  $MINIO_OPTS $MINIO_VOLUMES
```
　5. 再起動する
```
sudo systemctl daemon-reload
sudo systemctl restart minio
```