TECHSTEP

ITインフラ関連の記事を公開してます。

Rook-Ceph NFS Gatewayを利用する

はじめに

Rookが管理するストレージサービスは複数存在し、そのひとつにNFSがあります。Rookではnfsservers.nfs.rook.ioというCRDを利用することで、Kubernetes上にNFSを用意し、アプリケーションから利用することができます。

※参考リンク:

Rook Docs - NFS Server CRD

一方で、Rookの管理する別のストレージサービスであるCephにもNFSを利用できる機能が備わっています。Rook-CephではNFS-Ganeshaを利用してゲートウェイを用意し、CephのストレージリソースをNFS Gatewayを通じて利用できます。

Rook-Ceph NFS GatewayとRook NFS Serverとは、以下の点で違いがあります。

  • それぞれ専用のOperatorを利用し、他方のOperatorを必要としない
  • NFS server PodはバックエンドにCephFS / RGWを利用し、CephFS / RGWをPVC経由でNFS Podにマウントする必要はない

Rook-Ceph NFS Gatewaycephnfs.ceph.rook.ioというCRDが用意されており、これをデプロイすることでNFS Gatewayがデプロイされます。一方、Cephの公式ブログなどではこのCRDを利用せず、NFS関連の設定をイチから行う例が紹介されています。

今回は①手動でNFS用リソースを用意する場合②cephnfs.ceph.rook.io CRDを利用する場合の2つを紹介します。

検証環境

今回は以下の検証環境を利用しました。

  • Rook version: v1.2
  • Kubernetes version:v1.17.4
  • Kubernetes構成:master / worker それぞれ1ノードずつ用意
  • その他:AzureVM上にkubeadmを利用して構築、CNIはflannelを利用

事前準備

今回の紹介内容に共通で必要となるRook-Cephクラスターをあらかじめ用意しておきます。

# 3つのyamlファイルをデプロイ
[root@rookmaster ceph]# kubectl apply -f common.yaml
[root@rookmaster ceph]# kubectl apply -f operator.yaml
[root@rookmaster ceph]# kubectl apply -f cluster-test.yaml
[root@rookmaster ceph]# kubectl get pods -n rook-ceph
NAME                                                   READY   STATUS      RESTARTS   AGE
csi-cephfsplugin-cdtdj                                 3/3     Running     0          22m
csi-cephfsplugin-provisioner-7b8fbf88b4-78j7l          4/4     Running     0          22m
csi-cephfsplugin-provisioner-7b8fbf88b4-rqsqp          4/4     Running     0          22m
csi-rbdplugin-9xvv4                                    3/3     Running     0          22m
csi-rbdplugin-provisioner-6b8b4d558c-rzbdd             5/5     Running     0          22m
csi-rbdplugin-provisioner-6b8b4d558c-spvjz             5/5     Running     0          22m
rook-ceph-crashcollector-rookworker-58db759fb9-nwlvh   1/1     Running     0          19m
rook-ceph-mgr-a-5955db5c76-wn56j                       1/1     Running     0          20m
rook-ceph-mon-a-7b99cd7876-lt55t                       1/1     Running     0          20m
rook-ceph-operator-69f856fc5f-z85hd                    1/1     Running     0          23m
rook-ceph-osd-0-769b8db464-flv6l                       1/1     Running     0          19m
rook-ceph-osd-prepare-rookworker-x5n8k                 0/1     Completed   0          20m
rook-discover-ts7j2                                    1/1     Running     0          22m
[root@rookmaster ceph]#

今回利用したcluster-test.yamlは以下の通りです。

apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
  name: rook-ceph
  namespace: rook-ceph
spec:
  cephVersion:
    image: ceph/ceph:v14.2.8
    allowUnsupported: true
  dataDirHostPath: /var/lib/rook
  skipUpgradeChecks: false
  continueUpgradeAfterChecksEvenIfNotHealthy: false
  mon:
    count: 1
    allowMultiplePerNode: true
  dashboard:
    enabled: true
    ssl: true
  monitoring:
    enabled: false
    rulesNamespace: rook-ceph
  network:
    hostNetwork: false
  rbdMirroring:
    workers: 0
  crashCollector:
    disable: false
  mgr:
    modules:
    - name: pg_autoscaler
      enabled: true
  storage:
    useAllNodes: true
    useAllDevices: false
    config:
      databaseSizeMB: "1024" 
      journalSizeMB: "1024"  
      osdsPerDevice: "1"
