LoginSignup
21
16

KubernetesにRookを導入して、Block Storageを試してみた

Last updated at Posted at 2018-11-05

はじめに

この記事は完全に時代遅れです。
filestoreを使用した古いrook/cephはアップグレードせず、HDDを加えてbluestoreを有効にした最新版を新規に導入することをお勧めします。

kubernetes環境にCeph環境を構築しようとして、Rookを試しています。

基本的な導入手順は、下記のドキュメントにありますが、バージョンが新しくなって、ほんの少し変更が入っているのでメモを残しておきます。

Rookのv1.x以降では、各Kubernetesノードに専用のHDD/SSDが搭載されている事を前提としています。テスト用に引き続きdirectories: [path: /var/lib/rook]を指定することはできますが、cluster.yamlではuseAllDevices: trueがデフォルトの設定となっていて、未使用のブロックデバイス(e.g. /dev/sdb)の存在が期待されています。新しいバージョンのRookを利用する際には注意が必要です。可能であればFlex Volumeの使用は避けることをお勧めします。

参考資料

環境

ノードはBaremetal(Ubuntu16.04.5)上にkubesprayで構築しています。

実行前のNamespaceの状況は次のとおりです。

$ kubectl get ns
NAME             STATUS    AGE
default          Active    181d
ingress-nginx    Active    11d
istio-system     Active    13h
kube-public      Active    181d
kube-system      Active    181d
metallb-system   Active    179d

【メモ】転送速度について

近い内に全体を最新のv1.6.xに更新する予定です。

Rook/Ceph v1.6の古いバージョンには致命的な欠陥があります。
必ず最新のv1.7やv1.6.8以降を利用するようにしてください。

その前に2つのCeph filesystem間でデータを転送したので環境は以下のとおりです。

  • Kubernetes: v1.16.9 (TX1310m3 x4, Xeon E3-1225v6, 4TB HDD x2 RAID1)
  • Kubernetes: v1.19.9 (TX1320m4 x5, Xeon E-2234, 4TB HDD + 500GB SSD)
  • Local Network (K8sクラスター内部、両方とも): 10Gbps X520-DA1 + DAC + CRS309-1G-8S+
  • Backend Network (K8sクラスター間接続): 1Gbps RJ45ケーブル + Switch
  • Rook/Ceph v1.0.6 → v1.5.5

ネットワークは単一の192.168.1.0/24の内部で構成しています。

1ファイル 4KB未満のファイルを中心に構成されているFilesystem上にある約3GB(実転送データは約2.5GB)のデータ(ファイル数 2255364)を、片方のクラスターからもう片方(pod-to-pod)にrsyncで転送した結果は以下のようになりました。

sent 2,491,171,331 bytes  received 39,713,035 bytes  136,763.90 bytes/sec
total size is 2,945,556,696  speedup is 1.16

準備

kubectlコマンドが実行できるノードで、rookのリポジトリをgit cloneで取得します。

$ git clone https://github.com/rook/rook
$ cd rook
$ git checkout refs/tags/v0.8.3 -b v0.8.3

Deployment

基本的には公式のドキュメントに従います。
公式ドキュメントは普通にアクセスすると、masterブランチが表示されるので、左下のメニューでv0.8を選択します。

先ほどの手順に続いて、rookディレクトリから、次のコマンドを実行することで、必要なサービスがデプロイされます。

minikubeを利用している場合は、cluster.yamlのdataDirHostPath: /var/lib/rookを修正する必要があります。

$ cd cluster/examples/kubernetes/ceph
$ kubectl create -f operator.yaml
$ kubectl create -f cluster.yaml

[2018/11/20追記] ここでFLEXVOLUME_DIR_PATHを変更せずにoperator.yamlを実行すると動かない可能性があります。
修正可能ですが、2度手間を避けたい場合には、後半のFLEXVOLUME_DIR_PATHについてのセクションを参照してください。

ここまで進めると、namespaceは次のように変化しました。

$ kubectl get ns
NAME               STATUS    AGE
...
rook-ceph          Active    1m
rook-ceph-system   Active    1m

StorageClassでの利用

公式ドキュメントではBlock Storageの項目にあるStorageClassの操作を試してみます。

前の操作に引き続き、 cluster/examples/kubernetes/ceph がカレントディレクトリである事を想定しています。

