💬

Longhornのディスクを利用するMinio S3をセットアップ

に公開

https://min.io/

MinIO is an object storage solution that provides an Amazon Web Services S3-compatible API and supports all core S3 features.

今回はオンプレミスのKubernetesクラスタ上で構築できるS3サービス、Minioをセットアップしてきます。

こちらはおうちラボ用の構築となります。複数のディスクや複数のノードで完璧なレプリケーションやバックアップを備えたS3サービスを用意するのではなく、個人利用で満足のいく、ごく簡単なものをセットアップしていきます。

これまでの流れ

  • Control plane x3, worker x3のKubernetesクラスタ構築
  • GitOpsのセットアップ(GitLab, fluxcd, sops)
    • flux-system, infra-controllers, infra-configs, sops, appsにflux kustomizationを分けてセットアップ
  • Cilium L2Announcement & Gateway + cert-managerでクラスタ外からもKubernetes上のサービスへ簡単webアクセス
  • Longhornのセットアップ、storage classよりdynamic volume provisioning

今回やること

  • Longhorn上でS3用に利用するディスクにタグ付け
  • タグ付けされたディスクからvolume provisioningするstorage classを別途作成
  • (fluxcd, HelmRepository & HelmReleaseで) minio-operatorインストール
  • minio-tenantもインストール
  • minio-tenantのダッシュボードおよびS3サービスへのアクセスをcilium gateway & cert-managerで用意
  • できたものをお試し

ドキュメント

https://min.io/docs/minio/kubernetes/upstream/index.html

デプロイメントチェックリスト

公式ドキュメントにハードウェア、セキュリティ、ソフトウェアの観点で推奨環境を記載したチェックリストがあります。プロダクションレディなものを用意するならば、という時に参考になります。

https://min.io/docs/minio/kubernetes/upstream/operations/checklists.html

いくつか条件満たした状態で構築を進めることにはなりますが、おうちラボでの構築なので基本的に最小構成でやっていきます。

Longhornシステムに載せたディスク

先のポストでworkerノードに用意した追加ディスクを利用する形でセットアップしていきます。

  • lab-worker2 with 80GB disk
  • lab-worker3 with 80GB disk

Longhorn上のディスク利用に関連して

  • "xfs"タグをlab-worker2, lab-worker3上の追加したディスクへセット
  • 推奨に沿う形で個別のstorage classを作成
  • 全ノード、全ディスクをschedule状態へ戻す (Minio S3テナントでは利用されませんが今後ほかのstorage classで利用するために)

https://min.io/docs/minio/kubernetes/upstream/operations/install-deploy-manage/deploy-minio-tenant.html#persistent-volumes

Additionally, MinIO recommends setting a reclaim policy of Retain for the PVC StorageClass. Where possible, configure the Storage Class, CSI, or other provisioner underlying the PV to format volumes as XFS to ensure best performance.

作成するstorage classはこちらとなります。

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-xfs
parameters:
  staleReplicaTimeout: "30"
  diskSelector: xfs
  fsType: xfs
provisioner: driver.longhorn.io
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true

Minioのインストール

Helmチャートでminio-operatorとminio-tenantをインストールしていきます。

MinIO is a Kubernetes-native high performance object store with an S3-compatible API. The MinIO Kubernetes Operator supports deploying MinIO Tenants onto private and public cloud infrastructures (“Hybrid” Cloud).

The MinIO Operator installs a Custom Resource Definition (CRD) to support describing MinIO tenants as a Kubernetes object.

オペレータはKubernetesクラスタ上にMinioオブジェクトストレージを簡単にデプロイ、管理、運用するためのツールです。テナントが実際のS3互換オブジェクトストレージサービスを提供するインスタンスとなります。

infra-controllers flux kustomization に minio-operator をインストールし、インフラストラクチャ用に infra-configs flux kustomization に1つの minio-tenant をインストールします。後でアプリ用に別のMinioテナントを立ち上げる可能性も考慮して、このテナントを "infra-tenant" と命名します。ただおうちラボなので結局このテナント一つで全部やってしまう気はしますが!

minio-operator

Helmレポジトリを追加してその時点で最新のバージョンを確認します。

# add the repository
helm repo add minio-operator https://operator.min.io

# update helm repository whenever needed
# helm repo update

# see the latest version
helm search repo minio-operator/operator

# do not use the legacy minio-operator chart