## デバイスを指定 ##
    devices:
    - name: "sdc"

なお、今回は検証のためOSDの数が少なく、ceph statusで確認するとクラスターの状態はWarning状態となりますが、今回はここは気にせずに検証を行いました。

[root@rookmaster ceph]# kubectl apply -f toolbox.yaml

[root@rookmaster ceph]# kubectl exec -it -n rook-ceph $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- ceph status
  cluster:
    id:     5a17c461-19ee-4561-a704-5a727d11bdca
    health: HEALTH_WARN
            OSD count 1 < osd_pool_default_size 3

  services:
    mon: 1 daemons, quorum a (age 25m)
    mgr: a(active, since 25m)
    osd: 1 osds: 1 up (since 24m), 1 in (since 24m)

  data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage:   1.0 GiB used, 63 GiB / 64 GiB avail
    pgs:

[root@rookmaster ceph]#

※参考リンク:

Rook Docs - Ceph Examples (v1.2)

Rook Docs - Ceph Cluster CRD (v1.2)

1. 手動でリソースを用意する場合

まずは手動で各種リソースを用意する場合です。こちらは以下のリンクを参考にしています。なお、以下リンク先ではminikubeの利用を前提としております。

※参考リンク:

Ceph blog - Deploying a Ceph+NFS Server Cluster with Rook

Ceph Docs - NFS

CephFS Filesystemの作成

まずはCephFSを作成します。ここではToolbox Podから各種コマンドを実行して作成します。またデフォルトではOSD replicated sizeは3になりますが、今回はOSDを1つしか用意していないため、ここでは1に設定を変更します。

# Toolbox Podにログイン
[root@rookmaster ceph]# kubectl exec -it -n rook-ceph $(kubectl get pods -n rook-ceph -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') bash
bash: warning: setlocale: LC_CTYPE: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_COLLATE: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_MESSAGES: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_NUMERIC: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_TIME: cannot change locale (en_US.UTF-8): No such file or directory

# CephFS作成
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph fs volume create myfs
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph fs ls
name: myfs, metadata pool: cephfs.myfs.meta, data pools: [cephfs.myfs.data ]

# OSD size変更
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph osd pool set cephfs.myfs.meta size 1
set pool 1 size to 1
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph osd pool set cephfs.myfs.data size 1
set pool 2 size to 1
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph osd pool ls
cephfs.myfs.meta
cephfs.myfs.data

NFS Server Clusterの作成

次にNFS Server用のクラスターを作成します。NFS Ganeshaにはクライアントデータを保護するためのリカバリー機能があり、このデータの保存先としてRADOSを利用することができます。Rookはこのリカバリー機能を利用するよう自動的に設定を行い、再起動時のリカバリーコンフリクトが発生するのを防ぎます。

※参考リンク:

Active/Active NFS Server Recovery over CephFS (PDF)

# NFS Ganesha用のPoolを作成
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph osd pool create nfs-ganesha 64
pool 'nfs-ganesha' created
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph osd pool set nfs-ganesha size 1
set pool 3 size to 1

# NFS Server Cluster作成
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph orchestrator nfs add mynfs nfs-ganesha ganesha

# 確認
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph osd pool ls
cephfs.myfs.meta
cephfs.myfs.data
nfs-ganesha
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph orchestrator service ls
mds myfs.a rookworker rook-ceph-mds-myfs-a-6bbdb8dfb9-9rpmx None None
mds myfs.b rookworker rook-ceph-mds-myfs-b-85d5cdf8-jjtw6 None None
mgr a rookworker rook-ceph-mgr-a-5955db5c76-wn56j None None
mon a rookworker rook-ceph-mon-a-7b99cd7876-lt55t None None
nfs mynfs.a rookworker rook-ceph-nfs-mynfs-a-74d7d4444b-r5w5l None rados://nfs-ganesha/ganesha/conf-mynfs.a
osd 0 rookworker rook-ceph-osd-0-769b8db464-flv6l None None
[root@rook-ceph-tools-565698c784-hjzxg /]# 

なお、上記クラスターはceph orchestrator nfs updateでスケールアウトすることができます。

