ROOKを利用すれば、Kubernetesクラスタ上にCephなどを簡単に構築することができる。Kubernetesクラスタ上に作ることは、運用管理面で効率化が期待できる。一方、Cephを直接サーバーにインストールすれば、仮想サーバーや物理サーバーにインストールして、KubernetesクラスタをCSI(Conainer Storage Interface)を使って連携することもできる。
ダイレクトにCephを利用するメリットは、積み重ねるスタックが少なくて済み、Kubernetesのバージョンアップなどの影響を受けない点である。永続データそのものは、ストレージに格納されるため、RAIDを組むなどの対策があれば、遜色ないように思われる。しかし、失うことが許されないデータは、ソフトウェアスタックの少ない専用基盤の上に保存されることに安定感を感じる。
今後、ROOKを使っていくことになると思うが、今回は、CephクラスタとKubernetesと連携させることも顧慮できるように検証する。
検証の環境は、いつものように、アップストリームのKubernetesとCephである。
サンドボックスディレクトの作成
これには解説は要らないと思うが、Vagrantのファイル一式などを、このディレクト下に配置する。
mkdir sandbox-1
cd sandbox-1
Cephの起動
Cephクラスタの起動は、Vagrant仮想マシンでCephクラスタをAnsibleで構築してみたで開発した GitHub takara9/vagrant-ceph を利用する。
git clone https://github.com/takara9/vagrant-ceph ceph
cd ceph
vagrant up
Cephの初期設定
基本は、Cephクラスタを構築するAnsibleのプレイブックに記述してあるが、ここでは、Kubenetesクラスタを接続するための設定を実施する。
Cephクラスタのマスターノードへログインして、設定を実施する。
vagramt ssh master
sudo -s
以下の5行をコピーして、ターミナルへペーストすることで、一気に入力を終えることができる。
ceph version
ceph osd pool create kubernetes 20
rbd pool init kubernetes
ceph auth get-or-create client.kubernetes mon 'profile rbd' osd 'profile rbd pool=kubernetes' mgr 'profile rbd'
ceph mon dump
以下は実際に実行した例で、結果として表示される key と fsid は、後に使用するのでメモしておく。
vagrant@master:~$ sudo -s
root@master:~# ceph version
ceph version 14.2.6 (f0aa067ac7a02ee46ea48aa26c6e298b5ea272e9) nautilus (stable)
root@master:~# ceph osd pool create kubernetes 20
pool 'kubernetes' created
root@master:~# rbd pool init kubernetes
root@master:~# ceph auth get-or-create client.kubernetes mon 'profile rbd' osd 'profile rbd pool=kubernetes' mgr 'profile rbd'
[client.kubernetes]
key = AQARTCRe8YzyIBAAyILadDjDkabJ7qYBBMzfXg== <--- クライアント認証のキー
root@master:~# ceph mon dump
dumped monmap epoch 1
epoch 1
fsid aca2c93e-e75c-4fc3-b0b0-eecba959270c <--- クラスタID
last_changed 2020-01-19 12:26:07.410539
created 2020-01-19 12:26:07.410539
min_mon_release 14 (nautilus)
0: [v2:172.20.1.30:3300/0,v1:172.20.1.30:6789/0] mon.master
1: [v2:172.20.1.31:3300/0,v1:172.20.1.31:6789/0] mon.node1
2: [v2:172.20.1.32:3300/0,v1:172.20.1.32:6789/0] mon.node2
3: [v2:172.20.1.33:3300/0,v1:172.20.1.33:6789/0] mon.node3
ここまで完了すると、ブラウザからCephのコンソール画面を参照できる。URLアドレスは、以下のどちらかになり
- https://172.20.1.30:8443/ パソコン内LAN経由でアクセスする場合のURL
- https://192.168.1.90:8443/ パソコン外からアクセスする時のURL
このブラウザ画面は、自己署名証明書でTLS化されているので、アクセスするブラウザを選ぶ。筆者はFirefoxを利用してログインした。
ユーザーIDとパスワードは、admin/password が初期設定されている。
Kubernetesクラスタの起動
最新のバージョンは、ブランチに作ってテストしてある。マイナーバージョンがリリースされて安定したので、1.17を使用する。
git clone -b 1.17 https://github.com/takara9/vagrant-kubernetes k8s
cd k8s
vagrant up
環境変数を設定して、仮想マシンのホストから、kubectlコマンドの接続を確認する。
tkr@luigi:~/sandbox-1/k8s$ export KUBECONFIG=`pwd`/kubeconfig/config
tkr@luigi:~/sandbox-1/k8s$ kubectl get no
NAME STATUS ROLES AGE VERSION
master Ready master 111s v1.17.1
node1 Ready <none> 80s v1.17.1
node2 Ready <none> 80s v1.17.1
Ceph用の名前空間ceph-csi
とコンテキストcc
を作成して、切り替える。
kubectl create ns ceph-csi
kubectl config set-context cc --namespace=ceph-csi --cluster=kubernetes --user=kubernetes-admin
kubectl config use-context cc
kubectl config get-contexts
K8sとCeph連携の環境設定
K8sの名前空間上のポッドが、Cephクラスタにアクセスできるようにコンフィグマップを作成する。
cat <<EOF > csi-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
config.json: |-
[
{
"clusterID": "fsidで置き換える",
"monitors": [
"172.20.1.30:6789",
"172.20.1.31:6789",
"172.20.1.32:6789",
"172.20.1.33:6789"
]
}
]
metadata:
name: ceph-csi-config
EOF
kubectl apply -f csi-config-map.yaml
次に、アクセスのためのキーを格納したシークレットを作成する。
cat <<EOF > csi-rbd-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: csi-rbd-secret
namespace: ceph-csi
stringData:
userID: kubernetes
userKey: keyで置き換える
EOF
kubectl apply -f csi-rbd-secret.yaml
CSI実行のための権限設定(RBAC)
最初に、CSIを動かすための権限設定(RBAC)を適用する。ここで、前述のように名前空間を変更したので、エディタで開いて名前空間名をceph-csi
へ変更する。
curl -O https://raw.githubusercontent.com/ceph/ceph-csi/release-v1.2.0/deploy/rbd/kubernetes/v1.14%2B/csi-provisioner-rbac.yaml
vi csi-provisioner-rbac.yaml
kubectl apply -f csi-provisioner-rbac.yaml
同様に、名前空間を変更する。
curl -O https://raw.githubusercontent.com/ceph/ceph-csi/release-v1.2.0/deploy/rbd/kubernetes/v1.14%2B/csi-nodeplugin-rbac.yaml
vi csi-nodeplugin-rbac.yaml
kubectl apply -f csi-nodeplugin-rbac.yaml
CSIのポッドを起動
この中には、名前空間が設定されていないので、そのまま、実行する。
kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/release-v1.2.0/deploy/rbd/kubernetes/v1.14%2B/csi-rbdplugin-provisioner.yaml
kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/release-v1.2.0/deploy/rbd/kubernetes/v1.14%2B/csi-rbdplugin.yaml
ポッドのSTATUSが、Running に変わることを確認する。
kubectl get po -w
ストレージクラスの設定
ストレージクラスを設定して、PVCからPVが作成できるようにする。
cat <<EOF > csi-rbd-sc.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
clusterID: ***fsidで置き換える*** <<--- 注意
pool: kubernetes
csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
csi.storage.k8s.io/provisioner-secret-namespace: default
csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
reclaimPolicy: Delete
mountOptions:
- discard
EOF
$ kubectl apply -f csi-rbd-sc.yaml
それから、デフォルトのストレージクラスへ変更する。
kubectl patch storageclass csi-rbd-sc -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
kubectl get sc
これで、Kubernetesクラスタから、Cephのブロック・ストレージをダイナミック・プロビジョニングできるようになった。
ブロックデバイスとしてマウントの確認
ブロックデバイスとして、/dex/xvda を Cephのブロックストレージをマッピングする。
最初にPVCを作成する。この中で spec.volumeMode: Block
を指定することで、ブロックデバイスがコンテナのでデバイスとして利用できる。
cat <<EOF > raw-block-pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: raw-block-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block
resources:
requests:
storage: 1Gi
storageClassName: csi-rbd-sc
EOF
kubectl apply -f raw-block-pvc.yaml
ポッドのマニフェストでdevicePath: /dev/xvda
が設定され、ファイルシステムとしてマウントすることができない。
筆者が試したところ、このデバイスは、mkfs.ext4を実行して、ファイルシステムを書き込むことができるが、マウントはできない。
もちろん、RAWデバイスとして、読み書きする分には問題がない。
cat <<EOF > raw-block-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: pod-with-raw-block-volume
spec:
containers:
- name: fc-container
image: fedora:26
command: ["/bin/sh", "-c"]
args: ["tail -f /dev/null"]
volumeDevices:
- name: data
devicePath: /dev/xvda
volumes:
- name: data
persistentVolumeClaim:
claimName: raw-block-pvc
EOF
kubectl apply -f raw-block-pod.yaml
ブロックストレージをファイルシステムとしてマウント
PVCのマニフェストにspec.volumeMode: Filesystem
を設定することで、ブロックデバイスをファイルシステムでフォーマットされたボリュームとしてマウントできる。
cat <<EOF > pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
storageClassName: csi-rbd-sc
EOF
kubectl apply -f pvc.yaml
こちらは、コンテナにストレージをマウントした状態で起動する。
cat <<EOF > pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: csi-rbd-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
EOF
kubectl apply -f pod.yaml
クリーンナップ
以下のコマンドで、仮想サーバーごと消去することできる。一時的に止めておきたい場合は、vagrant halt
を利用すると良い。
cd sandbox-1/k8s
vagrant destroy -f
cd ../ceph
vagrant destroy -f
まとめ
Cephを数台のサーバーにインストールして、ストレージを構築して、Kubernetesクラスタへ接続することを想定した検証を実施してみた。Glusterfsは、その名の通り、分散ファイルシステムとしての利用になるが、Cephはブロックストレージとして、RAWとファイルシステムとして利用可能なので、データベースのストレージとしても利用も期待できる。
プールの作成などで、Cephクラスタを操作する必要も出てくるが、論理ボリュームの割り当てや開放など、PVCを利用して実施できるのは素晴らしい。次はROOKを検証してみたい。
参考URL
https://docs.ceph.com/docs/master/rbd/rbd-kubernetes/#block-devices-and-kubernetes
https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html