operatorチャートのvaluesファイルをコピーし、編集します。Kubernetesクラスタのドメイン名と、イメージ取得元をおうちラボ内のHarborレジストリに変更、そしてreplica数を1にしています。

# on gitops repo
cd ./infrastructure/lab-hlv3/controllers/default-values
helm show values --version 7.0.1 minio-operator/operator > minio-operator-7.0.1-values.yaml
cp minio-operator-7.0.1-values.yaml ../values/minio-operator-values.yaml
# edit minio-operator-values.yaml file

Valuesファイルが用意出来たら、flux用のhelmrepo, helmreleaseマニフェストを生成します。バージョンの変更、valuesファイルへの更新がある度に簡単に再生成できるよう、いつもスクリプトを用意してマニフェスト生成をしています。

大雑把に、ディレクトリはこのような感じです。

  • ./infrastructure/lab-hlv3/controllers/ # flux infra-controllers kustomization points here
    • kustomization.yaml # kubernetes kustomization
    • minio-operator.yaml # product flux helmrepo & helmrelease manifests file to be added to the k8s ks above
    • values/minio-operator-values.yaml # values file
    • scripts/minio-operator.sh

スクリプトはこちらです。

#!/bin/bash

# add flux helmrepo to the manifest
flux create source helm minio-operator \
  --url=https://operator.min.io \
  --interval=1h0m0s \
  --export >../minio-operator.yaml

# add flux helm release to the manifest including the customized values.yaml file
flux create helmrelease minio-operator \
  --interval=10m \
  --target-namespace=minio-operator \
  --source=HelmRepository/minio-operator \
  --chart=operator \
  --chart-version=7.0.1 \
  --values=../values/minio-operator-values.yaml \
  --export >>../minio-operator.yaml

最後に、infra-controllers kustomizationを更新してfluxに渡す前に、minio-operator namespaceを別途作っておきます。こちらは私の場合、flux-system kustomizationの方に (./clusters/lab-hlv3/namespaces/minio-operator.yamlに)ファイルを用意するようにしています。

flux tree ks infra-controllers

インストール後のflux treeの出力の一部です。

# flux tree ks infra-controllers
├── HelmRelease/flux-system/minio-operator
│   ├── ServiceAccount/minio-operator/minio-operator
│   ├── CustomResourceDefinition/tenants.minio.min.io
│   ├── CustomResourceDefinition/policybindings.sts.min.io
│   ├── ClusterRole/minio-operator-role
│   ├── ClusterRoleBinding/minio-operator-binding
│   ├── Service/minio-operator/operator
│   ├── Service/minio-operator/sts
│   └── Deployment/minio-operator/minio-operator

minio-tenant

https://min.io/docs/minio/kubernetes/upstream/operations/install-deploy-manage/deploy-minio-tenant-helm.html#

手順はオペレータと同様です。chartは先に追加したレポジトリに一緒に入っています。

# add the repository
# helm repo add minio-operator https://operator.min.io

# update helm repository whenever needed
# helm repo update

# see the latest version
helm search repo minio-operator/tenant

Valuesファイルをコピーし、編集します。

# on gitops repo
cd ./infrastructure/lab-hlv3/controllers/default-values
helm show values --version 7.0.1 minio-operator/tenant > minio-tenant-7.0.1-values.yaml
cp minio-tenant-7.0.1-values.yaml ../values/minio-tenant-values.yaml
# edit minio-tenant-values.yaml file

flux helmrepoマニフェストはオペレータ導入時に作成済みなので、テナント追加時にはflux helmreleaseマニフェストだけ生成していくことになります。

そしてテナントはinfra-configsより導入することにしています。今後テナントを追加するたびに、以下の流れで必要なファイルを増やしていくことになる予定です。

  • namespace
    • ./clusters/lab-hlv3/namespaces/minio-TENANT_NAME.yaml
    • or... you could share one namespace for all tenants
  • helm chart values file
    • ./infrastructure/lab-hlv3/configs/values/minio-TENANT_NAME-values.yaml
  • script to run flux create helmrelease to generate manifest
    • ./infrastructure/lab-hlv3/configs/scripts/minio-TENANT_NAME.sh
  • generated flux helmrelease manifest file
    • ./infrastructure/lab-hlv3/configs/minio-tenant/TENANT_NAME.yaml
#!/bin/bash