[root@rook-ceph-tools-565698c784-hjzxg /]# ceph orchestrator nfs update mynfs 2
[root@rook-ceph-tools-565698c784-hjzxg /]# ceph orchestrator service ls
mds myfs.a rookworker rook-ceph-mds-myfs-a-6bbdb8dfb9-9rpmx None None
mds myfs.b rookworker rook-ceph-mds-myfs-b-85d5cdf8-jjtw6 None None
mgr a rookworker rook-ceph-mgr-a-5955db5c76-wn56j None None
mon a rookworker rook-ceph-mon-a-7b99cd7876-lt55t None None
nfs mynfs.a rookworker rook-ceph-nfs-mynfs-a-74d7d4444b-r5w5l None rados://nfs-ganesha/ganesha/conf-mynfs.a
nfs mynfs.b rookworker rook-ceph-nfs-mynfs-b-649cf6469f-gw625 None rados://nfs-ganesha/ganesha/conf-mynfs.b
osd 0 rookworker rook-ceph-osd-0-769b8db464-flv6l None None

ここまでの操作により、Kubernetes上では以下のようにPodが作成されています。

[root@rookmaster ceph]# kubectl get pods -n rook-ceph
NAME                                                  READY   STATUS      RESTARTS   AGE
csi-cephfsplugin-cdtdj                                3/3     Running     0          37m
csi-cephfsplugin-provisioner-7b8fbf88b4-78j7l         4/4     Running     0          37m
csi-cephfsplugin-provisioner-7b8fbf88b4-rqsqp         4/4     Running     0          37m
csi-rbdplugin-9xvv4                                   3/3     Running     0          37m
csi-rbdplugin-provisioner-6b8b4d558c-rzbdd            5/5     Running     0          37m
csi-rbdplugin-provisioner-6b8b4d558c-spvjz            5/5     Running     0          37m
rook-ceph-crashcollector-rookworker-bc69898c5-nhw6w   1/1     Running     0          7m31s
rook-ceph-mds-myfs-a-6bbdb8dfb9-9rpmx                 1/1     Running     0          7m31s  ★
rook-ceph-mds-myfs-b-85d5cdf8-jjtw6                   1/1     Running     0          7m30s  ★
rook-ceph-mgr-a-5955db5c76-wn56j                      1/1     Running     0          35m
rook-ceph-mon-a-7b99cd7876-lt55t                      1/1     Running     0          36m
rook-ceph-nfs-mynfs-a-74d7d4444b-r5w5l                2/2     Running     0          5m7s  ★
rook-ceph-operator-69f856fc5f-z85hd                   1/1     Running     0          38m
rook-ceph-osd-0-769b8db464-flv6l                      1/1     Running     0          34m
rook-ceph-osd-prepare-rookworker-x5n8k                0/1     Completed   0          35m
rook-ceph-tools-565698c784-hjzxg                      1/1     Running     0          14m
rook-discover-ts7j2                                   1/1     Running     0          38m

NFS-Ganesha Exportの設定

この時点ではNFS ServerにはExportの設定がされておらず、外部から利用することはできません。ここでは、Ceph Dashboard経由でExport用の設定を追加し、外部からNFS Serverを利用できるようにします。

まずはCeph Dashboardにアクセスできるよう、ServiceリソースのタイプをNodePortに変更します。

# Serviceの確認
[root@rookmaster ceph]# kubectl get service -n rook-ceph
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
csi-cephfsplugin-metrics   ClusterIP   10.100.141.23    <none>        8080/TCP,8081/TCP   34m
csi-rbdplugin-metrics      ClusterIP   10.110.84.171    <none>        8080/TCP,8081/TCP   34m
rook-ceph-mgr              ClusterIP   10.107.200.238   <none>        9283/TCP            32m
rook-ceph-mgr-dashboard    ClusterIP   10.102.243.246   <none>        8443/TCP            32m
rook-ceph-mon-a            ClusterIP   10.100.24.136    <none>        6789/TCP,3300/TCP   33m
rook-ceph-nfs-mynfs-a      ClusterIP   10.104.188.15    <none>        2049/TCP            2m13s

# NodePortに変更
[root@rookmaster ceph]# kubectl patch service -n rook-ceph -p '{"spec":{"type": "NodePort"}}' rook-ceph-mgr-dashboard
service/rook-ceph-mgr-dashboard patched

