Ceph 块存储的使用
块存储一般用于一个Pod挂载一块存储使用,相当于一个服务器新挂了一个盘,只给一个应用使用。
官方文档地址: Block Storage
创建 StorageClass 和 Pool
在 Rook 可以配置存储之前,需要创建 StorageClass
和 CephBlockPool
。这将允许 Kubernetes 在配置持久卷时与 Rook 进行互操作.
此示例要求每个节点至少有 1 个 OSD,每个 OSD 位于 3 个不同的节点上
每个 OSD 必须位于不同的节点上,因为 failureDomain 设置为 host,replicated.size 设置为 3。因为这里是试验环境,所以将副本数设置成了2(不能设置为1),生产环境最少为3,且要小于等于osd的数量。
进入
rook/cluster/examples/kubernetes/ceph
目录,查看csi/rbd/storageclass.yaml
文件,内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
name: replicapool
namespace: rook-ceph
spec:
failureDomain: host # 容灾方案依据,可选值为 osd 或者 host,一般以 host 方案配置容灾
replicated:
size: 2 # 副本数,生产环境最少为3,且要小于等于osd的数量
requireSafeReplicaSize: true # 如果将副本数设置为 1,则需要将该参数设置为 false(强烈不建议)。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rook-ceph-block # storageClass 的名称,创建 pvc 时需要填写该名称
provisioner: rook-ceph.rbd.csi.ceph.com # 使用的 csi 存储驱动,可以使用 kubectl get csidrivers 查看存在的 csi驱动
parameters:
clusterID: rook-ceph # namespace:cluster
pool: replicapool
imageFormat: "2" # Ceph RBD 相关的配置
imageFeatures: layering # Ceph RBD 相关的配置
csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph # namespace:cluster
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph # namespace:cluster
csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph # namespace:cluster
csi.storage.k8s.io/fstype: ext4 # 创建卷文件系统类型
allowVolumeExpansion: true # 是否允许pvc扩容
reclaimPolicy: Delete # pvc 的回收策略使用以下命令创建 StorageClass 和 pool
1
2
3# kubectl create -f csi/rbd/storageclass.yaml -n rook-ceph
cephblockpool.ceph.rook.io/replicapool created
storageclass.storage.k8s.io/rook-ceph-block created查看创建的 pool 和 storageClass(StorageClass 没有 namespace 隔离性)
1
2
3
4
5
6
7# kubectl get cephblockpool -n rook-ceph
NAME AGE
replicapool 107s
# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate true 115s此时可以在 ceph Dashboard 查看到该 Pool,如果没有显示则说明 pool 没有创建成功
如果没有创建成功,有可能是 k8s 节点的配置不足导致,可以适当升级虚拟机配置
Deployment 挂载块存储 (persistentVolumeClaim)
Deployment 类型的资源创建 PVC 时只需要指定 storageClassName
为之前创建的 StorageClass 的名称既可连接到 rook 的 Ceph。
创建一个 MySQL 服务,该服务的资源清单文件所在位置为
rook/cluster/examples/kubernetes/mysql.yaml
,1
2
3
4# kubectl create -f mysql.yaml
service/wordpress-mysql created
persistentvolumeclaim/mysql-pv-claim created
deployment.apps/wordpress-mysql created该文件中有一段创建 pvc 的配置,如下
1
2
3
4
5
6
7
8
9
10
11
12
13apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
labels:
app: wordpress
spec:
storageClassName: rook-ceph-block # 需要连接的 StorageClass 名称
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20GiMySQL deployment 中的 volumes 配置了挂载该 pvc:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: changeme
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim: # DaemonSet 使用的模块
claimName: mysql-pv-claim- claimName 为 pvc 的名称
因为 MySQL 的数据不能多个MySQL实例连接同一个存储,所以一般只能用块存储。相当于新加了一块盘给MySQL使用。
- claimName 为 pvc 的名称
然后可以查看创建的 pvc 和 pv
1
2
3
4
5
6
7# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-ac8fd495-39a2-4a2d-86da-69e85088e45e 20Gi RWO Delete Bound default/mysql-pv-claim rook-ceph-block 4m14s
# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-ac8fd495-39a2-4a2d-86da-69e85088e45e 20Gi RWO rook-ceph-block 4m21s此时在 ceph 的 Dashboard 上面也可以看到对应的 image
StatefulSet 挂载块存储 (volumeClaimTemplates)
如果是 Statefulset 资源,创建 PVC 时只需要将 volumeTemplateClaim
里面的Claim名称改为StorageClass名称即可动态创建Pod
以下 StatefulSet 示例使用
volumeClaimTemplates
挂载块存储的示例nginx-sts.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # by default is 1
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # StatefulSet 的特有模块
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "rook-ceph-block"
resources:
requests:
storage: 1Gi使用以下命令创建 StatefulSet
1
kubectl create -f nginx-sts.yaml
查看自动创建的 pv 以及 pvc,发现系统会创建 3 个 pvc 绑定到自动创建的 3个 pv 上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18[root@k8s-master-01 rook-ceph]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3m8s
web-1 1/1 Running 0 115s
web-2 1/1 Running 0 75s
[root@k8s-master-01 rook-ceph]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-41576cec-b54e-4ef9-8a0f-c799063b183d 1Gi RWO Delete Bound default/www-web-2 rook-ceph-block 42s
pvc-837dabb2-0e8c-4fde-a28a-9f25420766d6 1Gi RWO Delete Bound default/www-web-1 rook-ceph-block 81s
pvc-c0360543-da84-4709-a2f1-4b7dc3191cd8 1Gi RWO Delete Bound default/www-web-0 rook-ceph-block 2m34s
[root@k8s-master-01 rook-ceph]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-c0360543-da84-4709-a2f1-4b7dc3191cd8 1Gi RWO rook-ceph-block 2m40s
www-web-1 Bound pvc-837dabb2-0e8c-4fde-a28a-9f25420766d6 1Gi RWO rook-ceph-block 87s
www-web-2 Bound pvc-41576cec-b54e-4ef9-8a0f-c799063b183d 1Gi RWO rook-ceph-block 47s
Ceph 共享文件存储的使用
共享文件系统一般用于多个 Pod 共享一个存储。官方文档地址: Shared Filesystem
创建共享类型的文件系统以及 pool
进入
rook/cluster/examples/kubernetes/ceph
目录,执行以下命令创建文件系统1
2# kubectl create -f filesystem.yaml
cephfilesystem.ceph.rook.io/myfs created创建完成后会启动 mds 容器,需要等待启动完成后才可以创建 StorageClass
1
2
3
4# kubectl get pods -n rook-ceph -l app=rook-ceph-mds
NAME READY STATUS RESTARTS AGE
rook-ceph-mds-myfs-a-669bdb8ddc-fdcb9 1/1 Running 0 109s
rook-ceph-mds-myfs-b-6547bcdb9-x2zs9 1/1 Running 0 106s也可以在 Ceph Dashboard 上面查看状态
创建共享类型文件系统的 StorageClass
执行以下命令创建共享型文件系统的 StorageClass
1
2# kubectl create -f csi/cephfs/storageclass.yaml
storageclass.storage.k8s.io/rook-cephfs created之后将 pvc 的 storageClassName 设置成 rook-cephfs 即可创建共享文件类型的存储,类似于NFS,可以给多个 Pod 共享数据。
使用 Nginx 挂载测试
创建文件
nginx-deploy-fs.yaml
,内容如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
selector:
app: nginx
type: ClusterIP
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-share-pvc
spec:
storageClassName: rook-cephfs
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
replicas: 3 # by default is 1
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: nginx-share-pvc说明:
- 创建 PVC 时,storageClassName 的值为之前创建的共享文件系统的 StorageClass 名称
rook-cephfs
; - Pod 挂载 PVC 时,claimName 的值为 PVC 的名称;
- 创建 PVC 时,storageClassName 的值为之前创建的共享文件系统的 StorageClass 名称
使用以下命令创建资源
1
2
3
4# kubectl create -f nginx-deploy-fs.yaml
service/nginx created
persistentvolumeclaim/nginx-share-pvc created
deployment.apps/web created查看创建的 PVC
1
2
3
4
5
6
7# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-share-pvc Bound pvc-684bf6df-87ab-42f9-aac6-8262a8e7cc90 1Gi RWX rook-cephfs 98s
# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-684bf6df-87ab-42f9-aac6-8262a8e7cc90 1Gi RWX Delete Bound default/nginx-share-pvc rook-cephfs 100s
PVC 扩容
文件共享类型的 PVC 扩容需要 k8s 1.15+ 以上才支持
块存储类型的 PVC 扩容需要 k8s 1.16+ 以上才支持
PVC 扩容需要开启 ExpandCSIVolumes,新版本的 k8s 已经默认打开了这个功能,可以使用以下命令查看自己的 k8s 版本是否已经默认打开了该功能:
1 | # /usr/local/kubernetes/bin/kube-apiserver -h |grep ExpandCSIVolumes |
如果 default 为 true 就不需要打开此功能,如果 default 为 false,则需要开启该功能。如上所示,说明已经打开了这个功能
扩容文件共享类型的 PVC
找到刚才创建的文件共享型 StorageClass ,将
allowVolumeExpansion
设置为 true(新版rook默认为true,如果不为true更改后执行kubectl replace即可):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rook-cephfs
provisioner: rook-ceph.cephfs.csi.ceph.com # driver:namespace:operator
parameters:
# clusterID is the namespace where operator is deployed.
clusterID: rook-ceph # namespace:cluster
# CephFS filesystem name into which the volume shall be created
fsName: myfs
# Ceph pool into which the volume shall be created
# Required for provisionVolume: "true"
pool: myfs-data0
# The secrets contain Ceph admin credentials. These are generated automatically by the operator
# in the same namespace as the cluster.
csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph # namespace:cluster
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph # namespace:cluster
csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph # namespace:cluster
# (optional) The driver can use either ceph-fuse (fuse) or ceph kernel client (kernel)
# If omitted, default volume mounter will be used - this is determined by probing for ceph-fuse
# or by setting the default mounter explicitly via --volumemounter command-line argument.
# mounter: kernel
reclaimPolicy: Delete
allowVolumeExpansion: true # 允许 pvc 扩容
mountOptions:
# uncomment the following line for debugging
#- debug找到之前示例创建的 PVC
1
2
3# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-share-pvc Bound pvc-684bf6df-87ab-42f9-aac6-8262a8e7cc90 1Gi RWX rook-cephfs 11m使用 edit 命令修改 pvc,将大小修改为 2G,之前是(1G)
1
# kubectl edit pvc nginx-share-pvc
重新查看 pv 和 pvc 的大小
1
2
3
4
5
6
7# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-684bf6df-87ab-42f9-aac6-8262a8e7cc90 2Gi RWX Delete Bound default/nginx-share-pvc rook-cephfs 14m
# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-share-pvc Bound pvc-684bf6df-87ab-42f9-aac6-8262a8e7cc90 2Gi RWX rook-cephfs 14m查看容器内是否已经完成扩容:
1
2# kubectl exec web-7bf54cbc8d-6ckm4 -- df -Th |grep /usr/share/nginx/html
10.109.78.80:6789,10.98.40.46:6789,10.108.19.112:6789:/volumes/csi/csi-vol-19138388-0eae-11ec-86ca-1a7d77656ad9/fd4dd64c-958b-427c-ac5a-2b4bd2e4bf11 ceph 2.0G 0 2.0G 0% /usr/share/nginx/html
扩容块存储类型的 PVC
扩容步骤类似,先找到之前创建的 pvc,直接 edit PVC,然后修改
spec.resources.requests.storage
的值既可:1
2
3
4
5
6# kubectl get pvc mysql-pv-claim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-b786a9c1-31c3-4344-b9cb-1a820ab9427a 2Gi RWO rook-ceph-block 90s
# kubectl edit pvc mysql-pv-claim
persistentvolumeclaim/mysql-pv-claim edited查看 PVC 是否扩容
1
2
3# kubectl get pvc mysql-pv-claim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-b786a9c1-31c3-4344-b9cb-1a820ab9427a 3Gi RWO rook-ceph-block 3m54s查看 Pod 的容器是否完成扩容
1
2# kubectl exec wordpress-mysql-6965fc8cc8-62tb2 -- df -Th |grep /var/lib/mysql
/dev/rbd0 ext4 2.9G 122M 2.8G 5% /var/lib/mysql也可以看到 ceph dashboard 的 image 也完成了扩容,但是 pvc 和 pod 里面的状态会有延迟,大概等待5-10分钟后,即可完成扩容