# add flux helm release to the manifest including the customized values.yaml file
flux create helmrelease minio-infra-tenant \
  --interval=10m \
  --target-namespace=minio-infra-tenant \
  --source=HelmRepository/minio-operator \
  --chart=tenant \
  --chart-version=7.0.1 \
  --values=../values/minio-infra-tenant-values.yaml \
  --export >../minio-tenant/infra-tenant.yaml

infra-tenant用のminio-tenantチャートのvaluesファイル

Valuesファイルの変更点は次の通りです。

  • tenant
    • name: infra-tenant
    • configuration
      • name: infra-tenant-env-configuration
    • configSecret:
      name: infra-tenant-env-configuration
      accessKey: (空白にしておく)
      secretKey: (空白にしておく)
      existingSecret: true
    • pools:
      • servers: 1
      • volumesPerServer: 1
      • size: 60Gi
      • storageClassName: longhorn-xfs
    • certificate:
      • requestAutoCert: false

テナントが利用するenvコンフィグファイル

config.envファイルで環境変数を渡すことでテナントのコンフィグができます。ここではテナントのUIにアクセスするときに使うユーザ、パスワードを用意します。

例としては以下の通りです。ユーザ名とパスワードの値は好きに指定しましょう。SOPSで暗号化したらGitOpsレポジトリへとプッシュします。

# ./sops/lab-hlv3/minio-tenant/infra-tenant-env-configuration.yaml
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: infra-tenant-env-configuration
  namespace: minio-infra-tenant
stringData:
  config.env: |-
    export MINIO_ROOT_USER=minio
    export MINIO_ROOT_PASSWORD=minio123

storage class longhorn-xfs

最初の方ですでに触れましたが、minio-tenantのvaluesファイル内でも指定しているstorage classを用意します。

# ./infrastructure/lab-hlv3/configs/longhorn/sc-longhorn-xfs.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-xfs
parameters:
  staleReplicaTimeout: "30"
  diskSelector: xfs
  fsType: xfs
provisioner: driver.longhorn.io
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true

flux tree ks infra-configs

インストール後のinfra-configs ksや作成されたpod(sts)、serviceなどは以下の通りです。

$ flux tree ks infra-configs
Kustomization/flux-system/infra-configs
├── StorageClass/longhorn-xfs
└── HelmRelease/flux-system/infra-tenant
    └── Tenant/minio-infra-tenant/infra-tenant


$ kubectl get all -n minio-infra-tenant
NAME                        READY   STATUS    RESTARTS        AGE
pod/infra-tenant-pool-0-0   2/2     Running   2 (4h23m ago)   4h24m

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/infra-tenant-console   ClusterIP   10.96.6.195     <none>        9090/TCP   4h24m
service/infra-tenant-hl        ClusterIP   None            <none>        9000/TCP   4h24m
service/minio                  ClusterIP   10.96.186.251   <none>        80/TCP     4h24m

NAME                                   READY   AGE
statefulset.apps/infra-tenant-pool-0   1/1     4h24m

テナントのUIへのアクセス

それでは次にUIへのアクセスを用意します。3ステップです。

  • 接続先のサービスの確認
  • gatewayにlistenerを追加
  • 追加したlistenerとサービスを繋ぐHTTPRouteを作成

接続先サービス名はinfra-tenant-consoleです。

cilium gatewayの.spec.listeners[]に追加したlistenerはこちらです。

- name: minio-infra-tenant-https
  hostname: infra-tenant.lab.blink-1x52.net
  port: 443
  protocol: HTTPS
  allowedRoutes:
    namespaces:
      from: Selector
      selector:
        matchLabels:
          gateway: cilium
  tls:
    mode: Terminate
    certificateRefs:
      - name: tls-minio-infra-tenant
        kind: Secret
        namespace: gateway

HTTPRouteはこのようになります。

---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: minio-infra-tenant-https
  namespace: minio-infra-tenant
spec:
  parentRefs:
    - name: cilium-gateway
      sectionName: minio-infra-tenant-https
      namespace: gateway
  hostnames:
    - "infra-tenant.lab.blink-1x52.net"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: infra-tenant-console
          port: 9090

Minio Tenant UI

テナントのS3サービスへのアクセス

S3サービスへのアクセスもcilium gateway上に用意します。

Listenerはこちら。

- name: s3-infra-tenant-https
  hostname: s3-infra-tenant.lab.blink-1x52.net
  port: 443
  protocol: HTTPS
  allowedRoutes:
    namespaces:
      from: Selector
      selector:
        matchLabels:
          gateway: cilium
  tls:
    mode: Terminate
    certificateRefs:
      - name: tls-s3-infra-tenant
        kind: Secret
        namespace: gateway