公式ドキュメントにあるように、storageclass.yaml ファイルを適用し、StorageClassの状態を確認します。

$ kubectl apply -f storageclass.yaml
$ kubectl -n rook-ceph get storageclass
NAME              PROVISIONER          AGE
rook-ceph-block   ceph.rook.io/block   1m

関連する定義を確認するため、-o yamlをつけて実行しました。$ kubectl -n rook-ceph get storageclass -o yaml

- apiVersion: storage.k8s.io/v1
  kind: StorageClass
  metadata:
    ...
    name: rook-ceph-block
    namespace: ""
    ...

namespaceが空なので実際には、どのnamespaceを指定してもstorageclassの定義を参照できることになります。

$ kubectl -n default get storageclass
NAME              PROVISIONER          AGE
rook-ceph-block   ceph.rook.io/block   1h

$ kubectl -n kube-system get storageclass
NAME              PROVISIONER          AGE
rook-ceph-block   ceph.rook.io/block   1h

そのため、システム全体から利用することができます。

StatefulSetを利用した事例について

ROOKの公式ドキュメントに含まれているwordpressのサンプルは、オリジナルがKubernetes公式ドキュメントに掲載されている(Example: Deploying WordPress and MySQL with Persistent Volumes)だと思われます。

これ自体はあまりおもしろくないので、以前、書いた Kubernetes公式のExample: CassandraをPersistentVolumeで構成する を、オリジナルに近い形に戻すことにしました。

このCassandraの例では volumeClaimTemplates を使用していて、StorageClassの定義が含まれています。

Service定義は公式ドキュメントのとおりで問題ありませんが、namespaceとして、cassandraを作成しています。

$ kubectl create ns cassandra
$ alias kubectl='kubectl -n cassandra'
$ kubectl create -f https://k8s.io/examples/application/cassandra/cassandra-service.yaml

StatefulSetは公式ドキュメントにあるcassandra-statefulset.yamlと比較すると次のようになります。

--- cassandra-statefulset.yaml.orig  2018-11-05 17:17:44.057436173 +0900
+++ cassandra-statefulset.yaml       2018-11-05 17:22:58.843780317 +0900
@@ -53,7 +53,7 @@
           - name: HEAP_NEWSIZE
             value: 100M
           - name: CASSANDRA_SEEDS
-            value: "cassandra-0.cassandra.default.svc.cluster.local"
+            value: "cassandra-0.cassandra.cassandra.svc.cluster.local"
           - name: CASSANDRA_CLUSTER_NAME
             value: "K8Demo"
           - name: CASSANDRA_DC
@@ -86,15 +86,7 @@
       name: cassandra-data
     spec:
       accessModes: [ "ReadWriteOnce" ]
-      storageClassName: fast
+      storageClassName: rook-ceph-block
       resources:
         requests:
           storage: 1Gi
----
-kind: StorageClass
-apiVersion: storage.k8s.io/v1
-metadata:
-  name: fast
-provisioner: k8s.io/minikube-hostpath
-parameters:
-  type: pd-ssd

namespaceを指定したので、"default"から"cassandra"に変更しています。
この前のところで、aliasでkubectlに"-n cassandra"を追加しているので、コマンドラインではnamespaceを意識することはありません。

また、StorageClassの部分をバッサリ削除して、storageClassNameの指定を先ほど確認したStorageClassの metadata.name の、rook-ceph-block に変更しています。

$ kubectl apply -f cassandra-statefulset.yaml 

ここまで実行しても、Podが起動しなくて困ってしまいました。

$ kubectl describe pod cassandra-0
...
Events:
  Type     Reason       Age                From               Message
  ----     ------       ----               ----               -------
  Normal   Scheduled    24m                default-scheduler  Successfully assigned cassandra/cassandra-0 to node6
  Warning  FailedMount  2m (x10 over 22m)  kubelet, node6     Unable to mount volumes for pod "cassandra-0_cassandra(0ad97640-e0d4-11e8-8510-000db93312a4)": timeout expired waiting for volumes to attach or mount for pod "cassandra"/"cassandra-0". list of unattached volumes=[cassandra-data default-token-hlb95]

ここで、サンプルのwordpress.yamlなども実行してみましたが、PVもPVCも問題なく作成されているようにみえるものの、Podからマウントできないようにみえます。

Podが稼動しているnode6の/var/log/syslogを確認してみます。