# 変更後
[root@rookmaster ceph]# kubectl get service -n rook-ceph
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
csi-cephfsplugin-metrics   ClusterIP   10.100.141.23    <none>        8080/TCP,8081/TCP   35m
csi-rbdplugin-metrics      ClusterIP   10.110.84.171    <none>        8080/TCP,8081/TCP   35m
rook-ceph-mgr              ClusterIP   10.107.200.238   <none>        9283/TCP            33m
rook-ceph-mgr-dashboard    NodePort    10.102.243.246   <none>        8443:32314/TCP      34m
rook-ceph-mon-a            ClusterIP   10.100.24.136    <none>        6789/TCP,3300/TCP   34m
rook-ceph-nfs-mynfs-a      ClusterIP   10.104.188.15    <none>        2049/TCP            3m37s
[root@rookmaster ceph]# 

続いて、設定変更用のjsonファイルを用意します。ここではexport.jsonという以下のファイルを用意します。

{
      "cluster_id": "mynfs",
      "path": "/",
      "fsal": {"name": "CEPH", "user_id":"admin", "fs_name": "myfs", "sec_label_xattr": null},
      "pseudo": "/cephfs",
      "tag": null,
      "access_type": "RW",
      "squash": "no_root_squash",
      "protocols": [4],
      "transports": ["TCP"],
      "security_label": true,
      "daemons": ["mynfs.a"],
      "clients": []
}

各項目は以下のように利用します。

  • path:関連するCephFSプール内のExport Path
  • fsal:File System Abstraction Layerの設定
    • name:NFS Ganeshaの利用するバックエンドを指定。CephFSの場合はCEPH、RGWの場合はRGW
  • pseudo:ターゲットNFSのExport Path。マウント時はここで指定したパスを指定します。
  • access_type:RO / RWなどアクセス方式を選択
  • squash:ルート権限無効化のオプション
  • protocols:NFSプロトコル
  • daemons:利用するDaemonを指定

※参考リンク:

debian manpages - GANESHA-EXPORT-CONFIG(8)

SUSE Doc - 14 NFS Ganesha: NFS経由でのCephデータのエクスポート

次に上記jsonファイルをCeph Dashboard経由で反映するためのスクリプトを用意します。ここではrun-backend-rook-api-request.shというファイルを利用します。スクリプトの内容は以下の通りです。

#!/bin/bash

#
# Query k8s to determine where the mgr is running and how to reach the
# dashboard from the local machine. This assumes that the dashboard is being
# exposed via a nodePort service
CURR_DIR=`pwd`
K8S_NAMESPACE='rook-ceph'

