Zenn
😺

Proxmox × k0s × CephFS で構築するKubernetesストレージ基盤

2025/03/23に公開

はじめに

この記事では、Proxmox 上に構築した Kubernetes クラスタ(k0s)環境において、Proxmox 側で構築済みの CephFS ストレージを利用し、PersistentVolumeClaim(PVC)を Pod にマウントするまでの一連の流れと、その過程で遭遇した問題・解決策を記録しています。

Kubernetes をベアメタルや自前仮想環境で運用する際に直面する「CSIドライバの認識」「PVCのバインド」「マウント失敗」など、実戦的なポイントが盛りだくさんです。
特に今回はk0s特有の課題も引いたためその解決法も含めて、k0sで楽にクラスタ構築をしたい方はぜひ参考にしてください。

本記事の執筆にあたって下記の記事が本当に参考になりました!
ほとんどの記事がRookを用いたCeph構築を前提としている中でProxmox側でCeph作成した場合の手順が細かく書かれていて本当に助かりました!

👉 kubernetesからProxmoxのCephを使う - tunamaguro's blog


🎯 本記事のアピールポイント

  1. この記事を書くためだけにコントローラーノードとワーカーノードを完全に初期化して最初からステップを踏みました。こちらのREADMEにあるような初期セットアップを含めても全ての動作確認は2~3時間程度で終了することを確認しています!つまり、2025/03/23から数ヶ月程度においてはほぼ確実な環境構築方法を提供しているということです!
  2. ちなみにどうしてそんなに早くマシンの初期化からセットアップまでを行えたかというとこちらこちらの自作リポジトリでProxmoxのVM作成をほぼ自動化ているからです!ぜひ使っていただきたいですし、IssueやPRもお待ちしています!

背景と目的

なぜ Proxmox?

Proxmox はオープンソースでありながら強力な仮想化環境を提供してくれるプラットフォームです。ZFS や Ceph との親和性も高く、オンプレミスでのプライベートクラウド基盤として非常に優秀です。
Proxmox用のTerraform Providerも提供されており、以下の自作リポジトリと組み合わせることで簡単に自宅に簡易的なプライベートクラウドを構築できます。

https://github.com/AobaIwaki123/Proxmox-Terraform

なぜ k0s?

k0s はシンプルかつ軽量な Kubernetes ディストリビューションです。Proxmox 上に軽量に展開し、RBAC や CSI との連携を柔軟に行える点が魅力です。
特にk0sctlと組み合わせることで非常に簡単にk8s-clusterの構築が可能です。
以下のリポジトリ (絶賛工事中) にはk0sを用いたk8s-cluster構築の方法がREADMEに詳しく書いているのでぜひ参考にしてください。
最終的には、minio, harbor, argocdを用いたプライベートなCI/CD基盤を構築する予定です。

https://github.com/AobaIwaki123/k8s-cluter

目的

本記事のゴールは、次の2つを実現することです:

  1. Proxmoxで構築したCephFSをKubernetesのストレージとしてマウントする
  2. PodからPVCを通じてそのストレージにアクセスし、ファイルの読み書きができる状態を確認する

全体構成

以下のような構成でクラスタとストレージを設計しました。
このイメージを一旦頭に入れておけば作業中迷子になることはないかと思います。

🧩 構成要素

✅ Proxmox Cluster

  • VM1k0s Controller
  • VM2k0s Worker 1
  • VM3k0s Worker 2
  • Ceph:Proxmox 上に構築された CephFS クラスタ

✅ Kubernetes Cluster (k0s)

  • Rook-Ceph Operator
    • 外部 Ceph クラスタに接続し、Kubernetes にストレージを提供するオペレーター
  • StorageClass (rook-cephfs)
    • CephFS を使用するストレージクラス
  • PVC (PersistentVolumeClaim)
    • Pod から永続ボリュームを要求するためのリソース
  • Pod
    • PVC を通じて CephFS をマウントして利用

✅ Ceph External Cluster

  • Ceph Monitor / MGR
    • Rook Operator からの接続先
  • CephFS
    • 実際のストレージリソースを提供

🔗 関係性の概要

  • Rook-Ceph Operator は Kubernetes 内で稼働し、CephCluster カスタムリソース経由で 外部 Ceph クラスタCeph Monitor / MGR)に接続。
  • Ceph 側の CephFSStorageClassPVCPod を通して、Kubernetes に永続ストレージを提供。
  • Rook は各ノード(VM1, VM2, VM3)に展開されている。
  • Proxmox 側の Ceph クラスタが、External Cluster として Rook から利用されている。

📊 Mermaid 図


✅ Proxmox 上の Ceph を Kubernetes(k0s)から使うための総合手順

0. 前提

  • Proxmox 側で Ceph クラスタが構築済み(CephFS or RBD)
  • helmなど基本的なコマンドは任意の方法でインストール済み。asdfを用いた方法であれば全てこちらで解説しています!
  • オプション: argocdのセットアップが完了していること。なくてもいいですがargocdの方がk8s使ってる感があってかっこいいです (重要)
    • 以下argocdの画面の例です。アプリケーションのデプロイ状況が一目でわかるのでテンションが上がります。

1. Rook Ceph Clusterの作成

$ kubectl create ns rook-ceph

1-1. Helmを使う場合

$ helm repo add rook-release https://charts.rook.io/release
$ helm repo update
$ helm install --namespace rook-ceph rook-ceph-cluster rook-release/rook-ceph-cluster
$ helm install rook-ceph rook-release/rook-ceph \
  --namespace rook-ceph \
  --set csi.kubeletDirPath="/var/lib/k0s/kubelet"