Nov  5 18:57:28 node6 kubelet[1264]: E1105 18:57:28.898651    1264 desired_state_of_world_populator.go:311] Failed to add volume "cassandra-data" (specName: "pvc-15227c15-e0df-11e8-8510-000db93312a4") for pod "1527d22f-e0df-11e8-8510-000db93312a4" to desiredStateOfWorld. err=failed to get Plugin from volumeSpec for volume "pvc-15227c15-e0df-11e8-8510-000db93312a4" err=no volume plugin matched

FLEXVOLUME_DIR_PATH 関連のトラブル

似ている事例としては、次の事例が該当すると思われました。

ここからリンクされている公式ドキュメントによれば、理由として考えられるものは次の2点です。

  1. FlexVolumeの設定
  2. 指定したFlexVolumeがkubeletに指定されている

最初のFlexVolumeの設定については、デフォルトの /usr/libexec/kubernetes/kubelet-plugins/volume/exec/ にディレクトリが作成されている事を確認しました。

$ ls -l /usr/libexec/kubernetes/kubelet-plugins/volume/exec/
total 16
drwxr-xr-x 2 root root 4096 Nov  6 00:10 ceph.rook.io~rook
drwxr-xr-x 2 root root 4096 Nov  6 00:10 ceph.rook.io~rook-ceph-system
drwxr-xr-x 2 root root 4096 Nov  6 00:10 rook.io~rook
drwxr-xr-x 2 root root 4096 Nov  6 00:10 rook.io~rook-ceph-system

この状態であれば、デフォルト設定でうまく動くかと思ったのですが、次のkubeletの設定について調べてみると、次のように /var/lib/kubelet/volume-plugins と、違う場所がポイントされています。

$ ps aux|grep volume-plugin-dir
root      1179 11.9  1.7 1848808 142048 ?      Ssl  Nov05  41:51 /usr/local/bin/kubelet    ...  --volume-plugin-dir=/var/lib/kubelet/volume-plugins

このため、cluster/examples/kubernetes/ceph の operator.yaml を編集して、FLEXVOLUME_DIR_PATHを設定しています。

$ cd cluster/examples/kubernetes/ceph

ここで、operator.yamlを編集してから、$ git diff operator.yamlを実行した結果は次のようになりました。

--- a/cluster/examples/kubernetes/ceph/operator.yaml
+++ b/cluster/examples/kubernetes/ceph/operator.yaml
@@ -308,8 +308,8 @@ spec:
         # - name: AGENT_TOLERATION_KEY
         #  value: "<KeyOfTheTaintToTolerate>"
         # Set the path where the Rook agent can find the flex volumes
-        # - name: FLEXVOLUME_DIR_PATH
-        #  value: "<PathToFlexVolumes>"
+        - name: FLEXVOLUME_DIR_PATH
+          value: "/var/lib/kubelet/volume-plugins/"
         # Rook Discover toleration. Will tolerate all taints with all keys.
         # Choose between NoSchedule, PreferNoSchedule and NoExecute:
         # - name: DISCOVER_TOLERATION

この operator.yaml を再び適用して、しばらくするとPodがリスタートされていきます。

$ kubectl apply -f operator.yaml

稼動の確認

ここまでの作業で無事にrook-cephが稼動するようになりました。

$ kubectl get all
NAME              READY     STATUS    RESTARTS   AGE
pod/cassandra-0   1/1       Running   0          6m
pod/cassandra-1   1/1       Running   0          4m
pod/cassandra-2   1/1       Running   0          1m

NAME                TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/cassandra   ClusterIP   None         <none>        9042/TCP   7h

NAME                         DESIRED   CURRENT   AGE
statefulset.apps/cassandra   3         3         6m

外部へのサービスの公開

ここまできて改めてtype: LoadBalancerなServiceを追加し、外部からcassandraにアクセスできるようにしました。

$ cat 03.cassandra-service.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: cassandra
  name: cassandracl
spec:
  ports:
  - port: 9042
  selector:
    app: cassandra
  type: LoadBalancer

$ kubectl apply -f 03.cassandra-service.yaml 
service/cassandracl created

ここまでで、外部からアクセス可能なCassandraクラスタが稼動しました。

$ kubectl get svc
NAME          TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
cassandra     ClusterIP      None           <none>        9042/TCP         24m
cassandracl   LoadBalancer   10.233.32.79   192.168.100.156   9042:30653/TCP   23m

