文章目录
目前官方Ceph csi版本已经支持Kubernetes 1.23,但是如果我们直接使用最新的ceph csi。在创建cephfs的时候会出现storageclass 创建pvc pending的状态。并且错误日志会提示persistentvolume-controller waiting for a volume to be created, either by external provisioner “cephfs.csi.ceph.com” or manually created by system administrator
。因为我们默认yum的ceph deploy会默认给我们安装N版本的ceph,但是最新的Ceph csi版本已经到了Q版本,需要根据实际情况调整版本信息
这个报错的解决方法,修改ceph csi版本,测试得出v3.5.1可以兼容N版本。或者将Ceph集群升级为最新版
已知可用于平台
Ceph CSI驱动程序目前仅在Kubernetes环境中开发和测试。
Ceph CSI版本 | 容器编排器名称 | 测试版本 |
---|---|---|
v3.6.1 | Kubernetes | v1.21、v1.22、v1.23 |
v3.6.0 | Kubernetes | v1.21、v1.22、v1.23 |
v3.5.1 | Kubernetes | v1.21、v1.22、v1.23 |
v3.5.0 | Kubernetes | v1.21、v1.22、v1.23 |
v3.4.0 | Kubernetes | v1.21、v1.22、v1.23 |
Ceph csi组件介绍
ceph-csi组件-作用介绍
(1)create pvc时,external-provisioner组件监听到pvc创建事件后,负责拼接请求,然后调用ceph-csi的CreateVolume方法来创建存储;
(2)delete pvc时,pv对象状态由bound变为release,external-provisioner监听到pv更新事件后,负责拼接请求,调用ceph-csi的DeleteVolume方法来删除存储。
(3)create pod cliam pvc时,kubelet会调用ceph-csi组件将创建好的存储从ceph集群挂载到pod所在的node上,然后再挂载到pod相应的目录上;
(4)delete pod cliam pvc时,kubelet会调用ceph-csi组件相应方法,解除存储在pod目录上的挂载,再解除存储在node上的挂载。
ceph-csi组件-服务组成
ceph-csi含有rbdType、cephfsType、livenessType三大类型服务,可以通过启动参数指定一种服务来进行启动。
而rbdType、cephfsType类型的服务可以继续细分,包括了NodeServer、ControllerServer与IdentityServer三种具体的服务,其中NodeServer与ControllerServer只能选其一进行启动,IdentityServer会伴随着NodeServer或ControllerServer的启动而启动。
环境说明
本次环境信息如下
- kubernetes版本:v1.23.5
- ceph版本:ceph version 14.2.22 (ca74598065096e6fcbd8433c8779a2be0c889351) nautilus (stable)
- Ceph-CSI版本: v3.5.1
请务必确定好版本号,必须为N版,新版本需要参考官方最新csi-ceph
版本下载地址
#官方下载(后期官方会改名)
wget https://github.com/ceph/ceph-csi/archive/refs/tags/v3.5.1.zip
#abcdocker代理下载地址
wget https://d.frps.cn/file/tools/ceph-csi/cephfs/v3.5.1.zip
替换镜像
#由于官方镜像大部分都是海外k8s.io类型的,可能无法直接使用,所以我们需要替换
#解压压缩包,进入相关镜像目录
[root@k8s-01 cephfs]# cd ceph-csi-3.5.1/deploy/cephfs/kubernetes/
#替换镜像
sed -i s#k8s.gcr.io/sig-storage/csi-provisioner:v3.1.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-provisioner:v3.1.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-resizer:v1.3.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-resizer:v1.3.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-snapshotter:v4.2.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-attacher:v3.4.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-attacher:v3.4.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#quay.io/cephcsi/cephcsi:v3.5.1#registry.cn-beijing.aliyuncs.com/abcdocker/cephcsi:v3.5.1#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.4.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-node-driver-registrar:v2.4.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#quay.io/cephcsi/cephcsi:v3.5.1#registry.cn-beijing.aliyuncs.com/abcdocker/cephcsi:v3.5.1#g csi-cephfsplugin.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.4.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-node-driver-registrar:v2.4.0#g csi-cephfsplugin.yaml
安装Ceph-csi
为sidecar容器和节点插件部署RBAC:
cd ceph-csi-3.5.1/deploy/cephfs/kubernetes/
kubectl create -f csi-provisioner-rbac.yaml
kubectl create -f csi-nodeplugin-rbac.yaml
这些清单部署服务帐户、集群角色和集群角色绑定。这些是RBD和CephFS CSI插件共享的,因为它们需要相同的权限。
为sidecar容器和节点插件部署 PodSecurityPolicy资源:
注意:仅当PodSecurityPolicy 准入控制器在您的集群上处于活动状态时才需要这些清单。
cd ceph-csi-3.5.1/deploy/cephfs/kubernetes/
kubectl create -f csi-provisioner-psp.yaml
kubectl create -f csi-nodeplugin-psp.yaml
为CSI插件部署ConfigMap:
获取ceph集群相关信息
- 获取ceph集群ID
- 获取admin key
- 获取ceph mon节点ip
获取ceph 集群ID
[root@ceph-01 ~]# ceph -s
cluster:
id: c8ae7537-8693-40df-8943-733f82049642 #这里为集群ID,需要复制保留
health: HEALTH_OK
services:
mon: 3 daemons, quorum ceph-01,ceph-02,ceph-03 (age 34h) #复制ceph mon节点ip
mgr: ceph-03(active, since 34h), standbys: ceph-02, ceph-01
mds: cephfs-abcdocker:1 cephfs:1 {cephfs-abcdocker:0=ceph-03=up:active,cephfs:0=ceph-02=up:active} 1 up:standby
osd: 4 osds: 4 up (since 34h), 4 in (since 8w)
rgw: 2 daemons active (ceph-01, ceph-02)
task status:
data:
pools: 14 pools, 688 pgs
objects: 8.73k objects, 31 GiB
usage: 96 GiB used, 84 GiB / 180 GiB avail
pgs: 688 active+clean
io:
client: 36 KiB/s wr, 0 op/s rd, 0 op/s wr
编辑configmap文件
vim ceph-csi-config.yaml
apiVersion: v1
kind: ConfigMap
data:
config.json: |-
[
{
"clusterID": "c8ae7537-8693-40df-8943-733f82049642",
"monitors": [
"192.168.31.20:6789",
"192.168.31.21:6789",
"192.168.31.22:6789"
]
}
]
metadata:
name: ceph-csi-config
这里不建议configmap名称修改
默认的deployment文件还有一个ceph-config configmap,这个也需要创建
vim ceph-config.yaml
apiVersion: v1
kind: ConfigMap
data:
ceph.conf: |
[global]
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
# Workaround for http://tracker.ceph.com/issues/23446
fuse_set_user_groups = false
# ceph-fuse which uses libfuse2 by default has write buffer size of 2KiB
# adding 'fuse_big_writes = true' option by default to override this limit
# see https://github.com/ceph/ceph-csi/issues/1928
fuse_big_writes = true
# keyring is a required key and its value should be empty
keyring: |
metadata:
name: ceph-config
创建configmap
[root@k8s-01 kubernetes]# kubectl apply -f ceph-csi-config.yaml
configmap/ceph-csi-config created
[root@k8s-01 kubernetes]# kubectl apply -f configmap.yaml
configmap/ceph-config configured
[root@k8s-01 kubernetes]# kubectl get cm
NAME DATA AGE
ceph-csi-config 1 3s
kube-root-ca.crt 1 36d
Ceph csi原理组件以及通信原理介绍
external-provisioner(csi-provisioner)
在启动时通过--provisioner指定自身provisioner名称,与StorageClass中的provisioner字段对应。
(1)watch PVC对象,判断PVC是否需要动态创建存储卷,标准如下:
- PVC的annotation[volume.beta.kubernetes.io/storage-provisioner](由PV Controller创建)是否与自己的provisioner名称相等。
- PVC对应StorageClass的VolumeBindingMode若为Immediate,则表示需要立即提供动态存储卷。
此时调用CSI Plugin的CreateVolume接口,同时创建名为${Provisioner指定的PV前缀}-${PVC uuid}的PV
(2)watch PV对象,判断其是否需要删除,标准如下:
- 判断其.status.phase是否为Release。
- 判断其.spec.PersistentVolumeReclaimPolicy是否为Delete。
- 判断其annotation[pv.kubernetes.io/provisioned-by]是否与自己的provisioner名称相等。
若需要,则调用CSI Plugin的DeleteVolume接口,同时删除PV对象
external-attacher(csi-attacher)
- watch VolumeAttachment对象,获得PV的所有信息,如volume ID、node ID等。根据VolumeAttachment的DeletionTimestamp和.status.attached来判断是调用CSI Plugin的ControllerPublish做attach,还是调用CntrollerUnpublish接口做detach
- 在attacher时为相关PV打上Finalizer;当PV处于删除状态(DeletionTimestamp非空)时,删除Finalizer
external-snapshotter
(1)watch VolumeSnapshot对象,根据其状态调用CSI Plugin的CreateSnapshot接口
等存储快照生成后,它会将存储快照生成的相关信息放到VolumeSnapshotContent对象中,并和用户提交的VolumeSnapshot做bound
(2)当VolumeSnapsho处于删除状态(DeletionTimestamp非空)时,调用CSI Plugin的DeleteSnapshot接口
external-resizer
watch PVC对象,判断用户在PVC中是否增加了需求的存储空间。如果PVC状态是Bound且.status.Capacity与.spec.Resources.Requests不等,则进行卷扩展:
- 更新PVC的.status.Conditions,表明此时处于Resizing状态
- 调用CSI Plugin的ControllerExpandVolume接口,若返回值中NodeExpansionRequired=true(还需要Kubelet中的Volume Manager继续调用CSI Plugin的NodeExpandVolume接口进行扩容),则更新PVC的status.Conditions 为 FileSystemResizePending;否则,更新 PVC的.Status.Conditions为空,且更新PVC的status.Capacity。
- 更新PV的spec.Capacity
node-driver-registrar
调用CSI Plugin的接口获取插件信息,通过Kubelet的插件注册机制将CSI Plugin注册到kubelet
livenessprobe
调用CSI Plugin的Probe接口,同时在/healthz暴露HTTP健康检查探针
因此,CSI分为两部分:
- 由k8s社区驱动实现的通用的部分,如图中的csi-provisioner和csi-attacher
- 由云存储厂商实现的csi-controller-server和csi-node-server(一般集成到一个一个CSI Plugin容器中),对接云存储厂商的API实现真正的create/delete/mount/unmount存储的相关操作
CSI插件与CSI sidecar容器的组合
一般会在一个CSI Plugin容器中同时实现所有接口,使其同时作为CSI Controller Server和CSI Node Server
它会和Kubernetes官方提供的CSI sidecar容器组成Pod,每种组合都会完成某种功能:
CSI Controller Server和External CSI SideCar、CSI Node Server和Kubelet通过Unix Socket来通信:
通过CRD管理CSI
对CSI的管理是通过CRD的形式实现的,所以引入了自定义对象类型VolumeAttachment、CSINode、CSIDriver
VolumeAttachmen
VolumeAttachment描述一个Volume的attach/detach信息。可以通过VolumeAttachment对一个Volume在某个节点上的attach状态进行跟踪。
VolumeAttachmentSpec数据结构:
- Attacher
根据Driver name指定由哪个CSI Plugin来进行attach/detach - NodeName
指定了attach/detach是发生在哪个节点上的 - Source
指定了对哪一个PV进行attach/detach。
VolumeAttachmentStatus数据结构:
- Attached
指示了是否已经attach如果VolumeAttachment的DeletionTimestamp为空且Attached=false,则external-attacher需要调用CSI Plugin的ControllerPublish做attach 如果VolumeAttachment的DeletionTimestamp不为空且Attached=true,则external-attacher需要调用CSI Plugin的ControllerUnPublish做detach
CSIDriver
CSIDriver描述了部署的CSI Plugin、定义了Kubernetes调用CSI Plugin的行为,需要管理员根据插件类型进行创建
CSIDriverSpec数据结构:
- AttachRequired
定义一个Plugin是否支持Attach功能。不需要Attach操作时,该标签就是False,说明无需部署external-attacher,也不需要VolumeAttachment对象。
例子:调用CreateVolume接口时,CreateVolumeRequest中VolumeCapability决定了是文件系统直接挂载还是块设备挂载。块存储需要Attach操作,但文件存储不需要Attach操作,例如NFS没有挂载、格式化的概念,只需要mount远端文件系统到本地即可
-
PodInfoOnMount
定义了调用CSI Plugin的NodePublishVolume接口时是否带上Pod信息(PodName、PodUID、PodNamespace)。
默认为false,即CSI Plugin无法获知Pod信息 -
VolumeLifecycleModes
该CSI Plugin支持哪些VolumeLifecycleMode
包括Persistent和Ephemeral两种 -
StorageCapacity
若为true,表示希望调度器调度时考虑节点的存储容量 -
FSGroupPolicy
Volume挂载前是否允许更改属主、权限的定义 -
TokenRequests
CSI Plugin可能需要Pod的Service Account Token -
RequiresRepublish
若为true,表示CSI Plugin希望不断被调用NodepublishVolume接口,以更新挂载到Pod中的Volume的相关变化。
不过只能更新Volume的contents,running状态Pod的挂载点是不能改变的
CSINode
CSINode是集群中的节点信息,由Node上的node-driver-registrar在启动时创建。
因此,可以只定义集群中一部分节点拥有CSINode。
CSINodeSpec由一组CSIDriver信息组成。每一个新的CSI Plugin注册后,都会在其中添加自身信息
每个CSI Plugin可添加的CSIDriver信息包括:
- Name
- NodeID
- Allocatable
节点最多可以attach多少个Volume
- TopologyKeys
该CSINode支持哪些TopologyKeys。进行支持拓扑感知的provisioning时,将会根据这些TopologyKeys从Node获取values,会传递给CSI Plugin
如果CSI Plugin不支持拓扑,可以置为null。
Csi原理部分需要详细查看请前往https://article.itxueyuan.com/vO01wa
部署 CSI Sidecar 容器:
kubectl create -f csi-cephfsplugin-provisioner.yaml
部署配置的部署,其中包括 CSI CephFS 的 external-provisioner、external-attacher。
部署 CSI CephFS 驱动程序:
kubectl create -f csi-cephfsplugin.yaml
#部署一个包含两个容器的守护程序集:CSI node-driver-registrar 和 CSI CephFS 驱动程序。
查看csi pod
[root@k8s-01 kubernetes]# kubectl get pod
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-4qcf7 3/3 Running 0 19m
csi-cephfsplugin-982v6 3/3 Running 0 19m
csi-cephfsplugin-bgq6t 3/3 Running 0 19m
csi-cephfsplugin-cfpqp 3/3 Running 0 19m
csi-cephfsplugin-gxctq 3/3 Running 1 (19m ago) 19m
csi-cephfsplugin-provisioner-7b58b6d568-7fq7x 6/6 Running 0 11m
csi-cephfsplugin-provisioner-7b58b6d568-8snn8 6/6 Running 0 11m
csi-cephfsplugin-provisioner-7b58b6d568-x8b4c 6/6 Running 0 11m
Ceph创建cephfs
CephFS 需要两个Pools - i4t_data和i4t_metadata, 分别存储文件数据和文件元数据
ceph osd pool create i4t_data 16 16
ceph osd pool create i4t_metadata 16 16
注:一般 metadata pool 可以从相对较少的 PGs 启动, 之后可以根据需要增加 PGs. 因为 metadata pool 存储着 CephFS 文件的元数据, 为了保证安全, 最好有较多的副本数. 为了能有较低的延迟, 可以考虑将 metadata 存储在 SSDs 上.
创建一个 CephFS, 名字为 i4tfs:
这里的i4tfs名称以及i4t_metadata i4t_data都需要保留,storageclass需要使用
ceph fs new i4tfs i4t_metadata i4t_data
创建Storageclass
首先我们需要创建一个secret,csi会通过pod访问ceph集群,但是访问集群需要一个用户,我这里就使用admin用户了
获取amdin key
[root@ceph-01 ~]# ceph auth get-key client.admin
AQB1RtxhH/YeHhAAxID/JplTyq77Oa1Pso7HNQ==
使用stringData不需要base64加密
vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: csi-cephfs-secret
stringData:
userID: admin
userKey: AQB1RtxhH/YeHhAAxID/JplTyq77Oa1Pso7HNQ==
adminID: admin
adminKey: AQB1RtxhH/YeHhAAxID/JplTyq77Oa1Pso7HNQ==
创建seceet检查
[root@k8s-01 kubernetes]# kubectl apply -f secret.yaml
secret/csi-cephfs-secret created
[root@k8s-01 kubernetes]# kubectl get secret
NAME TYPE DATA AGE
csi-cephfs-secret Opaque 4 5s
创建storageclass
vim i4t_storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-cephfs-sc
provisioner: cephfs.csi.ceph.com
parameters:
clusterID: c8ae7537-8693-40df-8943-733f82049642
fsName: i4tfs #cephfs名称,上面创建
pool: i4t_data #cephfs pool名称
# mounter: fuse #挂载方式
csi.storage.k8s.io/provisioner-secret-name: csi-cephfs-secret
csi.storage.k8s.io/provisioner-secret-namespace: default
csi.storage.k8s.io/controller-expand-secret-name: csi-cephfs-secret
csi.storage.k8s.io/controller-expand-secret-namespace: default
csi.storage.k8s.io/node-stage-secret-name: csi-cephfs-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- discard
#对于支持 Delete 回收策略的卷插件,删除动作会将 PersistentVolume 对象从 Kubernetes 中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 动态供应的卷会继承其 StorageClass 中设置的回收策略,该策略默认 为 Delet
#只有当 PVC 的存储类中将 allowVolumeExpansion 设置为 true 时,你才可以扩充该 PVC 申领
需要注意的是,storageclass需要和上面创建的secret名称对应上csi-cephfs-secret
以及命名空间
创建sc并查看
[root@k8s-01 kubernetes]# kubectl apply -f i4t_storageclass.yaml
storageclass.storage.k8s.io/csi-cephfs-sc created
[root@k8s-01 kubernetes]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
csi-cephfs-sc cephfs.csi.ceph.com Delete Immediate true 3s
创建pvc测试
编写pvc文件测试
vim pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: abcdocker-fs-data
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: csi-cephfs-sc
#pvc名称为abcdocker-fs-data
#资源大小为1G
#ReadWriteMany # PV以read-write挂载到多个节点,cephfs特有访问模式
检查pvc
[root@k8s-01 kubernetes]# kubectl apply -f pvc.yal
persistentvolumeclaim/abcdocker-fs-data created
我们可以看到,创建好pvc后会自动将我们pvc绑定到pv节点上
[root@k8s-01 kubernetes]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
abcdocker-fs-data Bound pvc-f931e74a-991b-440e-9180-9c7c283bf4a2 1Gi RWX csi-cephfs-sc 4s
可以顺便看一下pv
[root@k8s-01 kubernetes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-f931e74a-991b-440e-9180-9c7c283bf4a2 1Gi RWX Delete Bound default/abcdocker-fs-data csi-cephfs-sc 55s
挂载Pod测试
cat >nginx.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-abcdocker
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
subPath: html
volumes:
- name: www
persistentVolumeClaim:
claimName: abcdocker-fs-data #填写pvc名称
EOF
进入到nginx容器1中创建静态文件
[root@k8s-01 kubernetes]# kubectl get pod|grep nginx-abcdocker
nginx-abcdocker-7bb898c45c-48t9k 1/1 Running 0 64s
nginx-abcdocker-7bb898c45c-7mvtw 1/1 Running 0 64s
[root@k8s-01 kubernetes]# kubectl exec -it nginx-abcdocker-7bb898c45c-48t9k bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-abcdocker-7bb898c45c-48t9k:/#
root@nginx-abcdocker-7bb898c45c-48t9k:/# echo "abcdocker" >>/usr/share/nginx/html/index.html
到nginx 2中查看
[root@k8s-01 kubernetes]# kubectl get pod|grep nginx-abcdocker
nginx-abcdocker-7bb898c45c-48t9k 1/1 Running 0 2m19s
nginx-abcdocker-7bb898c45c-7mvtw 1/1 Running 0 2m19s
[root@k8s-01 kubernetes]# kubectl exec -it nginx-abcdocker-7bb898c45c-7mvtw bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-abcdocker-7bb898c45c-7mvtw:/# cat /usr/share/nginx/html/index.html
abcdocker
按照你的文章,在我本地的k8s使用ceph的fs一直处于pengding
查看一下你的ceph集群版本,以及csi的版本,是否都是一致
参考:https://i4t.com/5657.html
或者使用手动创建pv pvc的方式,先不使用storageclass
我在安装ceph是没有指定cluster-network,就指定了public-network,不影响吧
在ceph本地挂载报错?