📝 /var/lib/k0s/kubelet は k0s を使う場合のオプションです。適宜変更してください!

1-2. ArgoCDを使う場合

$ argocd app create --file apps/rook.yaml
📄 apps/rook.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: rook-ceph
  namespace: argocd
  annotations:
    argocd.argoproj.io/sync-wave: "-1"
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://charts.rook.io/release
    chart: rook-ceph
    targetRevision: v1.16.5
    helm:
      parameters:
        - name: csi.kubeletDirPath
          value: /var/lib/k0s/kubelet
  destination:
    server: "https://kubernetes.default.svc"
    namespace: rook-ceph
  syncPolicy:
    syncOptions:
      - CreateNamespace=true

2. Ceph Clusterの状態を確認

$ kubectl -n rook-ceph get pod | grep rook-ceph-operator
# RunningになればOK

2. ProxmoxでPoolを作成する

2-1. Proxmox GUIで作成する

  • PVE Node > Ceph > Pool > Create: k8s-pv-pool

2-2. Proxmox CLIで作成する

$ pveceph pool create k8s-pv-pool --pg_autoscale_mode-on

3. 環境変数の取得

🔧 以下のコマンドをProxmoxのホスト上で実行する:

$ wget https://raw.githubusercontent.com/rook/rook/release-1.16/deploy/examples/create-external-cluster-resources.py
$ python3 create-external-cluster-resources.py --namespace rook-ceph-external --rbd-data-pool-name k8s-pv-pool --format bash --skip-monitoring-endpoint --v2-port-enable
# 出力値は後で使うのでコピーしておく

💻 次に以下のコマンドを kubectl が使えるホスト上 で実行:

# env.shに前に取得した環境変数をコピーする
$ source ./env.sh
$ wget https://raw.githubusercontent.com/rook/rook/release-1.16/deploy/examples/import-external-cluster.sh
. import-external-cluster.sh

4. 外部Cephクラスターに接続する用のCeph Clusterを作成

4-1. Helmを使う場合

$ wget https://raw.githubusercontent.com/rook/rook/release-1.16/deploy/charts/rook-ceph-cluster/values-external.yaml
$ helm install --create-namespace --namespace $NAMESPACE rook-ceph-cluster --set operatorNamespace=rook-ceph rook-release/rook-ceph-cluster -f values-external.yaml

4-2. ArgoCDを使う場合

$ argocd app create --file apps/ceph-external-cluster.yaml
📄 apps/ceph-external-cluster.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: rook-ceph-external-cluster
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://charts.rook.io/release
    chart: rook-ceph-cluster
    targetRevision: v1.13.6
    helm:
      valuesObject:
        cephClusterSpec:
          external:
            enable: true
          crashCollector:
            disable: true
          healthCheck:
            daemonHealth:
              mon:
                disabled: false
                interval: 45s
        cephBlockPools: {}
        cephFileSystems: {}
        cephObjectStores: {}
  destination:
    server: "https://kubernetes.default.svc"
    namespace: rook-ceph-external 

✅ 5. 動作確認

$ kubectl create ns test
$ kubectl apply -f tests/pvc.yaml -f tests/pod.yaml -n test
$ kubectl get pod -n test csirbd-demo-pod
# RunningになればOK
$ kubectl get pvc -n test rbd-pvc
# BoundになればOK
📄 tests/pvc.yaml
# https://github.com/rook/rook/blob/release-1.13/deploy/examples/csi/rbd/pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: ceph-rbd
📄 tests/pod.yaml
# Ref: https://github.com/rook/rook/blob/release-1.13/deploy/examples/csi/rbd/pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: csirbd-demo-pod
spec:
  containers:
    - name: web-server
      image: nginx
      volumeMounts:
        - name: mypvc
          mountPath: /var/lib/www/html
  volumes:
    - name: mypvc
      persistentVolumeClaim:
        claimName: rbd-pvc
        readOnly: false

🐛 問題と解決の記録

全ての沼の元凶はここでした...

エラー:CSIドライバが見つからない

attacher.MountDevice failed to create newCsiDriverClient: driver name rook-ceph.rbd.csi.ceph.com not found in the list of registered CSI drivers

原因

  • kubelet がCSIドライバソケットを /var/lib/kubelet に探しに行っていたが、k0sの実体は /var/lib/k0s/kubelet

解決策

  • Helmの --set csi.kubeletDirPath="/var/lib/k0s/kubelet" によって正しく認識され、Podのマウントが成功

まとめと次の展望

Proxmox × k0s × CephFS という組み合わせで、以下を達成しました:

  • Proxmox上の仮想環境で軽量なk8sクラスタを構築(k0s)
  • ProxmoxベースのCephFSをKubernetesからマウント可能に
  • PVCを使ってPod内でストレージへ読み書き成功

今後の展望

このストレージ基盤の上に、以下を構築予定です:

  1. 🪣 MinIO:オブジェクトストレージ(Harborのバックエンドなどに)
  2. 🐳 Harbor:コンテナイメージのプライベートレジストリ
  3. 🚀 Argo CD:GitOpsによるCICD基盤構築(自動デプロイ)

これらを組み合わせ、オンプレミス環境でも高速に回せるCICD基盤を目指します。


🙌 おわりに

商用クラウドとは異なり、オンプレミスでのKubernetes環境では、ストレージとの統合やドライバの認識といった基礎部分に多くの手間がかかります。しかし、その分、深い理解と柔軟な構成が可能になります。

この記事が、同様の構成に挑戦する方々の助けになれば幸いです。

Discussion

ログインするとコメントできます