突然動かなくなる

この後に電源停止を想定して、ノード全体をリスタートしたところ、うまく動かなくなりました。
状態を確認すると、次のようになっています。

$ kubectl describe pod/cassandra-0
...
Events:
  Type     Reason       Age              From               Message
  ----     ------       ----             ----               -------
  Normal   Scheduled    5m               default-scheduler  Successfully assigned cassandra/cassandra-0 to node3
  Warning  FailedMount  1m (x2 over 3m)  kubelet, node3     Unable to mount volumes for pod "cassandra-0_cassandra(243ea4ec-e188-11e8-8a8f-000db93312a4)": timeout expired waiting for volumes to attach or mount for pod "cassandra"/"cassandra-0". list of unmounted volumes=[cassandra-data]. list of unattached volumes=[cassandra-data default-token-kl6r4]

Podのログをみると起動しているのに、cassandra-0のIPがlookupできていません。

当初はkube-dnsを疑っていたのですが、StatefulSetを利用する時には、ClusterIP: NoneなService(svc)定義がないと、cassandra-0のIPが引けなくなる事に気がつきました。

そのためsvcは"cassandra"と"cassandracl"の2つを定義しています。

この結果、kube-dns(10.233.0.3)にクラスター名を問合せると、配下のPODのAレコード(IP)がRoundRobinで返ってきます。

$ nslookup cassandra.cassandra.svc.cluster.local 10.233.0.3
Server:         10.233.0.3
Address:        10.233.0.3#53

Name:   cassandra.cassandra.svc.cluster.local
Address: 10.233.100.160
Name:   cassandra.cassandra.svc.cluster.local
Address: 10.233.71.56
Name:   cassandra.cassandra.svc.cluster.local
Address: 10.233.74.92

当初、ClusterIP: Noneなsvc定義を削除してから、type: LoadBalancerなsvcを再定義していたので、再起動のタイミングで問題が判明したのだと思われます。

次のPVCが作成できない問題

次にStorageClassを利用してrook-cephから作成することができなくなりました。

$ kubectl -n cassandra describe pvc myclaim
Name:          myclaim
Namespace:     cassandra
StorageClass:  rook-ceph-block
Status:        Pending
Volume:        
Labels:        <none>
Annotations:   control-plane.alpha.kubernetes.io/leader={"holderIdentity":"dd36afbf-e457-11e8-8335-1a7fdbbc44fe","leaseDurationSeconds":15,"acquireTime":"2018-11-20T05:03:14Z","renewTime":"2018-11-20T05:08:29Z","lea...
               kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"myclaim","namespace":"cassandra"},"spec":{"accessModes":["ReadWr...
               volume.beta.kubernetes.io/storage-provisioner=ceph.rook.io/block
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      
Access Modes:  
Events:
  Type     Reason              Age              From                                                                                         Message
  ----     ------              ----             ----                                                                                         -------
  Normal   Provisioning        1m (x9 over 5m)  ceph.rook.io/block rook-ceph-operator-6cc45dfb48-kpkj6 dd36afbf-e457-11e8-8335-1a7fdbbc44fe  External provisioner is provisioning volume for claim "cassandra/myclaim"
  Warning  ProvisioningFailed  1m (x9 over 5m)  ceph.rook.io/block rook-ceph-operator-6cc45dfb48-kpkj6 dd36afbf-e457-11e8-8335-1a7fdbbc44fe  Failed to provision volume with StorageClass "rook-ceph-block": Failed to create rook block image replicapool/pvc-958a9ee5-ec81-11e8-849d-000db9331290: failed to create image pvc-958a9ee5-ec81-11e8-849d-000db9331290 in pool replicapool of size 5368709120: Failed to complete '': exit status 2. rbd: error opening pool 'replicapool': (2) No such file or directory
. output:
  Normal  ExternalProvisioning  16s (x78 over 5m)  persistentvolume-controller  waiting for a volume to be created, either by external provisioner "ceph.rook.io/block" or manually created by system administrator

toolbox.yamlを適応して、cephコマンドからpoolの状態を確認すると、replicapoolの存在が確認できない事が分かります。

$ kubectl -n rook-ceph exec -it rook-ceph-tools -- ceph osd lspools
$

poolの定義をみると、replicatedとerasureCodedの両方を指定していたので、構成例にもないのでシンプルにreplicatedだけにしました。

$ kubectl -n rook-ceph get pool replicapool -o yaml
apiVersion: ceph.rook.io/v1beta1
kind: Pool
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"ceph.rook.io/v1beta1","kind":"Pool","metadata":{"annotations":{},"name":"replicapool","namespace":"rook-ceph"},"spec":{"erasureCoded":{"codingChunks":1,"dataChunks":2},"replicated":{"size":3}}}
  creationTimestamp: 2018-11-20T05:02:46Z
  generation: 1
  name: replicapool
  namespace: rook-ceph
  resourceVersion: "32423166"
  selfLink: /apis/ceph.rook.io/v1beta1/namespaces/rook-ceph/pools/replicapool
  uid: 8539e6e1-ec81-11e8-849d-000db9331290
spec:
  erasureCoded:
    codingChunks: 1
    dataChunks: 2
  replicated:
    size: 3

poolを削除してから、spec.erasureCodedを削除し、spec.replicatedだけを残したYAMLファイルを再度apply -fで適用して無事に動きました。

これも"apply -f"しただけでは即時に反映されないため、以前にstorageclass.yamlを変更したタイミングから少し遅れてSCを作り直したタイミングで発覚したものと思われます。

【閑話休題】 トラブルシューティング

DashBoard

トラブルシューティングのために、Dashboard ServiceのタイプをClusterIPから、LoadBalancerに変更しました。

$ kubectl -n rook-ceph edit svc rook-ceph-mgr-dashboard
$ kubectl -n rook-ceph get svc rook-ceph-mgr-dashboard
NAME                      TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)          AGE
rook-ceph-mgr-dashboard   LoadBalancer   10.233.49.37   192.168.100.110   7000:32606/TCP   6h