HTTPRouteです。

---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: s3-infra-tenant-https
  namespace: minio-infra-tenant
spec:
  parentRefs:
    - name: cilium-gateway
      sectionName: s3-infra-tenant-https
      namespace: gateway
  hostnames:
    - "s3-infra-tenant.lab.blink-1x52.net"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: minio
          port: 80

GitLab Runnerでお試し

GitLabのCI/CD pipelineを回してくれるGitLab Runnerはcache保存先としてS3サービスが指定可能です。Runnerのためにbucket、ポリシー、credentialsを用意します。

  • "runner-cache"という名前のbucketを作成
  • "rw-runner-cache"という名前でポリシーを用意、"runner-cache" bucketへのread-writeアクセスを可能とするポリシーにする
  • ユーザを"giltab-runner"という名前で用意し、パスワードも設定
  • "rw-runner-cache"ポリシーに"gitlab-runner"ユーザを追加

ユーザ名とそのパスワードが、S3サービスでのaccess keyおよびsecret keyとなります。

ポリシー

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:*"],
      "Resource": ["arn:aws:s3:::runner-cache/*", "arn:aws:s3:::runner-cache"]
    }
  ]
}

GitLab Runnerコンフィグファイル例

今おうちラボで動かしているGitLab Runnerはdockerコンテナとして稼働しているもののみですので、そのコンフィグファイル/etc/gitlab-runner/config.tomlの例を以下に紹介します。

"runners.cache"部分に"type = s3"を追加し、"runners.cache.s3"に宛先、bucket名、credentialsなどを設定しています。

参考までに、Kubernetesクラスタ上にHelmチャートでGitLab Runnerをセットアップしたときの記事、特に設定周りの記述はこちらにあります。

concurrent = 1
check_interval = 0
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "docker runner"
  url = "https://GITLAB_HOST"
  id = 14
  token = "GITLAB_RUNNER_TOKEN"
  token_obtained_at = 2025-04-04T06:04:33Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  clone_url = "https://GITLAB_HOST"
  [runners.cache]
    MaxUploadedArchiveSize = 0
    Type = "s3"
    [runners.cache.s3]
      ServerAddress = "s3-infra-tenant.lab.blink-1x52.net"
      BucketName = "runner-cache"
      BucketLocation = "lab-hlv3"
      Insecure = false
      AuthenticationType = "access-key"
      AccessKey = "gitlab-runner"
      SecretKey = "USER_PASSWORD"
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "alpine:latest"
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0

ジョブのログ

Cacheを利用するジョブのログからは以下のようにcache.zipをアップロードしていることが確認できると思います。

Saving cache for successful job 00:02
Creating cache xxx-protected...
/xxx/.cache/pip: found 568 matching artifact files and directories
Uploading cache.zip to https://s3-infra-tenant.lab.blink-1x52.net/runner-cache/runner/t1_CZUpzY/project/148/xxx-protected
Created cache

Uploading artifacts for successful job 00:01
Uploading artifacts...
public/: found 333 matching artifact files and directories
Uploading artifacts as "archive" to coordinator... 201 Created  id=3647 responseStatus=201 Created token=xxx

Cleaning up project directory and file based variables 00:00
Job succeeded

テナントのUIでbucketを確認すると確かにファイルができていることが確認できます。

Minio Tenant runner-cache bucket

終わりに

以上です!

minio-operatorとminio-tenantのhelmチャートを用いることでテナントを必要な数だけ、好きにインスタンスに分けて立ち上げられるのが良いですね。

今回はサーバ1台、サーバ毎のプール内のvolume数も1というstandalone構成と言われるテナントを作りましたが、S3ストレージを利用するサービスの重要性に応じて高可用性を求めた構成のテナントを立ち上げるのも簡単です。

あるいはminioテナントがstandalone構成でも、ディスクスペース提供元(今回の構成ではLonghorn)の方でレプリケーションやバックアップを充実させておき、そのディスクスペースを利用する専用のstorage classを設け、それを用いてテナントを立ち上げるというやり方もできます。

試せる構成が多くて困ってしまいますね。

今回遊んでいるKubernetesクラスタにおいて、S3を用意した主な理由の一つはロギングシステムとして導入予定のgrafana lokiです。lokiが扱うchunksやindexesの保存先としてobject storeが必要となり、その準備段階としてのS3構築でした。

Discussion