HOST=$(kubectl get pods -n $K8S_NAMESPACE -l "app=rook-ceph-mgr" -o json | jq .items[0].spec.nodeName | sed s/\"//g)
if [ "$HOST" = "minikube" ]; then
        HOST=$(minikube ip)
fi
PORT=$(kubectl get service -n $K8S_NAMESPACE rook-ceph-mgr-dashboard -o yaml | grep nodePort: | awk '{print $2}')
API_URL="https://${HOST}:${PORT}"

#
# Rook automagically sets up an "admin" account with a random PW and stuffs
# that into a k8s secret. This fetches it.
#
PASSWD=$(kubectl -n $K8S_NAMESPACE get secret rook-ceph-dashboard-password -o yaml | grep "password:" | awk '{print $2}' | base64 --decode)

if [ "$API_URL" = "null" ]; then
        echo "Couldn't retrieve API URL, exiting..." >&2
        exit 1
fi
cd $CURR_DIR

TOKEN=`curl --insecure -s -H "Content-Type: application/json" -X POST \
            -d "{\"username\":\"admin\",\"password\":\"${PASSWD}\"}"  $API_URL/api/auth \
                        | jq .token | sed -e 's/"//g'`

echo "METHOD: $1"
echo "URL: ${API_URL}${2}"
echo "DATA: $3"
echo ""

curl --insecure -s -b /tmp/cd-cookie.txt -H "Authorization: Bearer $TOKEN " \
         -H "Content-Type: application/json" -X $1 -d "$3" ${API_URL}$2 | jq

上記スクリプトではjqコマンドを利用しているため、コマンドをインストールしていない場合は適宜インストールします。

では上記スクリプトを実行します。実行結果でエラー等が返ってこなければjsonファイルの反映に成功しています。

# スクリプト実行
[root@rookmaster ceph]# ./run-backend-rook-api-request.sh POST /api/nfs-ganesha/export "$(cat export.json)"
METHOD: POST
URL: https://rookworker:32314/api/nfs-ganesha/export
DATA: {
      "cluster_id": "mynfs",
      "path": "/",
      "fsal": {"name": "CEPH", "user_id":"admin", "fs_name": "myfs", "sec_label_xattr": null},
      "pseudo": "/cephfs",
      "tag": null,
      "access_type": "RW",
      "squash": "no_root_squash",
      "protocols": [4],
      "transports": ["TCP"],
      "security_label": true,
      "daemons": ["mynfs.a"],
      "clients": []
}

{
  "squash": "no_root_squash",
  "access_type": "RW",
  "tag": null,
  "cluster_id": "mynfs",
  "fsal": {
    "fs_name": "myfs",
    "sec_label_xattr": null,
    "user_id": "admin",
    "name": "CEPH"
  },
  "daemons": [
    "mynfs.a"
  ],
  "path": "/",
  "export_id": 1,
  "protocols": [
    4
  ],
  "clients": [],
  "pseudo": "/cephfs",
  "security_label": true,
  "transports": [
    "TCP"
  ]
}

NFS Serverの利用

ここまででNFS Ganeshaの設定は完了しました。あとはNFS ServerのServiceリソースをNodePortタイプに変更し、外部からアクセスできるようにします。

# Serviceの確認
[root@rookmaster ceph]# kubectl get service -n rook-ceph
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
csi-cephfsplugin-metrics   ClusterIP   10.100.141.23    <none>        8080/TCP,8081/TCP   44m
csi-rbdplugin-metrics      ClusterIP   10.110.84.171    <none>        8080/TCP,8081/TCP   44m
rook-ceph-mgr              ClusterIP   10.107.200.238   <none>        9283/TCP            42m
rook-ceph-mgr-dashboard    NodePort    10.102.243.246   <none>        8443:32314/TCP      42m
rook-ceph-mon-a            ClusterIP   10.100.24.136    <none>        6789/TCP,3300/TCP   43m
rook-ceph-nfs-mynfs-a      ClusterIP   10.104.188.15    <none>        2049/TCP            12m

# NodePortに変更
[root@rookmaster ceph]# kubectl patch service -n rook-ceph -p '{"spec":{"type": "NodePort"}}' rook-ceph-nfs-mynfs-a
service/rook-ceph-nfs-mynfs-a patched
[root@rookmaster ceph]# 

# 変更後
[root@rookmaster ceph]# kubectl get service -n rook-ceph
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
csi-cephfsplugin-metrics   ClusterIP   10.100.141.23    <none>        8080/TCP,8081/TCP   45m
csi-rbdplugin-metrics      ClusterIP   10.110.84.171    <none>        8080/TCP,8081/TCP   45m
rook-ceph-mgr              ClusterIP   10.107.200.238   <none>        9283/TCP            43m
rook-ceph-mgr-dashboard    NodePort    10.102.243.246   <none>        8443:32314/TCP      43m
rook-ceph-mon-a            ClusterIP   10.100.24.136    <none>        6789/TCP,3300/TCP   43m
rook-ceph-nfs-mynfs-a      NodePort    10.104.188.15    <none>        2049:30969/TCP      13m

これでNFS Serverを外部から利用できるようになりました。今回はテストとして、Kubernetes MasterノードからNFS Serverをマウントし、テスト用ファイルが編集できるかを確認してみます。

# マウント
[root@rookmaster ceph]# mkdir -p /mnt/rook
[root@rookmaster ceph]# mount -t nfs -o port=30969 10.5.0.5:/cephfs /mnt/rook/
[root@rookmaster ceph]# df -h
Filesystem        Size  Used Avail Use% Mounted on
devtmpfs          3.9G     0  3.9G   0% /dev
tmpfs             3.9G     0  3.9G   0% /dev/shm
tmpfs             3.9G  9.6M  3.9G   1% /run

(中略)

10.5.0.5:/cephfs   60G     0   60G   0% /mnt/rook

# ファイルの書き込み
[root@rookmaster ceph]# touch /mnt/rook/test.txt
[root@rookmaster ceph]# ls -l /mnt/rook/
total 0
-rw-r--r-- 1 nobody nobody 0 Apr  4 00:58 test.txt
[root@rookmaster ceph]# dd if=/dev/zero of=/mnt/rook/testfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 22.4873 s, 47.7 MB/s
[root@rookmaster ceph]# ls -l /mnt/rook/
total 1048576
-rw-r--r-- 1 nobody nobody 1073741824 Apr  4 01:01 testfile
-rw-r--r-- 1 nobody nobody          0 Apr  4 00:58 test.txt
[root@rookmaster ceph]#

2. CRDを利用する場合

次にcephnfs.ceph.rook.io CRDを利用する場合を紹介します。といっても、基本的な流れは1つ目の方法と同じで、各種リソースの作成にCRDを利用する点が違うだけです。

Ceph Filesystemの作成

まずはcephfilesystem.ceph.rook.io CRDをデプロイしCephFSを用意します。

# CephFS作成
[root@rookmaster ceph]# kubectl apply -f filesystem-test.yaml

# 確認
[root@rookmaster ceph]# kubectl get cephfilesystem.ceph.rook.io -n rook-ceph
NAME   ACTIVEMDS   AGE
myfs   1           23s

[root@rookmaster ceph]# kubectl get pods -n rook-ceph
NAME                                                   READY   STATUS        RESTARTS   AGE
csi-cephfsplugin-kb9r4                                 3/3     Running       0          10m
csi-cephfsplugin-provisioner-7b8fbf88b4-kg59m          4/4     Running       0          10m
csi-cephfsplugin-provisioner-7b8fbf88b4-w248r          4/4     Running       0          10m
csi-rbdplugin-c2ck4                                    3/3     Running       0          10m
csi-rbdplugin-provisioner-6b8b4d558c-lkx62             5/5     Running       0          10m
csi-rbdplugin-provisioner-6b8b4d558c-tz7pg             5/5     Running       0          10m
rook-ceph-crashcollector-rookworker-58db759fb9-zqtkz   1/1     Terminating   0          9m14s
rook-ceph-crashcollector-rookworker-bc69898c5-z8dzr    1/1     Running       0          23s
rook-ceph-mds-myfs-a-75fb544555-5nqc6                  1/1     Running       0          23s
rook-ceph-mds-myfs-b-749854fc88-6468d                  1/1     Running       0          23s
rook-ceph-mgr-a-5c558f45fd-gqvtk                       1/1     Running       0          10m
rook-ceph-mon-a-7c698b79cd-jdrgn                       1/1     Running       0          10m
rook-ceph-operator-69f856fc5f-zhhtk                    1/1     Running       0          11m
rook-ceph-osd-0-65f9d5b7cd-lzm9m                       1/1     Running       0          9m14s
rook-ceph-osd-prepare-rookworker-rnw7j                 0/1     Completed     0          9m55s
rook-discover-6w4mr                                    1/1     Running       0          11m

# Poolも自動的に作成される
[root@rookmaster ceph]# kubectl apply -f toolbox.yaml
[root@rookmaster ceph]# kubectl exec -it -n rook-ceph $(kubectl get pods -n rook-ceph -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- ceph osd pool ls
myfs-metadata
myfs-data0

今回利用したfilesystem-test.yamlは以下の通りです。

apiVersion: ceph.rook.io/v1
kind: CephFilesystem
metadata:
  name: myfs
  namespace: rook-ceph
spec:
  metadataPool:
    replicated:
      size: 1
  dataPools:
    - failureDomain: osd
      replicated:
        size: 1
  preservePoolsOnDelete: false
  metadataServer:
    activeCount: 1
    activeStandby: true

※参考リンク:

Rook Docs - Ceph Shared Filesystem CRD (v1.2)

TECHSTEP - Rook-Cephの機能紹介(File Storage編)

NFS Server Clusterの作成

続いてcephnfs.ceph.rook.ioCRDをデプロイします。今回はnfs-test.yamlという以下のyamlファイルを利用します。

apiVersion: ceph.rook.io/v1
kind: CephNFS
metadata:
  name: my-nfs
  namespace: rook-ceph
spec:
  rados:
    pool: myfs-data0
    # RADOS namespace where NFS client recovery data is stored in the pool.
    namespace: nfs-ns
  server:
    active: 1

各パラメータは以下のような設定内容です。

  • spec.rados.poolNFSクライアントのリカバリデータを保存するRADOSプール
  • spec.rados.namespace:上記RADOSプールのあるnamespace
  • spec.server.active:アクティブなNFSサーバーの数

それでは上記ファイルをデプロイします。

# デプロイ
[root@rookmaster ceph]# kubectl apply -f nfs-test.yaml

# 確認
[root@rookmaster ceph]# kubectl get cephnfs.ceph.rook.io -n rook-ceph
NAME     AGE
my-nfs   29s
[root@rookmaster ceph]# kubectl get pods -n rook-ceph
NAME                                                  READY   STATUS      RESTARTS   AGE
csi-cephfsplugin-kb9r4                                3/3     Running     0          15m
csi-cephfsplugin-provisioner-7b8fbf88b4-kg59m         4/4     Running     0          15m
csi-cephfsplugin-provisioner-7b8fbf88b4-w248r         4/4     Running     0          15m
csi-rbdplugin-c2ck4                                   3/3     Running     0          15m
csi-rbdplugin-provisioner-6b8b4d558c-lkx62            5/5     Running     0          15m
csi-rbdplugin-provisioner-6b8b4d558c-tz7pg            5/5     Running     0          15m
rook-ceph-crashcollector-rookworker-bc69898c5-z8dzr   1/1     Running     0          5m14s
rook-ceph-mds-myfs-a-75fb544555-5nqc6                 1/1     Running     0          5m14s
rook-ceph-mds-myfs-b-749854fc88-6468d                 1/1     Running     0          5m14s
rook-ceph-mgr-a-5c558f45fd-gqvtk                      1/1     Running     0          15m
rook-ceph-mon-a-7c698b79cd-jdrgn                      1/1     Running     0          15m
rook-ceph-nfs-my-nfs-a-5b74794589-r6k9j               2/2     Running     0          40s
rook-ceph-operator-69f856fc5f-zhhtk                   1/1     Running     0          15m
rook-ceph-osd-0-65f9d5b7cd-lzm9m                      1/1     Running     0          14m
rook-ceph-osd-prepare-rookworker-rnw7j                0/1     Completed   0          14m
rook-ceph-tools-565698c784-68lct                      1/1     Running     0          4m3s
rook-discover-6w4mr                                   1/1     Running     0          15m
[root@rookmaster ceph]# kubectl get service -n rook-ceph
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
csi-cephfsplugin-metrics   ClusterIP   10.104.106.152   <none>        8080/TCP,8081/TCP   16m
csi-rbdplugin-metrics      ClusterIP   10.103.195.149   <none>        8080/TCP,8081/TCP   16m
rook-ceph-mgr              ClusterIP   10.97.164.91     <none>        9283/TCP            15m
rook-ceph-mgr-dashboard    ClusterIP   10.96.186.101    <none>        8443/TCP            15m
rook-ceph-mon-a            ClusterIP   10.99.213.248    <none>        6789/TCP,3300/TCP   16m
rook-ceph-nfs-my-nfs-a     ClusterIP   10.104.9.170     <none>        2049/TCP            80s
[root@rookmaster ceph]# 

NFS-Ganesha Exportの設定 / NFS Serverの利用

さて、ここまででNFS Serverのデプロイが完了しましたが、先ほど紹介した1つ目の方法と同様に、デフォルトではExport設定がなく外部からアクセスすることができません。これ以降は1つ目の方法と全く同じ手順で外部からのアクセスを可能にします。

# ServiceをNodePortタイプに変更

[root@rookmaster ceph]# kubectl patch service -n rook-ceph -p '{"spec": {"type": "NodePort"}}' rook-ceph-mgr-dashboard
[root@rookmaster ceph]# kubectl patch service -n rook-ceph -p '{"spec":{"type": "NodePort"}}' rook-ceph-nfs-my-nfs-a

[root@rookmaster ceph]# kubectl get service -n rook-ceph
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
csi-cephfsplugin-metrics   ClusterIP   10.104.106.152   <none>        8080/TCP,8081/TCP   5h55m
csi-rbdplugin-metrics      ClusterIP   10.103.195.149   <none>        8080/TCP,8081/TCP   5h55m
rook-ceph-mgr              ClusterIP   10.97.164.91     <none>        9283/TCP            5h54m
rook-ceph-mgr-dashboard    NodePort    10.96.186.101    <none>        8443:32110/TCP      5h55m
rook-ceph-mon-a            ClusterIP   10.99.213.248    <none>        6789/TCP,3300/TCP   5h55m
rook-ceph-nfs-my-nfs-a     NodePort    10.104.9.170     <none>        2049:30070/TCP      5h40m

# Ceph Dashboard経由でExport設定を反映
# export-nfscrd.jsonはdaemons設定のみ"my-nfs.a"に変更
[root@rookmaster ceph]# ./run-backend-rook-api-request.sh POST /api/nfs-ganesha/export "$(cat export-nfscrd.json)"
METHOD: POST
URL: https://rookworker:32110/api/nfs-ganesha/export
DATA: {
      "cluster_id": "mynfs",
      "path": "/",
      "fsal": {"name": "CEPH", "user_id":"admin", "fs_name": "myfs", "sec_label_xattr": null},
      "pseudo": "/cephfs",
      "tag": null,
      "access_type": "RW",
      "squash": "no_root_squash",
      "protocols": [4],
      "transports": ["TCP"],
      "security_label": true,
      "daemons": ["my-nfs.a"],
      "clients": []
}

{
  "squash": "no_root_squash",
  "access_type": "RW",
  "tag": null,
  "cluster_id": "mynfs",
  "fsal": {
    "fs_name": "myfs",
    "sec_label_xattr": null,
    "user_id": "admin",
    "name": "CEPH"
  },
  "daemons": [
    "my-nfs.a"
  ],
  "path": "/",
  "export_id": 1,
  "protocols": [
    4
  ],
  "clients": [],
  "pseudo": "/cephfs",
  "security_label": true,
  "transports": [
    "TCP"
  ]
}


# マウント
[root@rookmaster ceph]# mount -t nfs -o port=30070 10.5.0.5:/cephfs /mnt/rook/
[root@rookmaster ceph]# df -h
Filesystem        Size  Used Avail Use% Mounted on
devtmpfs          3.9G     0  3.9G   0% /dev
tmpfs             3.9G     0  3.9G   0% /dev/shm
tmpfs             3.9G  9.6M  3.9G   1% /run

(中略)

10.5.0.5:/cephfs   60G     0   60G   0% /mnt/rook

[root@rookmaster ceph]# touch /mnt/rook/test.txt
[root@rookmaster ceph]# ls -l /mnt/rook/
total 0
-rw-r--r-- 1 nobody nobody 0 Apr  4 08:14 test.txt
[root@rookmaster ceph]# dd if=/dev/zero of=/mnt/rook/testfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 22.4502 s, 47.8 MB/s
[root@rookmaster ceph]#

また、cephnfs.ceph.rook.ioCRDをデプロイすると、NFS Server Pod毎のConfigMapが作成されます。この中身はganesha.confの設定内容であり、こちらを編集してPodを再起動することでExportの設定を行うことができると思われますが、今回はこちらの検証は行っていません。

[root@rookmaster ceph]# kubectl get cm -n rook-ceph
NAME                        DATA   AGE
local-device-rookworker     1      25h
rook-ceph-csi-config        1      25h
rook-ceph-mon-endpoints     4      25h
rook-ceph-nfs-my-nfs-a      1      24h
rook-ceph-operator-config   0      25h
rook-config-override        1      25h
[root@rookmaster ceph]# kubectl describe cm rook-ceph-nfs-my-nfs-a -n rook-ceph
Name:         rook-ceph-nfs-my-nfs-a
Namespace:    rook-ceph
Labels:       app=rook-ceph-nfs
              ceph_nfs=my-nfs
              instance=a
              rook_cluster=rook-ceph
Annotations:  <none>

Data
====
config:
----

NFS_CORE_PARAM {
  Enable_NLM = false;
  Enable_RQUOTA = false;
  Protocols = 4;
}

CACHEINODE {
  Dir_Chunk = 0;
  NParts = 1;
  Cache_Size = 1;
}

EXPORT_DEFAULTS {
  Attr_Expiration_Time = 0;
}

NFSv4 {
  Delegations = false;
  RecoveryBackend = 'rados_cluster';
  Minor_Versions = 1, 2;
}

RADOS_KV {
  ceph_conf = '/etc/ceph/ceph.conf';
  userid = admin;
  nodeid = my-nfs.a;
  pool = "myfs-data0";
  namespace = "nfs-ns";
}

RADOS_URLS {
  ceph_conf = '/etc/ceph/ceph.conf';
  userid = admin;
  watch_url = 'rados://myfs-data0/nfs-ns/conf-my-nfs.a';
}

%url  rados://myfs-data0/nfs-ns/conf-my-nfs.a

Events:  <none>
[root@rookmaster ceph]#

参考ドキュメント

Rook Docs - Ceph NFS Gateway CRD (v1.2)

GitHub - rook/rook: Ceph NFS-Ganesha CRD