Proxmox × k0s × CephFS で構築するKubernetesストレージ基盤
はじめに
この記事では、Proxmox 上に構築した Kubernetes クラスタ(k0s)環境において、Proxmox 側で構築済みの CephFS ストレージを利用し、PersistentVolumeClaim(PVC)を Pod にマウントするまでの一連の流れと、その過程で遭遇した問題・解決策を記録しています。
Kubernetes をベアメタルや自前仮想環境で運用する際に直面する「CSIドライバの認識」「PVCのバインド」「マウント失敗」など、実戦的なポイントが盛りだくさんです。
特に今回はk0s特有の課題も引いたためその解決法も含めて、k0sで楽にクラスタ構築をしたい方はぜひ参考にしてください。
本記事の執筆にあたって下記の記事が本当に参考になりました!
ほとんどの記事がRookを用いたCeph構築を前提としている中でProxmox側でCeph作成した場合の手順が細かく書かれていて本当に助かりました!
👉 kubernetesからProxmoxのCephを使う - tunamaguro's blog
🎯 本記事のアピールポイント
- この記事を書くためだけにコントローラーノードとワーカーノードを完全に初期化して最初からステップを踏みました。こちらのREADMEにあるような初期セットアップを含めても全ての動作確認は2~3時間程度で終了することを確認しています!つまり、2025/03/23から数ヶ月程度においてはほぼ確実な環境構築方法を提供しているということです!
- ちなみにどうしてそんなに早くマシンの初期化からセットアップまでを行えたかというとこちらとこちらの自作リポジトリでProxmoxのVM作成をほぼ自動化ているからです!ぜひ使っていただきたいですし、IssueやPRもお待ちしています!
背景と目的
なぜ Proxmox?
Proxmox はオープンソースでありながら強力な仮想化環境を提供してくれるプラットフォームです。ZFS や Ceph との親和性も高く、オンプレミスでのプライベートクラウド基盤として非常に優秀です。
Proxmox用のTerraform Providerも提供されており、以下の自作リポジトリと組み合わせることで簡単に自宅に簡易的なプライベートクラウドを構築できます。
なぜ k0s?
k0s
はシンプルかつ軽量な Kubernetes ディストリビューションです。Proxmox 上に軽量に展開し、RBAC や CSI との連携を柔軟に行える点が魅力です。
特にk0sctlと組み合わせることで非常に簡単にk8s-clusterの構築が可能です。
以下のリポジトリ (絶賛工事中) にはk0sを用いたk8s-cluster構築の方法がREADMEに詳しく書いているのでぜひ参考にしてください。
最終的には、minio, harbor, argocdを用いたプライベートなCI/CD基盤を構築する予定です。
目的
本記事のゴールは、次の2つを実現することです:
- Proxmoxで構築したCephFSをKubernetesのストレージとしてマウントする
- PodからPVCを通じてそのストレージにアクセスし、ファイルの読み書きができる状態を確認する
全体構成
以下のような構成でクラスタとストレージを設計しました。
このイメージを一旦頭に入れておけば作業中迷子になることはないかと思います。
🧩 構成要素
✅ Proxmox Cluster
-
VM1:
k0s Controller
-
VM2:
k0s Worker 1
-
VM3:
k0s 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 側の
CephFS
がStorageClass
→PVC
→Pod
を通して、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内でストレージへ読み書き成功
今後の展望
このストレージ基盤の上に、以下を構築予定です:
- 🪣 MinIO:オブジェクトストレージ(Harborのバックエンドなどに)
- 🐳 Harbor:コンテナイメージのプライベートレジストリ
- 🚀 Argo CD:GitOpsによるCICD基盤構築(自動デプロイ)
これらを組み合わせ、オンプレミス環境でも高速に回せるCICD基盤を目指します。
🙌 おわりに
商用クラウドとは異なり、オンプレミスでのKubernetes環境では、ストレージとの統合やドライバの認識といった基礎部分に多くの手間がかかります。しかし、その分、深い理解と柔軟な構成が可能になります。
この記事が、同様の構成に挑戦する方々の助けになれば幸いです。
Discussion