ブラウザからDashboardを確認しましたが、あまりおもしろい結果は得られませんでした。
Dashboardは見栄えはともかく、あまりお勧めできません。

ToolBox

cephコマンドや、rdbコマンドを実行する時には、次のようにします。

あらかじめ toolbox.yaml を kubectl apply -f していることが前提です。

$ kubectl -n rook-ceph exec -it rook-ceph-tools bash
..# ceph osd status
# ceph osd status
+----+-------------------------------------+-------+-------+--------+---------+--------+---------+-----------+
| id |                 host                |  used | avail | wr ops | wr data | rd ops | rd data |   state   |
+----+-------------------------------------+-------+-------+--------+---------+--------+---------+-----------+
| 0  | rook-ceph-osd-id-0-6b577745cd-2dlcf | 35.4G |  421G |    0   |     0   |    0   |     0   | exists,up |
| 1  | rook-ceph-osd-id-1-56c8cb7449-wpmk9 | 21.0G |  206G |    0   |     0   |    0   |     0   | exists,up |
| 2  |  rook-ceph-osd-id-2-b8c5d98d5-cmkwh | 20.8G |  206G |    0   |     0   |    1   |    16   | exists,up |
| 3  |  rook-ceph-osd-id-3-894fc4d55-7ttr6 | 18.0G | 89.9G |    0   |     0   |    0   |     0   | exists,up |
| 4  | rook-ceph-osd-id-4-86d4557d64-85vvs | 17.5G | 90.4G |    0   |     0   |    1   |    90   | exists,up |
| 5  |  rook-ceph-osd-id-5-cbfdb6c8b-ws966 | 16.7G | 37.9G |    0   |     0   |    0   |     0   | exists,up |
| 6  |  rook-ceph-osd-id-6-ff948fbbd-dzvfd | 21.0G | 92.2G |    0   |     0   |    0   |     0   | exists,up |
+----+-------------------------------------+-------+-------+--------+---------+--------+---------+-----------+
[root@rook-ceph-tools /]# ceph df
GLOBAL:
    SIZE      AVAIL     RAW USED     %RAW USED
    1295G     1145G         150G         11.63
POOLS:
    NAME              ID     USED      %USED     MAX AVAIL     OBJECTS
    replicapool       1       134M      0.02          834G          48
    myfs-metadata     2      15962         0          834G          21
    myfs-data0        3         98         0          834G           2

toolbox.yamlを利用して、"ceph osd status"をalias設定しておくなどすると便利だと思われます。

alias show_ceph_osd_status="kubectl -n rook-ceph exec -it rook-ceph-tools -- ceph osd status"

以上

21
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
16